当前位置: 首页 > news >正文

行业门户网站设计/提高工作效率8个方法

行业门户网站设计,提高工作效率8个方法,口碑最好的旅游软件排名,百度统计登录Vue.js双向绑定的实现原理 解析 神奇的 Object.defineProperty这个方法了不起啊。。vue.js和avalon.js 都是通过它实现双向绑定的。。而且Object.observe也被草案发起人撤回了。。所以defineProperty更有必要了解一下了几行代码看他怎么用var a {}Object.defineProperty(a,&quo…

Vue.js双向绑定的实现原理

解析 神奇的 Object.defineProperty这个方法了不起啊。。vue.js和avalon.js 都是通过它实现双向绑定的。。而且Object.observe也被草案发起人撤回了。。所以defineProperty更有必要了解一下了几行代码看他怎么用var a= {}Object.defineProperty(a,"b",{value:123})console.log(a.b);//123
很简单,,它接受三个参数,而且都是必填的。。传入参数
第一个参数:目标对象第二个参数:需要定义的属性或方法的名字。第三个参数:目标属性所拥有的特性。(descriptor)前两个参数不多说了,一看代码就懂,主要看第三个参数descriptor,看看有哪些取值descriptor
他又以下取值,我们简单认识一下,后面例子,挨个介绍,value:属性的值(不用多说了)writable:如果为false,属性的值就不能被重写,只能为只读了configurable:总开关,一旦为false,就不能再设置他的(value,writable,configurable)enumerable:是否能在for...in循环中遍历出来或在Object.keys中列举出来。get:一会细说set:一会细说descriptor默认值
我们再看看第一个例子var a= {}Object.defineProperty(a,"b",{value:123})console.log(a.b);//123
我们只设置了 value,别的并没有设置,但是 第一次的时候可以简单的理解为(暂时这样理解)它会默认帮我们把writable,configurable,enumerable。都设上值,而且值还都是false。。也就是说,上面代码和下面是等价的的( 仅限于第一次设置的时候)var a= {}
Object.defineProperty(a,"b",{value:123,writable:false,enumerable:false,configurable:false
})
console.log(a.b);//123
以上非常重要哦。。并且以上理解对set 和 get 不起作用哦
configurable
总开关,第一次设置 false 之后,,第二次什么设置也不行了,比如说var a= {}
Object.defineProperty(a,"b",{configurable:false
})
Object.defineProperty(a,"b",{configurable:true
})
//error: Uncaught TypeError: Cannot redefine property: b
就会报错了。。注意上面讲的默认值。。。如果第一次不设置它会怎样。。会帮你设置为false。。所以。。第二次。再设置他会怎样?。。对喽,,会报错writable
如果设置为fasle,就变成只读了。。var a = {}; Object.defineProperty(o, "b", { value : 123,writable : false });console.log(a.b); // 打印 37
a.b = 25; // 没有错误抛出(在严格模式下会抛出,即使之前已经有相同的值)
console.log(o.a); // 打印 37, 赋值不起作用。
enumerable
属性特性 enumerable 定义了对象的属性是否可以在 for...in 循环和 Object.keys() 中被枚举。var a= {}
Object.defineProperty(a,"b",{value:3445,enumerable:true
})
console.log(Object.keys(a));// 打印["b"]
改为falsevar a= {}
Object.defineProperty(a,"b",{value:3445,enumerable:false //注意咯这里改了
})
console.log(Object.keys(a));// 打印[]
for...in 类似,,不赘述了set 和 get
在 descriptor 中不能 同时设置访问器 (get 和 set) 和 wriable 或 value,否则会错,就是说想用(get 和 set),就不能用(wriable 或 value中的任何一个)set 和 get ,他俩干啥用的的,var a= {}
Object.defineProperty(a,"b",{set:function(newValue){console.log("你要赋值给我,我的新值是"+newValue)},get:function(){console.log("你取我的值")return 2 //注意这里,我硬编码返回2}
})
a.b =1 //打印 你要赋值给我,我的新值是1
console.log(a.b)    //打印 你取我的值//打印 2    注意这里,和我的硬编码相同的
简单来说,, 这个 “b” 赋值 或者 取值的时候会分别触发 set 和 get 对应的函数这就是实现 observe的关键啊。。下一篇,,我会分析vue的observe的实现源码,聊聊自己如何一步一步实现$watchvar a = {b: {c:1},d:1}
a.$watch("b.c",()=>console.log("哈哈哈"))

  

Object.keys(obj)返回参数obj可被枚举的属性:

示例一:function Pasta(grain, width, shape) {this.grain = grain;this.width = width;this.shape = shape;this.toString = function () {return (this.grain + ", " + this.width + ", " + this.shape);}}console.log(Object.keys(Pasta)); //console: []var spaghetti = new Pasta("wheat", 0.2, "circle");console.log(Object.keys(spaghetti)); //console: ["grain", "width", "shape", "toString"]示例二:var arr = ["a", "b", "c"];console.log(Object.keys(arr)); // console: ["0", "1", "2"]var obj = { 0 : "a", 1 : "b", 2 : "c"};console.log(Object.keys(obj)); // console: ["0", "1", "2"]var an_obj = { 100: "a", 2: "b", 7: "c"};console.log(Object.keys(an_obj)); // console: ["2", "7", "100"]var my_obj = Object.create({}, { getFoo : { value : function () { return this.foo } } });my_obj.foo = 1;console.log(Object.keys(my_obj)); // console: ["foo"]

  

  Vue.js最核心的功能有两个,一是响应式的数据绑定系统,二是组件系统。本文仅探究几乎所有Vue的开篇介绍都会提到的hello world双向绑定是怎样实现的。先讲涉及的知识点,再参考源码,用尽可能少的代码实现那个hello world开篇示例。

   参考文章:https://segmentfault.com/a/1190000006599500

一、访问器属性

       访问器属性是对象中的一种特殊属性,它不能直接在对象中设置,而必须通过defineProperty()方法单独定义。

       var obj = { };

       // 为obj定义一个名为hello的访问器属性

       Object.defineProperty(obj, "hello", {

         get: function () {return sth},

         set: function (val) {/* do sth */}

       })

       obj.hello // 可以像普通属性一样读取访问器属性

       访问器属性的"值"比较特殊,读取或设置访问器属性的值,实际上是调用其内部特性:get和set函数。

       obj.hello // 读取属性,就是调用get函数并返回get函数的返回值

       obj.hello = "abc" // 为属性赋值,就是调用set函数,赋值其实是传参

 

       get和set方法内部的this都指向obj,这意味着get和set函数可以操作对象内部的值。另外,访问器属性的会"覆盖"同名的普通属性,因为访问器属性会被优先访问,与其同名的普通属性则会被忽略(也就是所谓的被"劫持"了)。

<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title></title><script type="text/javascript">var obj={}Object.defineProperty(obj,"sb",{get:function(val){console.log("get方法执行了"+val);},set:function(val){console.log("set方法执行了:"+val);}})console.log(obj.sb);obj.sb="这就是个傻B"</script></head><body></body>
</html>

  

 

二、极简双向绑定的实现

 

       此例实现的效果是:随文本框输入文字的变化,span中会同步显示相同的文字内容;在js或控制台显式的修改obj.name的值,视图会相应更新。这样就实现了model =>view以及view => model的双向绑定,并且是响应式的。

 

       以上就是Vue实现双向绑定的基本原理。

<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title></title><script type="text/javascript">window.onload = function() {window.obj = {}Object.defineProperty(obj, "sb", {get: function(val) {console.log("get方法执行了" + val);},set: function(val) {document.getElementById("sb").value=val;document.getElementById("test").innerText=val;}})document.getElementById("sb").oninput = function() {obj.sb=this.value;}}</script></head><body><input type="text" name="" id="sb" value="" /><span id="test"></span></body></html>

   

 

三、分解任务

       上述示例仅仅是为了说明原理。我们最终要实现的是:

 

 

       首先将该任务分成几个子任务:

   1、输入框以及文本节点与data中的数据绑定

   2、输入框内容变化时,data中的数据同步变化。即view => model的变化。

   3、data中的数据变化时,文本节点的内容同步变化。即model => view的变化。

       要实现任务一,需要对DOM进行编译,这里有一个知识点:DocumentFragment。

 

四、DocumentFragment

       DocumentFragment(文档片段)可以看作节点容器,它可以包含多个子节点,当我们将它插入到DOM中时,只有它的子节点会插入目标节点,所以把它看作一组节点的容器。使用DocumentFragment处理节点,速度和性能远远优于直接操作DOM。Vue进行编译时,就是将挂载目标的所有子节点劫持(真的是劫持)到DocumentFragment中,经过一番处理后,再将DocumentFragment整体返回插入挂载目标。

      

五、数据初始化绑定

       以上代码实现了任务一,我们可以看到,hello world已经呈现在输入框和文本节点中。

 

六、响应式的数据绑定

       再来看任务二的实现思路:当我们在输入框输入数据的时候,首先触发input事件(或者keyup、change事件),在相应的事件处理程序中,我们获取输入框的value并赋值给vm实例的text属性。我们会利用defineProperty将data中的text劫持为vm的访问器属性,因此给vm.text赋值,就会触发set方法。在set方法中主要做两件事,第一是更新属性的值,第二留到任务三再说。

       任务二也就完成了,text属性值会与输入框的内容同步变化:

 

七、订阅/发布模式(subscribe&publish)

       text属性变化了,set方法触发了,但是文本节点的内容没有变化。如何让同样绑定到text的文本节点也同步变化呢?这里又有一个知识点:订阅发布模式。

       订阅发布模式(又称观察者模式)定义了一种一对多的关系,让多个观察者同时监听某一个主题对象,这个主题对象的状态发生改变时就会通知所有观察者对象。

       发布者发出通知 => 主题对象收到通知并推送给订阅者 => 订阅者执行相应操作

       之前提到的,当set方法触发后做的第二件事就是作为发布者发出通知:“我是属性text,我变了”。文本节点则是作为订阅者,在收到消息后执行相应的更新操作。

 

八、双向绑定的实现

       回顾一下,每当new一个Vue,主要做了两件事:第一个是监听数据:observe(data),第二个是编译HTML:nodeToFragement(id)。

       在监听数据的过程中,会为data中的每一个属性生成一个主题对象dep。

       在编译HTML的过程中,会为每个与数据绑定相关的节点生成一个订阅者watcher,watcher会将自己添加到相应属性的dep中。

       我们已经实现:修改输入框内容 => 在事件回调函数中修改属性值 => 触发属性的set方法。

       接下来我们要实现的是:发出通知dep.notify() => 触发订阅者的update方法 => 更新视图。

       这里的关键逻辑是:如何将watcher添加到关联属性的dep中。

       在编译HTML过程中,为每个与data关联的节点生成一个Watcher。Watcher函数中发生了什么呢?

       首先,将自己赋给了一个全局变量Dep.target;

       其次,执行了update方法,进而执行了get方法,get的方法读取了vm的访问器属性,从而触发了访问器属性的get方法,get方法中将该watcher添加到了对应访问器属性的dep中;

       再次,获取属性的值,然后更新视图。

       最后,将Dep.target设为空。因为它是全局变量,也是watcher与dep关联的唯一桥梁,任何时刻都必须保证Dep.target只有一个值。

       至此,hello world双向绑定就基本实现了。文本内容会随输入框内容同步变化,在控制器中修改vm.text的值,会同步反映到文本内容中。

   完整代码:https://github.com/bison1994/two-way-data-binding

 

JavaScript 模板引擎实现原理解析

1、入门实例

首先我们来看一个简单模板:

复制代码
  <script type="template" id="template"><h2><a href="{{href}}">{{title}}</a></h2><img src="{{imgSrc}}" alt="{{title}}"></script>
复制代码

其中被{{ xxx }}包含的就是我们要替换的变量。
接着我们可能通过ajax或者其他方法获得数据。这里我们自己定义了数据,具体如下:

复制代码
var data = [{title: "Create a Sticky Note Effect in 5 Easy Steps with CSS3 and HTML5",href: "http://net.tutsplus.com/tutorials/html-css-techniques/create-a-sticky-note-effect-in-5-easy-steps-with-css3-and-html5/",imgSrc: "https://d2o0t5hpnwv4c1.cloudfront.net/771_sticky/sticky_notes.jpg"},{title: "Nettuts+ Quiz #8",href: "http://net.tutsplus.com/articles/quizzes/nettuts-quiz-8-abbreviations-darth-sidious-edition/",imgSrc: "https://d2o0t5hpnwv4c1.cloudfront.net/989_quiz2jquerybasics/quiz.jpg"}];
复制代码

ok,现在的问题就是我们怎么把数据导入到模板里面呢?

第一种大家会想到的就是采用replace直接替换里面的变量:

复制代码
template = document.querySelector('#template').innerHTML,
result = document.querySelector('.result'),
i = 0, len = data.length,
fragment = '';for ( ; i < len; i++ ) {fragment += template.replace( /\{\{title\}\}/, data[i].title ).replace( /\{\{href\}\}/, data[i].href ).replace( /\{\{imgSrc\}\}/, data[i].imgSrc );
}result.innerHTML = fragment;
复制代码

第二种的话,相对第一种比较灵活,采用的是正则替换,对于初级前端,很多人对正则掌握的并不是很好,一般也用的比较少。具体实现如下:

复制代码
template = document.querySelector('#template').innerHTML,
result = document.querySelector('.result'),
attachTemplateToData;// 将模板和数据作为参数,通过数据里所有的项将值替换到模板的标签上(注意不是遍历模板标签,因为标签可能不在数据里存在)。
attachTemplateToData = function(template, data) {var i = 0,len = data.length,fragment = '';// 遍历数据集合里的每一个项,做相应的替换function replace(obj) {var t, key, reg;//遍历该数据项下所有的属性,将该属性作为key值来查找标签,然后替换for (key in obj) {reg = new RegExp('{{' + key + '}}', 'ig');t = (t || template).replace(reg, obj[key]);}return t;}for (; i < len; i++) {fragment += replace(data[i]);}return fragment;};result.innerHTML = attachTemplateToData(template, data);
复制代码

 与第一种相比较,第二种代码看上去多了,但是功能实则更为强大了。第一种我们需要每次重新编写变量名,如果变量名比较多的话,会比较麻烦,且容易出错。第二种的就没有这些烦恼。

 

2、模板引擎相关知识

通过上面的例子,大家对模板引擎应该有个初步的认识了,下面我们来讲解一些相关知识。

2.1 模板存放

模板一般都是放置到 textarea/input 等表单控件,或者 script 等标签中。比如上面的例子,我们就是放在 script 标签上的。

2.2 模板获取

一般都是通过ID来获取,document.getElementById(“ID”):

//textarea或input则取value,其它情况取innerHTML
var html = /^(textarea|input)$/i.test(element.nodeName) ? element.value : element.innerHTML;

上面的是通用的模板获取方法,这样不管你是放在 textarea/input 还是 script 标签下都可以获取到。

2.3 模板函数

一般都是templateFun("id", data);其中id为存放模板字符串的元素id,data为需要装载的数据。

2.4 模板解析编译

模板解析主要是指将模板中 JavaScript 语句和 html 分离出来,编译的话将模板字符串编译成最终的模板。上面的例子比较简单,还没有涉及到模板引擎的核心。

2.5 模板解析编译

要指出的是,不同的模板引擎所用的分隔符可能是不一样,上面的例子用的是{{ }},而Jquery tmpl 使用的是<%  %>。

 

3、jQuery tmpl 实现原理解析

 jQuery tmpl是由jQuery的作者写的,代码短小精悍。总共20多行,功能却比我们上面的强大很多。我们先来看一看源码:

复制代码
(function(){var cache = {};this.tmpl = function tmpl(str, data){var fn = !/\W/.test(str) ? cache[str] = cache[str] ||tmpl(document.getElementById(str).innerHTML) :new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};" +"with(obj){p.push('" +str.replace(/[\r\t\n]/g, " ") .split("<%").join("\t") .replace(/((^|%>)[^\t]*)'/g, "$1\r").replace(/\t=(.*?)%>/g, "',$1,'")  .split("\t").join("');")  .split("%>").join("p.push('") .split("\r").join("\\'")+ "');}return p.join('');");return data ? fn( data ) : fn;};
})();
复制代码

初看是不是觉得有点懵,完全不能理解的代码。没事,后面我们会对源码进行解释的,我们还是先看一下所用的模板

  <ul><% for ( var i = 0; i < users.length; i++ ) { %><li><a href="<%=users[i].url%>"><%=users[i].name%></a></li><% } %></ul>

可以发现,这个模板比入门例子的模板更为复杂,因为里面还夹杂着 JavaScript 代码。JavaScript 代码采用 <%  %> 包含。而要替换的变量则是用 <%=   %> 分隔开的。

下面我再来对代码做个注释。不过即使看了注释,你也不一定能很快理解,最好的办法是自己实际动手操作一遍。

复制代码
// 代码整个放在一个立即执行函数里面
(function(){// 用来缓存,有时候一个模板要用多次,这时候,我们直接用缓存就会很方便
var cache = {};
// tmpl绑定在this上,这里的this值得是windowthis.tmpl = function tmpl(str, data){
// 只有模板才有非字母数字字符,用来判断传入的是模板id还是模板字符串,
// 如果是id的话,判断是否有缓存,没有缓存的话调用tmpl;
// 如果是模板的话,就调用new Function()解析编译var fn = !/\W/.test(str) ? cache[str] = cache[str] ||tmpl(document.getElementById(str).innerHTML) :new Function("obj",
     // 注意这里整个是字符串,通过 + 号拼接"var p=[],print=function(){p.push.apply(p,arguments);};" +"with(obj){p.push('" +str
      // 去除换行制表符\t\n\r.replace(/[\r\t\n]/g, " ")
      
      // 将左分隔符变成 \t.split("<%").join("\t")
      
      // 去掉模板中单引号的干扰.replace(/((^|%>)[^\t]*)'/g, "$1\r")
      
      // 为 html 中的变量变成 ",xxx," 的形式, 如:\t=users[i].url%> 变成 ',users[i].url,'
      // 注意这里只有一个单引号,还不配对 .replace(/\t=(.*?)%>/g, "',$1,'")
      
      // 这时候,只有JavaScript 语句前面才有 "\t", 将 \t 变成 ');
      // 这样就可把 html 标签添加到数组p中,而javascript 语句 不需要 push 到里面。
      .split("\t").join("');")
      
      // 这时候,只有JavaScript 语句后面才有 "%>", 将 %> 变成 p.push('
      // 上一步我们再 html 标签后加了 ');, 所以要把 p.push(' 语句放在 html 标签放在前面,这样就可以变成 JavaScript 语句.split("%>").join("p.push('")
      // 将上面可能出现的干扰的单引号进行转义
      .split("\r").join("\\'")
    // 将数组 p 变成字符串。+ "');}return p.join('');");return data ? fn( data ) : fn;}; })();
复制代码

上面代码中,有一个要指出的就是new Function 的使用 方法。给 new Function() 传一个字符串作为函数的body来构造一个 JavaScript函数。编程中并不经常用到,但有时候应该是很有用的。

下面是 new Function 的基本用法:

// 最后一个参数是函数的 body(函数体),类型为 string; 
// 前面的参数都是 索要构造的函数的参数(名字) 
var myFunction = new Function('users', 'salary', 'return users * salary'); 

最后的字符串就是下面这种形式:

复制代码
  var p = [],print = function() {p.push.apply(p, arguments);};with(obj) {p.push('     <ul>     ');for (var i = 0; i < users.length; i++) {p.push('          <li><a href="', users[i].url, '">', users[i].name, '</a></li>     ');}p.push('   </ul> ');}return p.join('');
复制代码

里面的 print 函数 在我们的模板里面是没有用到的。

要指出的是,采用 push 的方法在 IE6-8 的浏览器下会比 += 的形式快,但是在现在的浏览器里面, += 是拼接字符串最快的方法。实测表明现代浏览器使用 += 会比数组 push 方法快,而在 v8 引擎中,使用 += 方式比数组拼接快 4.7 倍。所以 目前有些更高级的模板引擎会 根据 javascript 引擎特性采用了两种不同的字符串拼接方式。

下面的代码是摘自腾讯的 artTemplate 的, 根据浏览器的类型来选择不同的拼接方式。功能越强大,所考虑的问题也会更多。

    var isNewEngine = ''.trim;// '__proto__' in {}var replaces = isNewEngine? ["$out='';", "$out+=", ";", "$out"]: ["$out=[];", "$out.push(", ");", "$out.join('')"];

 

挑战:有兴趣的可以改用 += 来实现上面的代码。

总结

模板引擎原理总结起来就是:先获取html中对应的id下得innerHTML,利用开始标签和关闭标签进行字符串切分,其实是将模板划分成两部份内容,一部分是html部分,一部分是逻辑部分,通过区别一些特殊符号比如each、if等来将字符串拼接成函数式的字符串,将两部分各自经过处理后,再次拼接到一起,最后将拼接好的字符串采用new Function()的方式转化成所需要的函数。

 

目前模板引擎的种类繁多,功能也越来越强大,不同模板间实现原理大同小异,各有优缺,请按需选择。

 

 

 

vue双向数据绑定原理探究(附demo)

传送门

双向绑定的思想

双向数据绑定的思想就是数据层与UI层的同步,数据再两者之间的任一者发生变化时都会同步更新到另一者。

双向绑定的一些方法

目前,前端实现数据双向数据绑定的方法大致有以下三种:

1.发布者-订阅者模式(backbone.js)

思路:使用自定义的data属性在HTML代码中指明绑定。所有绑定起来的JavaScript对象以及DOM元素都将“订阅”一个发布者对象。任何时候如果JavaScript对象或者一个HTML输入字段被侦测到发生了变化,我们将代理事件到发布者-订阅者模式,这会反过来将变化广播并传播到所有绑定的对象和元素。

2.赃值检测(angular.js)

思路:通过轮询的方式检测数据变动。才特定的事件触发时进入赃值检测。

大致如下:

•   DOM事件,譬如用户输入文本,点击按钮等。( ng-click )

•   XHR响应事件 ( $http )

•   浏览器Location变更事件 ( $location )

•   Timer事件( $timeout , $interval )

•   执行 $digest() 或 $apply()

3.数据劫持(vue.js)

思路:使用Object.defineProperty对数据对象做属性get和set的监听,当有数据读取和赋值操作时则调用节点的指令,这样使用最通用的=等号赋值就可以触发了。

wue双向数据绑定小demo思路

①  构造一个Wue对象,定义该对象的属性el、data,创建对象的时候传相应数据,并执行init()方法。

1
2
3
4
5
var Wue=function(params){
    this.el=document.querySelector(params.el);
    this.data=params.data;
    this.init();
};

②  Init方法中执行bindText和bindModel方法,这两个方法分别是解析dom中绑定了w-model、w-text指令的html,并作相应处理。

1
2
3
4
init:function(){
            this.bindText();
            this.bindModel();
       }

③  bindText方法,把带有w-text指令的元素放进一个数组中,如:w-text=’demo’,然后令其innerHTML的值等于传进来的data[demo]。

1
2
3
4
5
6
7
8
9
bindText:function(){
          var textDOMs=this.el.querySelectorAll('[w-text]'),
          bindText;
          for(var i=0;i<textDOMs.length;i++){
             bindText=textDOMs[i].getAttribute('w-text');
             textDOMs[i].innerHTML=this.data[bindText];
          }
        }

④  bindModel方法,把带有w-model指令的元素(一般为form相关元素)放进一个数组中,如:w-model=’demo’,为每一个元素绑定keyup事件(兼容浏览器写法)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
bindModel:function(){
  var modelDOMs=this.el.querySelectorAll('[w-model]'),
  bindModel;
  var _that=this;
  for(var i=0;i<modelDOMs.length;i++){
    bindModel=modelDOMs[i].getAttribute('w-model');
    modelDOMs[i].value=this.data[bindModel]||'';
    //数据劫持
    this.defineObj(this.data,bindModel);
    if(document.addEventListener){
        modelDOMs[i].addEventListener('keyup',function(event) {
            console.log('test');
            e=event||window.event;
            _that.data[bindModel]=e.target.value;
        },false);
    }else{
        modelDOMs[i].attachEvent('onkeyup',function(event){
            e=event||window.event;
            _that.data[bindModel]=e.target.value;  
        },false);
    }
  
}

⑤  使用Object.defineProperty,定义set和get方法,并在set方法中调用bindText方法。这是利用了一旦w-model的值在input中被改变,会自动执行set方法,所以只有在这个方法中调用更新w-text的方法即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
defineObj:function(obj,prop,value){
          var val=value||'';
          var _that=this;
          try{
            Object.defineProperty(obj,prop,{
               get:function(){
                return val;
               },
               set:function(newVal){
                val=newVal;
                _that.bindText();
               }
            })
          }catch (err){
            console.log('Browser not support!')
          
        }

⑥使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
html:<br><h3>双向数据绑定demo</h3>
<div id="wrap">
    <input type="text" w-model='demo'>
    <h5 w-text='demo'></h5>
</div><br>js:
    <script src='../js/wue.js'></script>
    <script>
      new Wue({
        el:'#wrap',
        data:{
            demo:'winty'
        }
      })
    </script>

 

完整demo戳这里!  

http://www.jmfq.cn/news/4942351.html

相关文章:

  • 商丘网吧什么时候恢复营业/建站网站关键词优化
  • 重庆制作网站培训/太原seo排名优化公司
  • 天津建筑工程信息招标网/seo是什么软件
  • seo网站优化推广教程/南京搜索引擎推广优化
  • 设计公司起名两个字/seo系统培训哪家好
  • 求做网站/百度推广平台登录网址
  • 甘肃网站开发企业/网络公关公司收费
  • 慕课联盟网站开发实战/南宁今日头条最新消息
  • 小程序定制公司哪里有/河南关键词优化搜索
  • 企业做网站服务费/网上有卖网站链接的吗
  • 美食网站怎么做/深圳网站建设开发公司
  • 长沙小学网站建设/产品推广计划怎么写
  • 网站栏目页优化/百度联系电话
  • 江西住房与城乡建设厅网站/一个产品的市场营销策划方案
  • 有什么网站可以做商品展示的吗/靠谱的seo收费
  • 旅游网站排名前5位的/奶茶店推广软文500字
  • 上饶专业做网站建设/百度下载安装到手机
  • 网站跳转怎么做360/发稿软文公司
  • 网站开发毕业论文提纲/沈阳线上教学
  • 怎么做电影网站教程/网络推广中心
  • 做企业商城网站/临沂做网站推广的公司
  • 怎么做网站凡科/万词霸屏百度推广seo
  • b2b外贸建站/网店代运营商
  • 关于做网站的英语对话/收录优美的图片app
  • 做网站的难题/百度 站长工具
  • 福州自助建站/关键词汇总
  • 建设网站域名有了还要什么/深圳网站建设方案
  • 小蓝鸟加速器/宁波seo服务
  • 网站建设合同英文版/正规电商培训班
  • 网站导航条怎么做/百度快照是什么意思?