• <fieldset id="8imwq"><menu id="8imwq"></menu></fieldset>
  • <bdo id="8imwq"><input id="8imwq"></input></bdo>
    最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
    問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
    當前位置: 首頁 - 科技 - 知識百科 - 正文

    使用Vue如何寫一個雙向數據綁定(面試常見)

    來源:懂視網 責編:小采 時間:2020-11-27 22:16:00
    文檔

    使用Vue如何寫一個雙向數據綁定(面試常見)

    使用Vue如何寫一個雙向數據綁定(面試常見):1、原理 Vue的雙向數據綁定的原理相信大家也都十分了解了,主要是通過 Object對象的defineProperty屬性,重寫data的set和get函數來實現的,這里對原理不做過多描述,主要還是來實現一個實例。為了使代碼更加的清晰,這里只會實現最基本的內容,主要實現v-m
    推薦度:
    導讀使用Vue如何寫一個雙向數據綁定(面試常見):1、原理 Vue的雙向數據綁定的原理相信大家也都十分了解了,主要是通過 Object對象的defineProperty屬性,重寫data的set和get函數來實現的,這里對原理不做過多描述,主要還是來實現一個實例。為了使代碼更加的清晰,這里只會實現最基本的內容,主要實現v-m

    1、原理

    Vue的雙向數據綁定的原理相信大家也都十分了解了,主要是通過 Object對象的defineProperty屬性,重寫data的set和get函數來實現的,這里對原理不做過多描述,主要還是來實現一個實例。為了使代碼更加的清晰,這里只會實現最基本的內容,主要實現v-model,v-bind 和v-click三個命令,其他命令也可以自行補充。

    添加網上的一張圖

    2、實現

    頁面結構很簡單,如下

    <div id="app">
     <form>
     <input type="text" v-model="number">
     <button type="button" v-click="increment">增加</button>
     </form>
     <h3 v-bind="number"></h3>
     </div>

    包含:

     1. 一個input,使用v-model指令
     2. 一個button,使用v-click指令
     3. 一個h3,使用v-bind指令。

    我們最后會通過類似于vue的方式來使用我們的雙向數據綁定,結合我們的數據結構添加注釋

    var app = new myVue({
     el:'#app',
     data: {
     number: 0
     },
     methods: {
     increment: function() {
     this.number ++;
     },
     }
     })

    首先我們需要定義一個myVue構造函數:

    function myVue(options) {
    }

    為了初始化這個構造函數,給它添加一 個_init屬性

    function myVue(options) {
     this._init(options);
    }
    myVue.prototype._init = function (options) {
     this.$options = options; // options 為上面使用時傳入的結構體,包括el,data,methods
     this.$el = document.querySelector(options.el); // el是 #app, this.$el是id為app的Element元素
     this.$data = options.data; // this.$data = {number: 0}
     this.$methods = options.methods; // this.$methods = {increment: function(){}}
     }

    接下來實現_obverse函數,對data進行處理,重寫data的set和get函數

    并改造_init函數

    myVue.prototype._obverse = function (obj) { // obj = {number: 0}
     var value;
     for (key in obj) { //遍歷obj對象
     if (obj.hasOwnProperty(key)) {
     value = obj[key]; 
     if (typeof value === 'object') { //如果值還是對象,則遍歷處理
     this._obverse(value);
     }
     Object.defineProperty(this.$data, key, { //關鍵
     enumerable: true,
     configurable: true,
     get: function () {
     console.log(`獲取${value}`);
     return value;
     },
     set: function (newVal) {
     console.log(`更新${newVal}`);
     if (value !== newVal) {
     value = newVal;
     }
     }
     })
     }
     }
     }
     myVue.prototype._init = function (options) {
     this.$options = options;
     this.$el = document.querySelector(options.el);
     this.$data = options.data;
     this.$methods = options.methods;
     this._obverse(this.$data);
     }

    接下來我們寫一個指令類Watcher,用來綁定更新函數,實現對DOM元素的更新

    function Watcher(name, el, vm, exp, attr) {
     this.name = name; //指令名稱,例如文本節點,該值設為"text"
     this.el = el; //指令對應的DOM元素
     this.vm = vm; //指令所屬myVue實例
     this.exp = exp; //指令對應的值,本例如"number"
     this.attr = attr; //綁定的屬性值,本例為"innerHTML"
     this.update();
     }
     Watcher.prototype.update = function () {
     this.el[this.attr] = this.vm.$data[this.exp]; //比如 H3.innerHTML = this.data.number; 當number改變時,會觸發這個update函數,保證對應的DOM內容進行了更新。
     }

    更新_init函數以及_obverse函數

    myVue.prototype._init = function (options) {
     //...
     this._binding = {}; //_binding保存著model與view的映射關系,也就是我們前面定義的Watcher的實例。當model改變時,我們會觸發其中的指令類更新,保證view也能實時更新
     //...
     }
     myVue.prototype._obverse = function (obj) {
     //...
     if (obj.hasOwnProperty(key)) {
     this._binding[key] = { // 按照前面的數據,_binding = {number: _directives: []} 
     _directives: []
     };
     //...
     var binding = this._binding[key];
     Object.defineProperty(this.$data, key, {
     //...
     set: function (newVal) {
     console.log(`更新${newVal}`);
     if (value !== newVal) {
     value = newVal;
     binding._directives.forEach(function (item) { // 當number改變時,觸發_binding[number]._directives 中的綁定的Watcher類的更新
     item.update();
     })
     }
     }
     })
     }
     }
     }

    那么如何將view與model進行綁定呢?接下來我們定義一個_compile函數,用來解析我們的指令(v-bind,v-model,v-clickde)等,并在這個過程中對view與model進行綁定。

     myVue.prototype._init = function (options) {
     //...
     this._complie(this.$el);
     }
    myVue.prototype._complie = function (root) { root 為 id為app的Element元素,也就是我們的根元素
     var _this = this;
     var nodes = root.children;
     for (var i = 0; i < nodes.length; i++) {
     var node = nodes[i];
     if (node.children.length) { // 對所有元素進行遍歷,并進行處理
     this._complie(node);
     }
     if (node.hasAttribute('v-click')) { // 如果有v-click屬性,我們監聽它的onclick事件,觸發increment事件,即number++
     node.onclick = (function () {
     var attrVal = nodes[i].getAttribute('v-click');
     return _this.$methods[attrVal].bind(_this.$data); //bind是使data的作用域與method函數的作用域保持一致
     })();
     }
     if (node.hasAttribute('v-model') && (node.tagName == 'INPUT' || node.tagName == 'TEXTAREA')) { // 如果有v-model屬性,并且元素是INPUT或者TEXTAREA,我們監聽它的input事件
     node.addEventListener('input', (function(key) { 
     var attrVal = node.getAttribute('v-model');
     //_this._binding['number']._directives = [一個Watcher實例]
     // 其中Watcher.prototype.update = function () {
     // node['vaule'] = _this.$data['number']; 這就將node的值保持與number一致
     // }
     _this._binding[attrVal]._directives.push(new Watcher( 
     'input',
     node,
     _this,
     attrVal,
     'value'
     ))
     return function() {
     _this.$data[attrVal] = nodes[key].value; // 使number 的值與 node的value保持一致,已經實現了雙向綁定
     }
     })(i));
     } 
     if (node.hasAttribute('v-bind')) { // 如果有v-bind屬性,我們只要使node的值及時更新為data中number的值即可
     var attrVal = node.getAttribute('v-bind');
     _this._binding[attrVal]._directives.push(new Watcher(
     'text',
     node,
     _this,
     attrVal,
     'innerHTML'
     ))
     }
     }
     }

    至此,我們已經實現了一個簡單vue的雙向綁定功能,包括v-bind, v-model, v-click三個指令。效果如下圖

    附上全部代碼,不到150行

    <!DOCTYPE html>
    <head>
     <title>myVue</title>
    </head>
    <style>
     #app {
     text-align: center;
     }
    </style>
    <body>
     <div id="app">
     <form>
     <input type="text" v-model="number">
     <button type="button" v-click="increment">增加</button>
     </form>
     <h3 v-bind="number"></h3>
     </div>
    </body>
    <script>
     function myVue(options) {
     this._init(options);
     }
     myVue.prototype._init = function (options) {
     this.$options = options;
     this.$el = document.querySelector(options.el);
     this.$data = options.data;
     this.$methods = options.methods;
     this._binding = {};
     this._obverse(this.$data);
     this._complie(this.$el);
     }
     myVue.prototype._obverse = function (obj) {
     var value;
     for (key in obj) {
     if (obj.hasOwnProperty(key)) {
     this._binding[key] = { 
     _directives: []
     };
     value = obj[key];
     if (typeof value === 'object') {
     this._obverse(value);
     }
     var binding = this._binding[key];
     Object.defineProperty(this.$data, key, {
     enumerable: true,
     configurable: true,
     get: function () {
     console.log(`獲取${value}`);
     return value;
     },
     set: function (newVal) {
     console.log(`更新${newVal}`);
     if (value !== newVal) {
     value = newVal;
     binding._directives.forEach(function (item) {
     item.update();
     })
     }
     }
     })
     }
     }
     }
     myVue.prototype._complie = function (root) {
     var _this = this;
     var nodes = root.children;
     for (var i = 0; i < nodes.length; i++) {
     var node = nodes[i];
     if (node.children.length) {
     this._complie(node);
     }
     if (node.hasAttribute('v-click')) {
     node.onclick = (function () {
     var attrVal = nodes[i].getAttribute('v-click');
     return _this.$methods[attrVal].bind(_this.$data);
     })();
     }
     if (node.hasAttribute('v-model') && (node.tagName == 'INPUT' || node.tagName == 'TEXTAREA')) {
     node.addEventListener('input', (function(key) {
     var attrVal = node.getAttribute('v-model');
     _this._binding[attrVal]._directives.push(new Watcher(
     'input',
     node,
     _this,
     attrVal,
     'value'
     ))
     return function() {
     _this.$data[attrVal] = nodes[key].value;
     }
     })(i));
     } 
     if (node.hasAttribute('v-bind')) {
     var attrVal = node.getAttribute('v-bind');
     _this._binding[attrVal]._directives.push(new Watcher(
     'text',
     node,
     _this,
     attrVal,
     'innerHTML'
     ))
     }
     }
     }
     function Watcher(name, el, vm, exp, attr) {
     this.name = name; //指令名稱,例如文本節點,該值設為"text"
     this.el = el; //指令對應的DOM元素
     this.vm = vm; //指令所屬myVue實例
     this.exp = exp; //指令對應的值,本例如"number"
     this.attr = attr; //綁定的屬性值,本例為"innerHTML"
     this.update();
     }
     Watcher.prototype.update = function () {
     this.el[this.attr] = this.vm.$data[this.exp];
     }
     window.onload = function() {
     var app = new myVue({
     el:'#app',
     data: {
     number: 0
     },
     methods: {
     increment: function() {
     this.number ++;
     },
     }
     })
     }
    </script>

    總結

    以上所述是小編給大家介紹的使用Vue如何寫一個雙向數據綁定(面試常見),希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對腳本之家網站的支持!

    聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

    文檔

    使用Vue如何寫一個雙向數據綁定(面試常見)

    使用Vue如何寫一個雙向數據綁定(面試常見):1、原理 Vue的雙向數據綁定的原理相信大家也都十分了解了,主要是通過 Object對象的defineProperty屬性,重寫data的set和get函數來實現的,這里對原理不做過多描述,主要還是來實現一個實例。為了使代碼更加的清晰,這里只會實現最基本的內容,主要實現v-m
    推薦度:
    標簽: 面試 VUE 實現
    • 熱門焦點

    最新推薦

    猜你喜歡

    熱門推薦

    專題
    Top
    主站蜘蛛池模板: 亚洲?V无码乱码国产精品| 久久丫精品国产亚洲av| 中文字幕精品久久久久人妻| 久久亚洲国产精品一区二区| 久久久久99精品成人片直播 | 久久精品中文闷骚内射| 精品久久综合1区2区3区激情| 久久99国产精品久久| 精品熟女少妇av免费久久| 亚洲AV成人精品日韩一区18p| 国产精品综合久久第一页| 亚洲精品成人av在线| 国产精品久久永久免费| 精品久久8x国产免费观看| 在线观看亚洲精品福利片 | 精品日产一区二区三区手机| 久久久国产精品亚洲一区| 中文字幕精品亚洲无线码二区| 久久精品国产99久久久香蕉| 国产精品1024在线永久免费| 四虎影视国产精品亚洲精品hd| 国内精品51视频在线观看| 99精品国产一区二区三区2021| 无码人妻精品中文字幕免费| 一本久久a久久精品综合香蕉| 四库影院永久四虎精品国产 | 国产精品久久久亚洲| 久久亚洲精精品中文字幕| 日本伊人精品一区二区三区| 永久无码精品三区在线4| 亚洲精品无码日韩国产不卡?V | 久久久久99精品成人片三人毛片 | 国产精品日本一区二区不卡视频 | 亚洲精品国精品久久99热| 欧美 日韩 精品 另类视频| 精品中文高清欧美| 久久噜噜久久久精品66| 色哟哟国产精品免费观看| 亚洲精品二三区| 久久精品人人做人人爽97| 精品国产三级a在线观看|