zoukankan      html  css  js  c++  java
  • vue 源码初级学习

    // 从Vue的第二个commit来学习数据驱动视图



    //Vue里面v-text的实现原理(为了易于理解,以下代码为超简化版)

    <div id="test"> <p v-text="date"></p> <p v-text="msg"></p> <span v-text="msg"></span> </div> var bindingMark = "v-text"; //绑定标记 //初始数据 var initData = { date: "2017-05-04", msg: "hello" }; var bindings = {};//内部数据备份 var data = {};//外部数据接口 var root = document.getElementById("test"), //模型根节点 els = root.querySelectorAll("[" + bindingMark + "]");//获取test下 所有的带有 v-test属性的节点 //收集 v-text 里面的值 [].forEach.call(els, function (el) { var variable = el.getAttribute(bindingMark); //获取v-text属性的值 bindings[variable] = {}; }); //数据驱动绑定函数 var bind = function(variable){ bindings[variable].els = root.querySelectorAll('[' + bindingMark + '="' + variable + '"]'); //获取某一 v-text 值的NodeList //删除v-text属性 [].forEach.call(bindings[variable].els, function (e) { e.removeAttribute(bindingMark); }); //添加set get 存取器描述 Object.defineProperty(data, variable, { set: function (newVal) { //数据重新赋值时候 更新dom中相对应的v-text [].forEach.call(bindings[variable].els, function (e) { bindings[variable].value = e.textContent = newVal; }); }, get: function () { return bindings[variable].value; } }) }; //执行绑定 for (var variable in bindings) { bind(variable); } //初始化赋值 if (initData) { for (var variable in initData) { data[variable] = initData[variable]; } } //更新数据函数 var updateData = function(newData){ for(var n in newData){ if(data[n] && (data[n] != newData[n])){ data[n] = newData[n]; } } }; //点击模型元素时 更新数据 然后触发set函数执行,进而驱动视图去改变 root.addEventListener('click', function(){ updateData({ date: "2017-07-02", msg: "world" }); });

    本文地址:https://zhuanlan.zhihu.com/p/26744423

      1 <!DOCTYPE html>
      2 <html lang="en">
      3 <head>
      4     <meta charset="UTF-8">
      5     <title>Title</title>
      6 </head>
      7 <body>
      8 <div id="test">
      9     <p>v-model 绑定的输入框,可同步下面的v-msg文本: <input v-model="msg" placeholder="edit me"></p>
     10     <p>v-msg 文本: <span v-text="msg"></span></p>
     11     <hr>
     12     <p>v-show 显示隐藏 demo: <span v-show="isShow">我是v-show属性绑定元素</span></p>
     13     <p>v-on:click,可以触发上面文本的显示隐藏<a href="javascript:;" v-on:click="changeShow" v-text="btn"></a></p>
     14 </div>
     15 </body>
     16 <script>
     17     /**
     18      * 支持的模板语法
     19      * [Directives description]
     20      * @type {Object}
     21      */
     22     var Directives = {
     23         text: function (el, value) {
     24             el.textContent = value || ''
     25         },
     26         show: function (el, value) {
     27             el.style.display = value ? '' : 'none'
     28         },
     29         on: {
     30             update: function (el, handler, event, directive) {
     31                 if (!directive.handlers) {
     32                     directive.handlers = {}
     33                 }
     34                 var handlers = directive.handlers
     35                 if (handlers[event]) {
     36                     el.removeEventListener(event, handlers[event])
     37                 }
     38                 if (handler) {
     39                     handler = handler.bind(el);
     40                     el.addEventListener(event, handler);
     41                     handlers[event] = handler;
     42                 }
     43             }
     44         },
     45         model: {
     46             bind: function (el, key, directive, seed) {
     47                 el.addEventListener('keyup', function (e) {
     48                     seed.$data[key] = el.value;
     49                 });
     50             },
     51             update: function (el, value) {
     52                 el.value = value;
     53             }
     54         }
     55     }
     56 
     57     /**
     58      * 工具方法
     59      * [Utils description]
     60      * @type {Object}
     61      */
     62     var Utils = {
     63         cloneAttributes: function (attributes) {
     64             return [].map.call(attributes, function (attr) {
     65                 return {
     66                     name: attr.name,
     67                     value: attr.value
     68                 }
     69             })
     70         },
     71         parseDirective: function (attr) {
     72             if (attr.name.indexOf(prefix) === -1) return;
     73 
     74             var noprefix = attr.name.slice(prefix.length + 1),
     75                 argIndex = noprefix.indexOf(':'),
     76                 dirname = argIndex === -1 ? noprefix : noprefix.slice(0, argIndex),
     77                 def = Directives[dirname],
     78                 arg = argIndex === -1 ? null : noprefix.slice(argIndex + 1);
     79 
     80             var exp = attr.value,
     81                 key = exp.trim();
     82 
     83             return def
     84                 ? {
     85                     attr: attr,
     86                     key: key,
     87                     definition: def,
     88                     argument: arg,
     89                     update: typeof def === 'function' ? def : def.update,
     90                     bind: typeof def === 'function' ? null : def.bind ? def.bind : null
     91                 }
     92                 : null;
     93         }
     94     };
     95 
     96     var prefix = 'v',
     97         selector = Object.keys(Directives).map(function (d) {
     98             return '[' + prefix + '-' + d + ']'
     99         }).join();
    100 
    101     /**
    102      * Vue构造函数
    103      * [Vue description]
    104      * @param {[type]} el   [description]
    105      * @param {[type]} opts [description]
    106      */
    107     function Vue (el, opts) {
    108         var self = this,
    109             root = self.$el = document.getElementById(el),
    110             els  = root.querySelectorAll(selector),
    111             _bindings = {};
    112 
    113         self.$opts = opts || {};
    114 
    115         self.$data = {}; //对外暴露的数据接口
    116 
    117         self.processNode(els, _bindings);
    118 
    119         self.initData(_bindings);
    120     }
    121 
    122     /**
    123      * 处理node节点
    124      *
    125      * [processNode description]
    126      * @param  {[type]} els       [description]
    127      * @param  {[type]} _bindings [description]
    128      * @return {[type]}           [description]
    129      */
    130     Vue.prototype.processNode = function(els, _bindings){
    131         var self = this;
    132         [].forEach.call(els, function(el){
    133             Utils.cloneAttributes(el.attributes).forEach(function (attr) {
    134                 var directive = Utils.parseDirective(attr);
    135                 if (directive) {
    136                     self.bindDirective(el, _bindings, directive)
    137                 }
    138             });
    139         });
    140     }
    141 
    142     //属性移除 指令绑定
    143     Vue.prototype.bindDirective = function(el, _bindings, directive){
    144         var self = this;
    145 
    146         el.removeAttribute(directive.attr.name);
    147         var key = directive.key,
    148             binding = _bindings[key];
    149         if (!binding) {
    150             _bindings[key] = binding = {
    151                 value: undefined,
    152                 directives: []
    153             }
    154         }
    155         directive.el = el;
    156         binding.directives.push(directive);
    157 
    158         if (directive.bind) {
    159             directive.bind(el, key, directive, self);
    160         }
    161         if (!self.$data.hasOwnProperty(key)) {
    162             self.bind(key, binding);
    163         }
    164     }
    165 
    166     //绑定 赋值拦截 set 方法
    167     Vue.prototype.bind = function(key, binding) {
    168         var that = this;
    169         Object.defineProperty(that.$data, key, {
    170             set: function (value) {
    171                 binding.value = value;
    172 
    173                 binding.directives.forEach(function (directive) {
    174                     directive.update(
    175                         directive.el,
    176                         value,
    177                         directive.argument,
    178                         directive,
    179                         self
    180                     )
    181                 })
    182             },
    183             get: function () {
    184                 return binding.value;
    185             }
    186         })
    187     };
    188     //实例初始化 赋值
    189     Vue.prototype.initData = function(_bindings) {
    190         var self = this;
    191         for (var variable in _bindings) {
    192             this.$data[variable] = self.$opts[variable];
    193         }
    194     };
    195 
    196     /**
    197      * 创建vm实例
    198      */
    199     var vm = new Vue('test', {
    200         msg: 'aaa',
    201         isShow: true,
    202         btn: '点击我',
    203         changeShow: function(){
    204             vm.$data.isShow = !vm.$data.isShow;
    205         }
    206     });
    207 </script>
    208 </html>

    精品文章

    vue学习笔记:http://jiongks.name/blog/vue-code-review/

  • 相关阅读:
    Oracle EBS-SQL (INV-1):库存货位列表.sql
    Oracle EBS-SQL (SYS-24):职责列表
    Oracle EBS-SQL (SYS-23):用户权限查询.sql
    Oracle EBS-SQL (SYS-22):sysadmin_用户职责查询.sql
    Oracle EBS-SQL (SYS-21):sys_用户名与人员对应关系查询.sql
    Oracle EBS-SQL (SYS-20):职责使用菜单2.sql
    Oracle EBS-SQL (SYS-20):OPM接口处理.sql
    Oracle EBS-SQL (SYS-19):sys-用户登陆纪录查询.sql
    Oracle EBS-SQL (SYS-18):检查系统安装的各个表是否打开(PJM%).sql
    Oracle EBS-SQL (SYS-17):查询一张报表在哪个职责下面.sql
  • 原文地址:https://www.cnblogs.com/WhiteHorseIsNotHorse/p/6841097.html
Copyright © 2011-2022 走看看