предисловие
В этой статье в основном написан исходный код Vue2.0 от руки.слушать свойство
В предыдущей статье мы в основном представили VueПринцип компонентаУглубленное понимание характеристик разработки компонентов Vue В этой статье будет представлен принцип использования большого количества свойств прослушивания в нашем ежедневном развитии бизнеса.
Для людей:
1. Хотите иметь глубокое понимание исходного кода vue для лучшего ежедневного развития бизнеса
2. Хотите владеть исходным кодом vue framework в резюме (больше не боитесь вопросов интервьюера о серийных убийцах, ха-ха)
3. Учащиеся, у которых нет времени смотреть официальный исходный код или им трудно понять с первого взгляда исходный код
текст
<script>
// Vue实例化
let vm = new Vue({
el: "#app",
data() {
return {
aa: 1,
bb: 2,
};
},
template: `<div id="a">hello 这是我自己写的Vue{{name}}</div>`,
methods: {
doSomething() {},
},
watch: {
aa(newVal, oldVal) {
console.log(newVal);
},
// aa: {
// handle(newVal, oldVal) {
// console.log(newVal);
// },
// deep: true
// },
// aa: 'doSomething',
// aa: [{
// handle(newVal, oldVal) {
// console.log(newVal);
// },
// deep: true
// }]
},
});
setTimeout(() => {
vm.aa = 1111;
}, 1000);
</script>
Есть много способов записать свойство прослушивания, которое может быть записано в виде строк, функций, массивов и объектов.Вы можете добавить некоторые опции в запись объекта, чтобы улучшить функцию.Особенность свойства прослушивания заключается в том, что вы можете выполнить пользовательский метод, переданный пользователем после изменения значения прослушивания.
1. Инициализация свойств прослушивания
// src/state.js
// 统一初始化数据的方法
export function initState(vm) {
// 获取传入的数据对象
const opts = vm.$options;
if (opts.watch) {
//侦听属性初始化
initWatch(vm);
}
}
// 初始化watch
function initWatch(vm) {
let watch = vm.$options.watch;
for (let k in watch) {
const handler = watch[k]; //用户自定义watch的写法可能是数组 对象 函数 字符串
if (Array.isArray(handler)) {
// 如果是数组就遍历进行创建
handler.forEach((handle) => {
createWatcher(vm, k, handle);
});
} else {
createWatcher(vm, k, handler);
}
}
}
// 创建watcher的核心
function createWatcher(vm, exprOrFn, handler, options = {}) {
if (typeof handler === "object") {
options = handler; //保存用户传入的对象
handler = handler.handler; //这个代表真正用户传入的函数
}
if (typeof handler === "string") {
// 代表传入的是定义好的methods方法
handler = vm[handler];
}
// 调用vm.$watch创建用户watcher
return vm.$watch(exprOrFn, handler, options);
}
initWatch инициализирует Watch для обработки массива createWatcher обрабатывает совместимость Watch, включая строки, функции, массивы и объекты Наконец, вызовите $watch и передайте обработанные параметры для создания пользовательского Watcher
2.$watch
// src/state.js
import Watcher from "./observer/watcher";
Vue.prototype.$watch = function (exprOrFn, cb, options) {
const vm = this;
// user: true 这里表示是一个用户watcher
let watcher = new Watcher(vm, exprOrFn, cb, { ...options, user: true });
// 如果有immediate属性 代表需要立即执行回调
if (options.immediate) {
cb(); //如果立刻执行
}
};
Метод прототипа $watch — это основной метод для создания пользовательских часов.Передайте определяемые пользователем параметры и user:true конструктору Watcher.
3. Преобразование наблюдателя
// src/observer/watcher.js
import { isObject } from "../util/index";
export default class Watcher {
constructor(vm, exprOrFn, cb, options) {
// this.vm = vm;
// this.exprOrFn = exprOrFn;
// this.cb = cb; //回调函数 比如在watcher更新之前可以执行beforeUpdate方法
// this.options = options; //额外的选项 true代表渲染watcher
// this.id = id++; // watcher的唯一标识
// this.deps = []; //存放dep的容器
// this.depsId = new Set(); //用来去重dep
this.user = options.user; //标识用户watcher
// 如果表达式是一个函数
if (typeof exprOrFn === "function") {
this.getter = exprOrFn;
} else {
this.getter = function () {
//用户watcher传过来的可能是一个字符串 类似a.a.a.a.b
let path = exprOrFn.split(".");
let obj = vm;
for (let i = 0; i < path.length; i++) {
obj = obj[path[i]]; //vm.a.a.a.a.b
}
return obj;
};
}
// 实例化就进行一次取值操作 进行依赖收集过程
this.value = this.get();
}
// get() {
// pushTarget(this); // 在调用方法之前先把当前watcher实例推到全局Dep.target上
// const res = this.getter.call(this.vm); //如果watcher是渲染watcher 那么就相当于执行 vm._update(vm._render()) 这个方法在render函数执行的时候会取值 从而实现依赖收集
// popTarget(); // 在调用方法之后把当前watcher实例从全局Dep.target移除
// return res;
// }
// 把dep放到deps里面 同时保证同一个dep只被保存到watcher一次 同样的 同一个watcher也只会保存在dep一次
// addDep(dep) {
// let id = dep.id;
// if (!this.depsId.has(id)) {
// this.depsId.add(id);
// this.deps.push(dep);
// // 直接调用dep的addSub方法 把自己--watcher实例添加到dep的subs容器里面
// dep.addSub(this);
// }
// }
// 这里简单的就执行以下get方法 之后涉及到计算属性就不一样了
// update() {
// // 计算属性依赖的值发生变化 只需要把dirty置为true 下次访问到了重新计算
// if (this.lazy) {
// this.dirty = true;
// }else{
// // 每次watcher进行更新的时候 可以让他们先缓存起来 之后再一起调用
// // 异步队列机制
// queueWatcher(this);
// }
// }
// depend(){
// // 计算属性的watcher存储了依赖项的dep
// let i=this.deps.length
// while(i--){
// this.deps[i].depend() //调用依赖项的dep去收集渲染watcher
// }
// }
run() {
const newVal = this.get(); //新值
const oldVal = this.value; //老值
this.value = newVal; //现在的新值将成为下一次变化的老值
if (this.user) {
// 如果两次的值不相同 或者值是引用类型 因为引用类型新老值是相等的 他们是指向同一引用地址
if (newVal !== oldVal || isObject(newVal)) {
this.cb.call(this.vm, newVal, oldVal);
}
} else {
// 渲染watcher
this.cb.call(this.vm);
}
}
}
В основном мы фокусируемся на неаннотированных местах, здесь есть два основных преобразования.
1. При создании экземпляра, чтобы быть совместимым с методом записи пользовательских часов, метод записи входящей строки будет преобразован в значение, соответствующее экземпляру Vue, и метод get будет вызван для получения и сохранения старого значения один раз. .
2. Метод запуска определяет, что если это часы пользователя, то следует выполнить функцию обратного вызова cb, переданную пользователем, и передать новое значение и старое значение в качестве параметров.
4. Интеллект-карта свойств слушания
резюме
На данный момент принцип свойства прослушивания Vue завершен. По сравнению с предыдущим принципом эта статья проще. Фактически, вычисляемое свойство и свойство прослушивания реализованы с помощью Watcher. Если вы не уверены в реализации всего Watcher, вы можете прочитать в этой статье.Рукописный исходный код Vue2.0 (четыре) — принцип обновления рендерингаВ следующей статье принцип вычисления свойств, которые будут сравниваться со свойствами прослушивания.Вы можете посмотреть на карту разума и написать код ядра самостоятельно.Если вы столкнулись с чем-то, что вы не понимаете или у вас есть споры, пожалуйста, оставьте комментарий .
Наконец, если вы найдете эту статью полезной, помнитеКак СанлианБольшое спасибо!
Ссылка на сериал (будет обновлена позже)
- Написанный от руки исходный код Vue2.0 (1) — принцип адаптивных данных
- Рукописный исходный код Vue2.0 (2) - принцип компиляции шаблона
- Рукописный исходный код Vue2.0 (3) — принцип начального рендеринга
- Рукописный исходный код Vue2.0 (четыре) — принцип обновления рендеринга
- Рукописный исходный код Vue2.0 (5) - принцип асинхронного обновления
- Рукописный исходный код Vue2.0 (6) - принцип алгоритма diff
- Рукописный исходный код Vue2.0 (7) - Принцип микширования
- Рукописный исходный код Vue2.0 (8)-компонентный принцип
- Рукописный исходный код Vue2.0 (9) - принцип свойства прослушивания
- Рукописный исходный код Vue2.0 (10) — Принцип вычисляемых свойств
- Рукописный исходный код Vue2.0 (11) — принцип глобального API
- Самые полные вопросы интервью Vue + подробные ответы
- Рукописный исходный код vue-router
- Рукописный исходный код vuex
- Рукописный исходный код vue3.0
Группа передовых рыболовных технологий Brother Shark
Приветствую всех на технических биржахСвязь