Vue.js双向绑定的实现原理和模板引擎实现原理(##########################################)...
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戳这里!
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
相关文章
- Web应用或引领下一代Web趋势?
在旧金山创业公司 3scale网站上经常有人会问道:“究竟什么样类型的Web架构会成为最终的赢家?是 HTML5还是AppAPI?”我们的答案非常简单:“将两者集合。” 来自Alexander Aghassipour和Shajith Chacko发表的这篇 文章讲述了单页应用…...
2024/4/21 15:45:40 - 1.Vue
Vue 1.什么是双向绑定? Model-View-ViewModel (MVVM模式) model:即所谓的数据 View:即所谓的视图 双向绑定,即model数据层更新,View视图层也会随之更新;如果视图层更新,对应的数据Model层也会…...
2024/4/21 15:45:40 - 单页Web应用或引领下一代Web新趋势?
原文地址:http://www.csdn.net/article/2012-12-10/2812658-Single-Page-Applications摘要:一门新的技术诞生总会引来一番争议,单页Web应用程序也不例外,其最大的优势在于用户体验,对于内容的改动不需要加载整个页面&a…...
2024/4/28 7:06:21 - flux架构
与 React 相同,Flux 同样由一群 Facebook 工程师提出,它的名字是拉丁语的 Flow。Flux 的 提出主要是针对现有前端 MVC 框架的局限总结出来的一套基于 dispatcher 的前端应用架构模 式。如果用 MVC 的命名习惯,它应该叫 ADSV(Actio…...
2024/5/3 9:08:28 - SPA
什么是单页面应用?单页Web应用(single page web application,SPA),就是只有一张Web页面的应用,是加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序,是指在浏览器中运行的应用&#…...
2024/4/28 11:55:37 - 从单向到双向数据绑定
本文来自我的github 0.前言 用户最满意的,无非就是界面的操作能实事反应到数据。而实现这种的可以有双向数据绑定、单向数据流的形式。双向数据绑定是,ui行为改变model层的数据,model层的数据变了也能反映到ui上面。比如点击按钮,…...
2024/4/28 21:29:22 - GUI 应用程序架构的十年变迁:MVC、MVP、MVVM、Unidirectional、Clean
随着现代浏览器的日渐流行,Web 以及混合开发技术的发展,大前端的概念日渐成为某种共识;而无论 iOS、Android、Web 这样的端开发还是 React Native、Weex 这样的跨端开发,其术不同而道相似。笔者在日前总结的泛前端知识图谱&#x…...
2024/4/28 14:25:12 - 割双眼皮六个月还能恢复自然吗
...
2024/4/28 16:27:18 - 内双眼皮明星
...
2024/4/28 22:48:06 - 双眼皮贴可以贴多久
...
2024/4/28 18:53:05 - Angular2+ 思维导图
Angular2知识点 Angular2整体知识点/结构图 Angular学习笔记 AngularX angularX angular6 Angular7运行机制 Angular7运行机制–《Angular4从入门到实战》学习体会...
2024/4/29 0:11:41 - 天津哪里做双眼皮最好
...
2024/4/28 11:19:37 - DEV ChartControl 图表设计 -- Line
ChartControl myChartControl = new ChartControl(); //图标位置myChartControl.Legend.AlignmentHorizontal = LegendAlignmentHorizontal.Right;myChartControl.Legend.AlignmentVertical = LegendAlignmentVertical.Top;ChartTitle chartTitle = new ChartTitle()…...
2024/4/28 21:28:41 - 双眼皮7mm太窄了
...
2024/4/28 20:11:02 - 欧式全切双眼皮恢复记录
...
2024/4/28 4:43:47 - 割双眼皮一年
...
2024/4/28 1:39:54 - 两个眼睛双眼皮不对称
...
2024/4/28 5:52:07 - 双眼皮变大
...
2024/4/28 17:50:03 - 欧式双眼皮 东方人
...
2024/4/28 15:56:36 - 韩式双眼皮男生图片大全
...
2024/4/27 23:07:15
最新文章
- Jammy@Jetson Orin Nano - Tensorflow GPU版本安装
JammyJetson Orin Nano - Tensorflow GPU版本安装 1. 源由2. 问题2.1 Tensorflow跑以下示例代码的时候,发现jtop中6个CPU占用率都跑满了。2.2 Jetson Orin Nano运行Tensorflow示例结果不一致 3. 分析3.1 当前版本Tensorflow 2.16.13.2 GPU版本二进制安装3.3 GPU版本…...
2024/5/3 15:14:35 - 梯度消失和梯度爆炸的一些处理方法
在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言,在此感激不尽。 权重和梯度的更新公式如下: w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...
2024/3/20 10:50:27 - 鹅厂实习offer
#转眼已经银四了,你收到offer了吗# 本来都打算四月再投实习了,突然三月初被wxg捞了(一年前找日常实习投的简历就更新了下),直接冲了,流程持续二十多天,结果是运气还不错,应该是部门比…...
2024/5/1 13:19:09 - 2024免费Mac苹果解压压缩包软件BetterZip5
在2024年,对于Mac电脑用户来说,如果你想要无需解压就能快速查看压缩文档的内容,BetterZip是一个极佳的选择。这款软件不仅支持多种格式的压缩和解压,如zip、rar、7z、tar等,还具备丰富的功能和设置,包括预览…...
2024/5/2 2:34:06 - 【外汇早评】美通胀数据走低,美元调整
原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...
2024/5/1 17:30:59 - 【原油贵金属周评】原油多头拥挤,价格调整
原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...
2024/5/2 16:16:39 - 【外汇周评】靓丽非农不及疲软通胀影响
原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...
2024/4/29 2:29:43 - 【原油贵金属早评】库存继续增加,油价收跌
原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...
2024/5/2 9:28:15 - 【外汇早评】日本央行会议纪要不改日元强势
原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...
2024/4/27 17:58:04 - 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响
原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...
2024/4/27 14:22:49 - 【外汇早评】美欲与伊朗重谈协议
原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...
2024/4/28 1:28:33 - 【原油贵金属早评】波动率飙升,市场情绪动荡
原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...
2024/4/30 9:43:09 - 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试
原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...
2024/4/27 17:59:30 - 【原油贵金属早评】市场情绪继续恶化,黄金上破
原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...
2024/5/2 15:04:34 - 【外汇早评】美伊僵持,风险情绪继续升温
原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...
2024/4/28 1:34:08 - 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势
原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...
2024/4/26 19:03:37 - 氧生福地 玩美北湖(上)——为时光守候两千年
原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...
2024/4/29 20:46:55 - 氧生福地 玩美北湖(中)——永春梯田里的美与鲜
原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...
2024/4/30 22:21:04 - 氧生福地 玩美北湖(下)——奔跑吧骚年!
原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...
2024/5/1 4:32:01 - 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!
原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...
2024/4/27 23:24:42 - 「发现」铁皮石斛仙草之神奇功效用于医用面膜
原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...
2024/4/28 5:48:52 - 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者
原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...
2024/4/30 9:42:22 - 广州械字号面膜生产厂家OEM/ODM4项须知!
原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...
2024/5/2 9:07:46 - 械字号医用眼膜缓解用眼过度到底有无作用?
原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...
2024/4/30 9:42:49 - 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...
解析如下:1、长按电脑电源键直至关机,然后再按一次电源健重启电脑,按F8健进入安全模式2、安全模式下进入Windows系统桌面后,按住“winR”打开运行窗口,输入“services.msc”打开服务设置3、在服务界面,选中…...
2022/11/19 21:17:18 - 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。
%读入6幅图像(每一幅图像的大小是564*564) f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...
2022/11/19 21:17:16 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...
win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面,在等待界面中我们需要等待操作结束才能关机,虽然这比较麻烦,但是对系统进行配置和升级…...
2022/11/19 21:17:15 - 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...
有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows,请勿关闭计算机”的提示,要过很久才能进入系统,有的用户甚至几个小时也无法进入,下面就教大家这个问题的解决方法。第一种方法:我们首先在左下角的“开始…...
2022/11/19 21:17:14 - win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...
置信有很多用户都跟小编一样遇到过这样的问题,电脑时发现开机屏幕显现“正在配置Windows Update,请勿关机”(如下图所示),而且还需求等大约5分钟才干进入系统。这是怎样回事呢?一切都是正常操作的,为什么开时机呈现“正…...
2022/11/19 21:17:13 - 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...
Win7系统开机启动时总是出现“配置Windows请勿关机”的提示,没过几秒后电脑自动重启,每次开机都这样无法进入系统,此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一:开机按下F8,在出现的Windows高级启动选…...
2022/11/19 21:17:12 - 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...
有不少windows10系统用户反映说碰到这样一个情况,就是电脑提示正在准备windows请勿关闭计算机,碰到这样的问题该怎么解决呢,现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法:1、2、依次…...
2022/11/19 21:17:11 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...
今天和大家分享一下win7系统重装了Win7旗舰版系统后,每次关机的时候桌面上都会显示一个“配置Windows Update的界面,提示请勿关闭计算机”,每次停留好几分钟才能正常关机,导致什么情况引起的呢?出现配置Windows Update…...
2022/11/19 21:17:10 - 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...
只能是等着,别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚,只能是考虑备份数据后重装系统了。解决来方案一:管理员运行cmd:net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...
2022/11/19 21:17:09 - 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?
原标题:电脑提示“配置Windows Update请勿关闭计算机”怎么办?win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢?一般的方…...
2022/11/19 21:17:08 - 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...
关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!关机提示 windows7 正在配…...
2022/11/19 21:17:05 - 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...
钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...
2022/11/19 21:17:05 - 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...
前几天班里有位学生电脑(windows 7系统)出问题了,具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面,长时间没反应,无法进入系统。这个问题原来帮其他同学也解决过,网上搜了不少资料&#x…...
2022/11/19 21:17:04 - 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...
本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法,并在最后教给你1种保护系统安全的好方法,一起来看看!电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中,添加了1个新功能在“磁…...
2022/11/19 21:17:03 - 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...
许多用户在长期不使用电脑的时候,开启电脑发现电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机。。.这要怎么办呢?下面小编就带着大家一起看看吧!如果能够正常进入系统,建议您暂时移…...
2022/11/19 21:17:02 - 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...
配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!配置windows update失败 还原更改 请勿关闭计算机&#x…...
2022/11/19 21:17:01 - 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...
不知道大家有没有遇到过这样的一个问题,就是我们的win7系统在关机的时候,总是喜欢显示“准备配置windows,请勿关机”这样的一个页面,没有什么大碍,但是如果一直等着的话就要两个小时甚至更久都关不了机,非常…...
2022/11/19 21:17:00 - 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...
当电脑出现正在准备配置windows请勿关闭计算机时,一般是您正对windows进行升级,但是这个要是长时间没有反应,我们不能再傻等下去了。可能是电脑出了别的问题了,来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...
2022/11/19 21:16:59 - 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...
我们使用电脑的过程中有时会遇到这种情况,当我们打开电脑之后,发现一直停留在一个界面:“配置Windows Update失败,还原更改请勿关闭计算机”,等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢࿰…...
2022/11/19 21:16:58 - 如何在iPhone上关闭“请勿打扰”
Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...
2022/11/19 21:16:57