(1)双向数据绑定必须在表单里面使用,如input、select
双向绑定原理:
采用数据劫持结合发布者-订阅者模式的方法,通过Object.defineProperity()来劫持各个属性的set,get,在数据变动时发布消息给订阅者,触发相应的监听回调。
数据劫持通过Object.defineProperity(obj,prop,descriptor)方法来实现,当我们访问或设置对象属性时都会触发该方法,当触发方法时,做一些其他操作,就是“劫持”操作。
其中参数obj表示目标对象;props需要定义的属性或方法名称;descriptor表示目标属性所拥有的特性。
var obj={ text:123, name:"an" } Object.defineProperty(obj,"text",{ configurable:false, //configurable是否可以删除目标属性或是否可以再次修改属性的特性,设置为true可以被删除或可以重新设置特性;设置为false,不能被可以被删除或不可以重新设置特性。默认为false。 value:4, writable:false,//是否可以被重写 enumerable:false //enumerable是否可以被枚举(使用for...in或者Object.keys()) }) console.log(obj.text);//4 obj.text=5; console.log(obj.text);//4 for(var i in obj){ console.log(i);//只显示name } delete obj.text; console.log(obj.text);//不可删除仍然可以打印出4
//手写一个简单的双向绑定 <input type='text' id='model'/> <p id='text'></p> <script> var user={}; var model=document.getElementById('model'); var val=document.getElementById('text'); //数据劫持 Object.defineProperty(user,"name",{ get:function(){ console.log('获取输入值'); return model.value; }, set:function(newValue){ model.value=newValue; val.textContent=newValue; } }) //发布订阅模式 model.addEventListener('keyup',function(){ console.log("从视图->数据"); user.name=this.value; }) setTimeout(function(){ console.log('从数据——>视图'); user.name="修改后的新值"; },3000) </script>
当在输入框输入数据时,首先触发input事件,在相应的事件处理程序中,将获得的value值赋值给vm实例的text属性,我们会利用defineProperity将data中的text设置为value值,就会触发set方法。
text属性变化了,set方法触发了,但是文本节点的内容没有变化。如何才能绑定到text文本节点也同步变化呢?这里用到订阅发布模式。
订阅发布模式又称为观察者模式,定义了一种一对多的关系,让多个观察者同时监听某一个主题对象,一旦这个主题对象的状态发生改变时就会通知所有的观察者对象。
发布订阅模式的优点:
- 实现时间上的解耦(组件,模块之间的异步通讯);
- 对象之间的解耦。
发布订阅模式的缺点:
- 创建订阅者本身会消耗内存,订阅消息后,也许永远不会有发布,而订阅者始终存在内存中;
- 对象之间解耦的同时,他们的关系也会被深埋在代码背后,这会造成一定的维护成本。
(2)ref用来获取dom节点,如
<input type="text" ref='sexValue'/>
<div ref='boxValue'></div>
<button v-on:click="getInputValue()">获取dom的内容</button>
methods:{
getInputValue(){
console.log(this.$refs.sexValue);
alert(this.$refs.sexValue.value);
}
}
(3)绑定属性 v-bind:
<img v-bind:src='url'/>
<img :src='url'/>
绑定方法 v-on:click:
<button v-on:click="getname()">获取表单内容</button>
<button @click="setname()">设置表单内容</button>
(4)v-if与v-show的区别
v-if是条件渲染,在初始条件为假时不会被渲染;v-show无论初始条件是什么都会被渲染,只是控制显示与隐藏。
v-if有更高的切换开销,而v-show有更高的初始渲染开销,如果需要频繁切换,则使用v-show,如果在运行条件很少时用v-if
(5)<keep-alive>
<keep-alive>是Vue的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染dom。
我们之前曾经在一个多标签的界面中使用 is
特性来切换不同的组件,
如<component v-bind:is="currentTabComponent"></component>
当这些组件之间切换时,有时想保持这些组件的状态,以避免反复重渲染导致的性能问题。
如上图page1、page2、page3按钮为组件之间的切换,正常情况下,当在组件page1中选择其它tab时,下次再回到该组件则会重新渲染,默认选中的是“php”,如果使用<keep-alive>将这些动态组件包裹住,则下次再点击page1时,还是上次选中的“javascript”
(6)计算属性vs方法
对于任何复杂逻辑,都应当使用计算属性
computed: {
// 计算属性的 getter
reversedMessage: function () {
return this.message.split('').reverse().join('')
}
}
通过{{reversedMessage}}获取计算结果。
也可以将一个函数定义为一个方法而不是计算属性,两种最终结果是完全相同的,但是
计算属性是基于它们的依赖进行缓存的,只有在相关依赖发生变化时才会重新求值,这就意味着只要 message
还没有发生改变,多次访问 reversedMessage
计算属性会立即返回之前的计算结果,而不必再次执行函数。
methods: {
reversedMessage: function () {
return this.message.split('').reverse().join('')
}
}
通过{{reversedMessage()}}获取计算结果。相比之下,每当触发重新渲染时,调用方法将总会再次执行函数。
(7)计算属性computed VS 侦听器watch
computed计算属性是用来声明式的描述一个值依赖了其他的值。当你把模板里的数据绑定到一个计算属性上时,vue会在其依赖的任何值导致该计算属性改变时更新DOM。
watch监听的是你定义变量,当定义的变量的值发生变化时,调用对应的方法。
而计算属性计算的是fullName依赖的值,他不能计算在data中已经定义过的变量。
(8)v-bind与v-on的区别
v-bind用于设置属性,如v-bind:href,缩写为 :href
v-on用于绑定事件 如v-on:click,缩写为 @click
(9)插槽slot
通过插槽分发内容
单个插槽:
父组件
子组件testSlot.vue
具名插槽:就是将某个名字的内容插到子组件对应名字里面去
父组件:
子组件:
运行结果:
我们还是可以保留一个未命名插槽,这个插槽是默认插槽,也就是说它会作为所有未匹配到插槽内容的统一出口。