watch:{x(){}}
中的方法名必须跟要监听的data中的属性名一样,才代表监听指定属性
当侦听器监听的属性发生变化时,就会调用watch中对应的方法
侦听器属性,比计算属性计算效率消耗大
- new Vue({
- el:"",//关联界面元素
- data:{x:12},//vm的数据源
- methods:{},//方法
- filter:{},//过滤器
- computed:{xx(){}}, //xx就是一个计算属性
- watch:{x(){}} //x就是监听了data中的x属性的一个监听器
- })
用法:
- <div id='app'>
- <p>{{n}}p>
- <button @click="change1">修改nbutton>
- <p>{{obj.age}}p>
- <button @click="change2">修改objbutton>
- div>
- <script>
- var vm = new Vue({
- el: '#app',
- data: {
- n: 100,
- obj: {
- age: 20
- }
- },
- methods: {
- change1() {
- console.log("点击事件触发了")
- this.n = "修改了"
- },
- change2() {
- // this.obj.age="修改了引用数据内部的属性值:页面会重新渲染,但是侦听器属性不会触发"
- // this.obj={age:"只有修改了引用数据的引用 才能触发侦听器属性"}
- this.obj.age = "修改了引用数据内部的属性值也想触发侦听器属性,必须深度监听"
- }
- },
- watch: {//侦听器属性:必须和data中的数据源同名
- n() {
- console.log(666666666)
- },
- // obj(){
- // console.log("obj改变了")
- // }
- obj: { //这就是深度监听,上面改变this.obj.age,这个属性监听器也会触发
- //其实这样设计不好
- deep: true,
- handler: () => {
- console.log("obj改变了")
- }
- }
- }
- })
- script>
案例一:汇率换算
- <div id='app'>
- RMB:<input type="text" v-model="rmb">
- doller:<input type="text" v-model="doller">
- div>
- <script>
- var vm = new Vue({
- el: '#app',
- data: {
- rmb:0,
- doller:0
- },
- methods: {},
- watch:{
- rmb(newvalue,oldvalue){
- console.log(arguments) //会打印两个值,原来的值和新的值
- this.doller=(newvalue/6.9).toFixed(2)*100/100
- },
- doller(newvalue,oldvalue){
- this.rmb=newvalue*6.9
- }
- }
- })
- script>
案例二:消费余额提示
- <div id='app'>
- <p>{{money}}p>
- <button @click="fn">消费button>
- div>
- <script>
- var vm = new Vue({
- el: '#app',
- data: {
- money:100
- },
- methods: {
- fn(){
- this.money-=5
- }
- },
- watch:{
- money(newv,oldv){
- if(newv<30){
- alert("发短信还给用户:只剩30了不到了")
- }
- }
- }
- })
- script>
案例三:播放进度条监听
- <style type="text/css">
- .slider{
- width:400px;
- height: 20px;
- background-color: skyblue;
- position: relative;
- left: 100px;
- top: 100px;
- border-radius: 10px;
- }
- .sliderbar{
- width:30px;
- height: 30px;
- border-radius: 50%;
- background-color:cadetblue;
- position: relative;
- top: -5px;
- }
- style>
- <div id='app'>
- 进度条:{{total-currenttime|timerparser}}
- <div class="slider">
- <div class="sliderbar" :style="{left:x}">div>
- div>
- <button @click="start">startbutton>
- div>
- <script>
- var vm = new Vue({
- el: '#app',
- data: {
- currenttime:0,
- total:242,
- x:0,
- maxwidth:370
- },
- methods: {
- start(){
- this.timer=setInterval(()=>{
- this.currenttime+=0.1
- },100)
- }
- },
- filters:{
- timerparser(arg){
- return ` ${parseInt(arg/60).toString().padStart(2,"0")}:${parseInt(arg%60).toString().padStart(2,"0")}`
- }
- },
- watch:{
- currenttime(value){
- this.x=this.maxwidth*value/this.total+"px"
- if(value>=60){
- clearInterval(this.timer)
- alert("试听结束")
- }
- }
- }
- })
- script>
除了默认设置的核心指令( v-model 和 v-show 等),Vue 也允许注册自定义指令。
在Vue里,代码复用的主要形式和抽象是组件。
有的情况下,仍然需要对纯 DOM 元素进行底层操作,这时候就会用到自定义指令 。
指令:Vue中指令就是标签中V-开始的一种自定义的标签的属性,它在Vue运行了以后,就具有封装好的功能,使用时非常简洁
以一个input元素自动获得焦点为例,当页面加载时,使用autofocuse可以让元素将获得焦点 ,但是autofocuse在移动版Safari上不工作,现在注册一个使元素自动获取焦点的指令。
指令注册类似于组件注册,包括全局指令和局部指令两种。
- html>
- <html>
- <head>
- <meta charset="utf-8">
- <title>title>
- <script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/2.6.14/vue.js">script>
- head>
- <body>
- <div id="app">
- <p v-html="msg">p>
- <input v-red type="text" v-model="count" v-focus/>
- <div v-red>hellodiv>
- <h2 v-color="'blue'">123h2>
- <h2 v-color="'gold'">123h2>
- <p v-color="mycolor">123p>
- <input type="text" >
- div>
- <script>
- var vm = new Vue({
- el: "#app",
- data: {
- msg: "hello",
- count: 123,
- mycolor:"grey"
- },
- methods: {
- },
- directives: {
- red: {
- inserted(el) {
- console.log(el) //绑定这个指令的节点对象:DOM
- el.style.color = "red"
- }
- },
- color: {
- inserted(el, option) { //option是一个对象
- el.style.color = option.value
- }
- },
- focus:{
- inserted(el){
- el.focus()
- }
- }
- }
- })
- script>
- body>
- html>
案例:Echarts
- html>
- <html>
- <head>
- <meta charset="utf-8">
- <title>title>
- <script src='https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/2.6.14/vue.js'>script>
- <script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/echarts/5.3.0-rc.1/echarts.js">script>
- head>
- <body>
- <style type="text/css">
- .box {
- width: 600px;
- height: 600px;
- }
- style>
- <div id='app'>
- <div class="box" style="width:600px;height:600px;" v-echarts>
- div>
- div>
- <script>
- var vm = new Vue({
- el: '#app',
- data: {
- },
- methods: {},
- directives: {
- echarts: {
- bind(el) {
- var myChart = echarts.init(el);
- let options = {
- title: {
- text: 'Referer of a Website',
- subtext: 'Fake Data',
- left: 'center'
- },
- tooltip: {
- trigger: 'item'
- },
- legend: {
- orient: 'vertical',
- left: 'left'
- },
- series: [{
- name: 'Access From',
- type: 'pie',
- radius: '50%',
- data: [{
- value: 1048,
- name: 'Search Engine'
- },
- {
- value: 735,
- name: 'Direct'
- },
- {
- value: 580,
- name: 'Email'
- },
- {
- value: 484,
- name: 'Union Ads'
- },
- {
- value: 300,
- name: 'Video Ads'
- }
- ],
- emphasis: {
- itemStyle: {
- shadowBlur: 10,
- shadowOffsetX: 0,
- shadowColor: 'rgba(0, 0, 0, 0.5)'
- }
- }
- }]
- }
- myChart.setOption(options)
- }
- }
- }
- })
- script>
- body>
- html>
1)全局指令
// 注册一个全局自定义指令 v-focus Vue.directive('focus', { // 当绑定元素插入到 DOM 中。 inserted: function (el) { // 聚焦元素 el.focus() } })
2)局部指令
var vm = new Vue({ el: '#app', directives:{ focus:{ inserted: function (el) { el.focus() } } } })在模板中任何元素上使用新的 v-focus 属性
3)钩子函数
指令定义函数提供了几个钩子函数(可选) 。
【bind】
只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。
【inserted】
被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。
【update】
所在组件的 VNode 更新时调用,但是可能发生在其孩子的 VNode 更新之前。指令的值可能发生了改变也可能没有。但是可以通过比较更新前后的值来忽略不必要的模板更新。
当前所在组件更新的时候,这个函数才运行
【componentUpdated】
所在组件的 VNode 及其孩子的 VNode 全部更新时调用。
【unbind】
只调用一次, 指令与元素解绑时调用。
注意区别:
bind与inserted:bind时父节点为null,inserted时父节点存在;
update与componentUpdated:update是数据更新前,componentUpdated是数据更新后。
4)钩子函数参数
【el】
指令所绑定的元素,可以用来直接操作 DOM。
【binding】
一个对象,包含指令名称及该指令所绑定的表达式信息。
里面有name、value、oldvalue等等
【vnode】
Vue 编译生成的虚拟节点。
【oldVnode】
上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
注意:除了 el 之外,其它参数都是只读的,尽量不要修改他们。如果需要在钩子之间共享数据,建议通过元素的 dataset 来进行。
- <div id='app'>
- <p v-hqyj="red" @click="change1">hellop>
- div>
- <script>
- var vm = new Vue({
- el: '#app',
- data: {
- red:"rgb(255,0,0)"
- },
- methods: {
- change1(){
- this.red="rgb(200,0,0)"
- }
- },
- directives:{
- hqyj:{
- bind(){
- console.log("bind")
- },
- inserted(el,binding){
- var v=binding.value
- console.log(v)
- },
- update(){
- console.log("update")
- },
- componentUpdated(){
-
- },
- unbind(){
- }
- }
- }
- })
- script>
5)函数简写
大多数情况下,可能想在bind和update钩子上做重复动作,并且不想关心其它的钩子函数。可以这样写:
"{ color: 'white', text: 'hello!' }"> Vue.directive('demo', function (el, binding) { console.log(binding.value.color) // => "white" console.log(binding.value.text) // => "hello!" })
学习了生命周期之后,会有一个问题:我们在写业务的时候,写的业务代码能否操作vm
所以需要一个工具,让我们写的diamagnetic,无论在哪里写,都希望它是组件加载完了以后才运行
这个函数的回调函数是在组件加载完了才会执行
- <div id='app'>
- <p>{{msg}}p>
- div>
- <script>
- var vm = new Vue({
- el: '#app',
- data: {
- msg:"hello"
- },
- methods: {},
- beforeCreate(){
- //这个函数的回调函数是在组件加载完了才会执行
- this.$nextTick(()=>{
- console.log(this.msg)
- })
- }
- })
- script>
==>这个函数就可以解决上面ECharts案例
- html>
- <html>
- <head>
- <meta charset="utf-8">
- <title>title>
- <script src='https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/2.6.14/vue.js'>script>
- <script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/echarts/5.3.0-rc.1/echarts.js">script>
- head>
- <body>
- <style type="text/css">
- .box {
- width: 600px;
- height: 600px;
- }
- style>
- <div id='app'>
- <div class="box" v-echarts>
- div>
- div>
- <script>
- var vm = new Vue({
- el: '#app',
- data: {},
- methods: {},
- directives: {
- echarts: {
- inserted(el) {
- Vue.nextTick(()=>{
- var myChart = echarts.init(el);
- let options={
- title: {
- text: 'Referer of a Website',
- subtext: 'Fake Data',
- left: 'center'
- },
- tooltip: {
- trigger: 'item'
- },
- legend: {
- orient: 'vertical',
- left: 'left'
- },
- series: [{
- name: 'Access From',
- type: 'pie',
- radius: '50%',
- data: [{
- value: 1048,
- name: 'Search Engine'
- },
- {
- value: 735,
- name: 'Direct'
- },
- {
- value: 580,
- name: 'Email'
- },
- {
- value: 484,
- name: 'Union Ads'
- },
- {
- value: 300,
- name: 'Video Ads'
- }
- ],
- emphasis: {
- itemStyle: {
- shadowBlur: 10,
- shadowOffsetX: 0,
- shadowColor: 'rgba(0, 0, 0, 0.5)'
- }
- }
- }]
- }
- myChart.setOption(options)
- })
- }
- }
- }
- })
- script>
- body>
- html>