watch
vm.$watch(expOrFn,callback,[options])
功能
观察Vue实例变化的一个表达式或计算属性函数。回调函数得到的参数为新值和旧值。表达式值接收监督的键路径
参数
- exOrFn:要监视的$data 中的属性,可以说表达式或函数
- callback:数据变化后执行的函数
函数:回调函数
对象:具有handler属性(字符串或者函数),如果该属性为字符串则methods中相应的定义 - options:可选的选项
deep: 布尔类型,深度监听
immediate: 布尔类型,是否立即执行一次回调函数
示例
const vm = new Vue({
el:"#app",
data:{
user:{
fisrtName: 'aaaa',
lastName: 'bbbbb'
}
}
})
vm.$watch('user',function(newValue,oldValue){
this.user.firstName = newValue.firstName + " " + newValue.lastName
},{
immediate: true,
deep: true
})
三种类型的Watcher对象
- 没有静态方法,因为$watch方法中要是用Vue的实例
- Watcher分三种:计算属性Watcher,用户Watcher(侦听器)、渲染Watcher
创建顺序:计算属性Watcher,用于Watcher,渲染Watcher - vm.$watch()
src/core/instance/state.js
部分代码
export function initState (vm: Component) {
vm._watchers = []
const opts = vm.$options
if (opts.props) initProps(vm, opts.props) // 初始化props,并且通过defineReactive函数将值转换为set,get
if (opts.methods) initMethods(vm, opts.methods) // 将选项中的methods注入到vue实例,
if (opts.data) {
initData(vm) //
} else {
observe(vm._data = {}, true /* asRootData */) //转换成响应式数据
}
if (opts.computed) initComputed(vm, opts.computed) // 初始化computed
if (opts.watch && opts.watch !== nativeWatch) {
initWatch(vm, opts.watch) // 初始化watch
}
}
function initWatch (vm: Component, watch: Object) {
for (const key in watch) {
const handler = watch[key]
if (Array.isArray(handler)) {
for (let i = 0; i < handler.length; i++) {
createWatcher(vm, key, handler[i])
}
} else {
createWatcher(vm, key, handler)
}
}
}
function createWatcher (
vm: Component,
expOrFn: string | Function,
handler: any,
options?: Object
) {
if (isPlainObject(handler)) { // hundler是回调函数,就是对应传入方法
options = handler
handler = handler.handler
}
if (typeof handler === 'string') {
handler = vm[handler]
}
return vm.$watch(expOrFn, handler, options)
}
export function stateMixin (Vue: Class<Component>) {
// flow somehow has problems with directly declared definition object
// when using Object.defineProperty, so we have to procedurally build up
// the object here.
const dataDef = {}
dataDef.get = function () { return this._data }
const propsDef = {}
propsDef.get = function () { return this._props }
if (process.env.NODE_ENV !== 'production') {
dataDef.set = function () {
warn(
'Avoid replacing instance root $data. ' +
'Use nested data properties instead.',
this
)
}
propsDef.set = function () {
warn(`$props is readonly.`, this)
}
}
Object.defineProperty(Vue.prototype, '$data', dataDef)
Object.defineProperty(Vue.prototype, '$props', propsDef)
Vue.prototype.$set = set
Vue.prototype.$delete = del
Vue.prototype.$watch = function (
expOrFn: string | Function,
cb: any,
options?: Object
): Function {
// 获取 Vue 实例的this
const vm: Component = this
if (isPlainObject(cb)) {
// 判断如果 cb 是对象执行createWatcher
return createWatcher(vm, expOrFn, cb, options)
}
options = options || {}
// 标记为用户 watcher
options.user = true
// 创建用户 watcher 对象
const watcher = new Watcher(vm, expOrFn, cb, options)
// 判断 immediate 对象
if (options.immediate) {
// 立即执行一次cb回调,并把当前值传入
try {
cb.call(vm, watcher.value)
} catch (error) {
handleError(error, vm, `callback for immediate watcher "${watcher.expression}"`)
}
}
// 返回取消监听的方法
return function unwatchFn () {
watcher.teardown()
}
}
}