# 实例方法

# $watch

  • 参数:

    • {string | Function} source
    • {Function | Object} callback
    • {Object} [options]
      • {boolean} deep
      • {boolean} immediate
  • 返回值:{Function} unwatch

  • 用法:

    观察组件实例上的响应式属性或函数计算结果的变化。回调函数得到的参数为新值和旧值。我们只能将顶层的 datapropcomputed 属性名作为字符串传递。对于更复杂的表达式,用一个函数取代。

  • 示例:

    const app = Vue.createApp({
    	data() {
    		return {
    			a: 1,
    			b: 2,
    			c: {
    				d: 3,
    				e: 4,
    			},
    		}
    	},
    	created() {
    		// 顶层属性名
    		this.$watch('a', (newVal, oldVal) => {
    			// 做点什么
    		})
    
    		// 用于监视单个嵌套属性的函数
    		this.$watch(
    			() => this.c.d,
    			(newVal, oldVal) => {
    				// 做点什么
    			}
    		)
    
    		// 用于监视复杂表达式的函数
    		this.$watch(
    			// 表达式 `this.a + this.b` 每次得出一个不同的结果时
    			// 处理函数都会被调用。
    			// 这就像监听一个未被定义的计算属性
    			() => this.a + this.b,
    			(newVal, oldVal) => {
    				// 做点什么
    			}
    		)
    	},
    })
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37

    当观察的值是一个对象或者数组时,对其属性或元素的任何更改都不会触发观察,因为它们引用相同的对象/数组:

    const app = Vue.createApp({
    	data() {
    		return {
    			article: {
    				text: 'Vue is awesome!',
    			},
    			comments: ['Indeed!', 'I agree'],
    		}
    	},
    	created() {
    		this.$watch('article', () => {
    			console.log('Article changed!')
    		})
    
    		this.$watch('comments', () => {
    			console.log('Comments changed!')
    		})
    	},
    	methods: {
    		// 这些方法不会触发观察,因为我们只更改了Object/Array的一个property,
    		// 不是对象/数组本身
    		changeArticleText() {
    			this.article.text = 'Vue 3 is awesome'
    		},
    		addComment() {
    			this.comments.push('New comment')
    		},
    
    		// 这些方法将触发观察,因为完全替换了对象/数组
    		changeWholeArticle() {
    			this.article = { text: 'Vue 3 is awesome' }
    		},
    		clearComments() {
    			this.comments = []
    		},
    	},
    })
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37

    $watch 返回一个取消观察函数,用来停止触发回调:

    const app = Vue.createApp({
    	data() {
    		return {
    			a: 1,
    		}
    	},
    })
    
    const vm = app.mount('#app')
    
    const unwatch = vm.$watch('a', cb)
    // 之后取消观察
    unwatch()
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
  • 选项:deep

    为了发现对象内部值的变化,可以在选项参数中指定 deep: true。注意监听数组的变更不需要这么做。

    vm.$watch('someObject', callback, {
    	deep: true,
    })
    vm.someObject.nestedValue = 123
    // callback is fired
    
    1
    2
    3
    4
    5
  • 选项:immediate

    在选项参数中指定 immediate: true 将立即以表达式的当前值触发回调:

    vm.$watch('a', callback, {
    	immediate: true,
    })
    // 立即以 `a` 的当前值触发回调
    
    1
    2
    3
    4

    注意,在带有 immediate 选项时,你不能在第一次回调时取消帧听给定的 property。

    // 这会导致报错
    const unwatch = vm.$watch(
    	'value',
    	function() {
    		doSomething()
    		unwatch()
    	},
    	{ immediate: true }
    )
    
    1
    2
    3
    4
    5
    6
    7
    8
    9

    如果你仍然希望在回调内部调用一个取消侦听的函数,你应该先检查其函数的可用性:

    const unwatch = vm.$watch(
    	'value',
    	function() {
    		doSomething()
    		if (unwatch) {
    			unwatch()
    		}
    	},
    	{ immediate: true }
    )
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
  • 参考: Watchers

# $emit

  • 参数:

    • {string} eventName
    • ...args (optional)

    触发当前实例上的事件。附加参数都会传给监听器回调。

  • 示例:

    只配合一个事件名使用 $emit:

    <div id="emit-example-simple">
    	<welcome-button v-on:welcome="sayHi"></welcome-button>
    </div>
    
    1
    2
    3
    const app = Vue.createApp({
    	methods: {
    		sayHi() {
    			console.log('Hi!')
    		},
    	},
    })
    
    app.component('welcome-button', {
    	template: `
        <button v-on:click="$emit('welcome')">
          Click me to be welcomed
        </button>
      `,
    })
    
    app.mount('#emit-example-simple')
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

    配合额外的参数使用 $emit

    <div id="emit-example-argument">
    	<advice-component v-on:give-advice="showAdvice"></advice-component>
    </div>
    
    1
    2
    3
    const app = Vue.createApp({
    	methods: {
    		showAdvice(advice) {
    			alert(advice)
    		},
    	},
    })
    
    app.component('advice-component', {
    	data() {
    		return {
    			adviceText: 'Some advice',
    		}
    	},
    	template: `
        <div>
          <input type="text" v-model="adviceText">
          <button v-on:click="$emit('give-advice', adviceText)">
            Click me for sending advice
          </button>
        </div>
      `,
    })
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
  • 参考:

  • emits 选项

  • 事件抛出一个值

# $forceUpdate

  • 用法:

    迫使组件实例重新渲染。注意它仅仅影响实例本身和插入插槽内容的子组件,而不是所有子组件。

# $nextTick

  • 参数:

    • {Function} callback (optional)
  • 用法:

    将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。它跟全局方法 nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上。

  • 示例:

    Vue.createApp({
    	// ...
    	methods: {
    		// ...
    		example() {
    			// 修改数据
    			this.message = 'changed'
    			// DOM 还没有更新
    			this.$nextTick(function() {
    				// DOM 现在更新了
    				// `this` 绑定到当前实例
    				this.doSomethingElse()
    			})
    		},
    	},
    })
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
  • 参考: nextTick