vue3.0实现原理
vue3.0.js
------------------
function Vue(option){
?this.$el = document.querySelector(option.el); //獲取掛載節點
?this.$data = option.data;
?this.$methods = option.methods;
?this.deps = {}; ?//所有訂閱者集合 目標格式(一對多的關系):{msg: [訂閱者1, 訂閱者2, 訂閱者3], info: [訂閱者1, 訂閱者2]}
?this.observer(this.$data); //調用觀察者
?this.compile(this.$el); ?//調用指令解析器
}
Vue.prototype.compile = function (el) {
?let nodes = el.children; //獲取掛載節點的子節點
?for (var i = 0; i < nodes.length; i++) {
? var node = nodes[i];
? if (node.children.length) {
? ?this.compile(node) //遞歸獲取子節點
? }
? if (node.hasAttribute('l-model')) { //當子節點存在l-model指令
? ?let attrVal = node.getAttribute('l-model'); //獲取屬性值
? ?node.addEventListener('input', (() => {
? ? this.deps[attrVal].push(new Watcher(node, "value", this, attrVal)); //添加一個訂閱者
? ? let thisNode = node;
? ? return () => {
? ? ?this.$data[attrVal] = thisNode.value //更新數據層的數據
? ? }
? ?})())
? }
? if (node.hasAttribute('l-html')) {
? ?let attrVal = node.getAttribute('l-html'); //獲取屬性值
? ?this.deps[attrVal].push(new Watcher(node, "innerHTML", this, attrVal)); //添加一個訂閱者
? }
? if (node.innerHTML.match(/{{([^\{|\}]+)}}/)) {
? ?let attrVal = node.innerHTML.replace(/[{{|}}]/g, ''); //獲取插值表達式內容
? ?this.deps[attrVal].push(new Watcher(node, "innerHTML", this, attrVal)); //添加一個訂閱者
? }
? if (node.hasAttribute('l-on:click')) {
? ?let attrVal = node.getAttribute('l-on:click'); //獲取事件觸發的方法名
? ?node.addEventListener('click', this.$methods[attrVal].bind(this.$data)); //將this指向this.$data
? }
?}
}
Vue.prototype.observer = function (data) {
?const that = this;
?for(var key in data){
? that.deps[key] = []; //初始化所有訂閱者對象{msg: [訂閱者], info: []}
?}
?let handler = {
? get(target, property) {
? ?return target[property];
? },
? set(target, key, value) {
? ?let res = Reflect.set(target, key, value);
? ?var watchers = that.deps[key];
? ?watchers.map(item => {
? ? item.update();
? ?});
? ?return res;
? }
?}
?this.$data = new Proxy(data, handler);
}
function Watcher(el, attr, vm, attrVal) {
?this.el = el;
?this.attr = attr;
?this.vm = vm;
?this.val = attrVal;
?this.update(); //更新視圖
}
Watcher.prototype.update = function () {
?this.el[this.attr] = this.vm.$data[this.val]
}
-----------------------------------------------
vue3.0.html
---------------------------------------------
<!DOCTYPE html>
<html lang="en">
<head>
?<meta charset="UTF-8">
?<meta name="viewport" content="width=device-width, initial-scale=1.0">
?<meta http-equiv="X-UA-Compatible" content="ie=edge">
?<title>Document</title>
?<script src="./vue3.0.js"></script>
</head>
<body>
?<!--
? 實現mvvm的雙向綁定,是采用數據劫持結合發布者-訂閱者模式的方式,通過Proxy來劫持各個屬性的setter,getter,在數據變動時發布消息給訂閱者,觸發相應的監聽回調。就必須要實現以下幾點:
? ?1、實現一個數據監聽器Observer,能夠對數據對象的所有屬性進行監聽,如有變動可拿到最新值并通知訂閱者
? ?2、實現一個指令解析器Compile,對每個元素節點的指令進行掃描和解析,根據指令模板替換數據,以及綁定相應的更新函數
? ?3、實現一個Watcher,作為連接Observer和Compile的橋梁,能夠訂閱并收到每個屬性變動的通知,執行指令綁定的相應回調函數,從而更新視圖
? ?4、mvvm入口函數,整合以上三者
?-->
?<div id="app">
? <input type="text" l-model="msg" >
? <p l-html="msg"></p>
? <input type="text" l-model="info" >
? <p l-html="info"></p>
? <button l-on:click="clickMe">點我</button>
? <p>{{msg}}</p>
?</div>
?
?<script>
? var vm = new Vue({
? ?el: "#app",
? ?data: {
? ? msg: "恭喜發財",
? ? info: "好好學習, 天天向上"
? ?},
? ?methods: {
? ? clickMe(){
? ? ?this.msg = "我愛敲代碼";
? ? }
? ?}
? })
?</script>
</body>
</html>
總結
以上是生活随笔為你收集整理的vue3.0实现原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 通俗易懂了解Vue双向绑定原理及实现
- 下一篇: vue mianjs 引用css_vue