1. Vue实例就是其中的data下的对象。 Vue实例的改变,也会导致其中对象的改变。如下:
<script> var bar = { foo: "zzw" }; var vm = new Vue({ data: bar }); console.log(vm.foo === bar.foo); // true vm.foo = "htt"; console.log(bar.foo); // htt bar.foo = "baby"; console.log(vm.foo); // baby </script>
在这里,通过Vue构造函数创建的实例 vm 就是bar。
2. Vue的实例还暴露了一些属性和方法。 其中比较有意思的是$watch方法,即监视某一个元素,一旦那个元素发生了变化,就去调用这个回调函数,如下所示。
<script> var bar = { foo: "zzw", baz: "ht" }; var vm = new Vue({ el: ".wrap", data: bar }); console.log(vm.$data.foo); //zzw console.log(vm.$el); //<div class="wrap"></div> // 可以看到,vm是了一个Vue实例,如果需要调用其中的属性,使用$调用即可。 // vue自身还有一些暴露的方法,如watch // 不论是实例的属性还是方法,调用时都需要使用$ </script>
3. 生命周期与生命周期钩子
这篇博客介绍了生命周期。
在vue中,一个通过Vue构造函数创建的实例是有声明周期的,比如创建前,创建中,创建后。。。这就是生命周期。这是随便说的,大概是这么个意思,因为实际上肯定比这个复杂。 如vue中的created方法可以定义在vue实例中,一旦实例被创建,就会调用这个方法。 这个方法与生命周期相关,并且是一个方法,即与某一个事件相关联,所以称之为生命周期钩子。如下:
var bar = { foo: "zzw", baz: "ht" }; var vm = new Vue({ data: bar, created: function () { console.log("我是与生命周期相关的钩子,一旦Vue实例创建完成,我就会被调用!"); } });
下面就是vue中的声明周期,看了就知道东西很多。。。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>vue生命周期</title> <script src="../js/vue.js"></script> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> </head> <body> <div class="test" style="border: 1px black dashed;padding: 8px;"> {{a}} </div> <div class="test2" style="border: 1px red solid;margin-top: 10px;padding: 8px;"> 我是内容二 </div> <script type="text/javascript"> var myVue = new Vue({ el: ".test", data: { a: "我是内容,在控制台输入myVue.a=123456,可以改变我的值" }, created: function () { //在实例创建之后同步调用。此时实例已经结束解析选项,这意味着已建立:数据绑定,计算属性,方法,watcher/事件回调。 //但是还没有开始 DOM 编译,$el 还不存在,但是实例存在,即this.a存在,可打印出来 。 console.log("建立"); }, beforeCompile: function () { console.log("未开始编译"); }, compiled: function () { //在编译结束后调用。此时所有的指令已生效,因而数据的变化将触发 DOM 更新。但是不担保 $el 已插入文档。 console.log("编译完成"); }, ready: function () { //在编译结束和 $el 第一次插入文档之后调用,如在第一次 attached 钩子之后调用。注意必须是由 Vue 插入(如 vm.$appendTo() 等方法或指令更新)才触发 ready 钩子。 console.log("一切准备好了"); }, attached :function () { //myVue.$appendTo(".test2")暂时触发不了,不知道怎么解决 //在 vm.$el 插入 DOM 时调用。必须是由指令或实例方法(如 $appendTo())插入,直接操作 vm.$el 不会 触发这个钩子。 console.log("插入DOM成功"); }, detached :function () { //触发事件 myVue.$destroy(true),其中参数true控制是否删除DOM节点或者myVue.$remove() //在 vm.$el 从 DOM 中删除时调用。必须是由指令或实例方法删除,直接操作 vm.$el 不会 触发这个钩子。 console.log("删除DOM成功"); }, beforeDestroy: function () { //触发方式,在console里面打myVue.$destroy(); //在开始销毁实例时调用。此时实例仍然有功能。 console.log("销毁前"); }, destroyed: function () { //触发方式,在console里面打myVue.$destroy();其中myVue.$destroy(true)是删除DOM节点,会触发detached函数,但是实例仍然存在 //在实例被销毁之后调用。此时所有的绑定和实例的指令已经解绑,注意是解绑不是销毁,所有的子实例也已经被销毁。 console.log("已销毁"); } }); </script> </body> </html>
4. 模板语法 && 表达式
显然,在div中会被渲染为hello world! JohnZhu 值得注意的是: 不难发现,data一定是要写成对象的形式,否则:怎么有名值对呢?
另外,我们常常使用v-bind来绑定属性,属性直接使用“”括起来就行,不需要{{}}的形式。
<div class="wrap" v-bind:title="title.toUpperCase()"> {{message + "JohnZhu"}} </div>
<script>
var vm = new Vue({
el: ".wrap",
data: {
message: "hello world!",
title: "myTitle"
}
});
</script>
注意: 在{{}}中和v-bind后面的双引号中我们都可以使用JavaScript表示式,但是不能使用语句,如var a = "d"; if () {} 这样的都是非法的。
5. 指令 && 缩写
在之前的文章中我也介绍了v-bind 、v-if、 v-on等指令。 使用也都非常简单。
这些指令是可以缩写的,但是并没有少多少东西,我个人不是很喜欢。如:
<!-- 完整语法 --> <a v-bind:href="url"></a> <!-- 缩写 --> <a :href="url"></a>
6. 过滤器
过滤器是在创建Vue实例时当做方法写进去的, 而定义过滤器是在{{}}或者v-bind中变量的后面使用 | 分隔定义名称的,后面还可以再来几个 | , 即串联过滤器。如下:
<div class="wrap" v-bind:title="title.toUpperCase() | lowercase"> {{message + "JohnZhu" | lowercase}} </div> <script> var vm = new Vue({ el: ".wrap", data: { message: "hello world!", title: "myTitle" }, filters: { lowercase: function (value) { return value.toLowerCase() } } }); </script>
- filters 只用于 {{}}和v-bind,因为使用它的目的在于处理文字。
- filters 又是一个对象, 虽然说有个s,但不是数组, 因为利用属性会更好调用一些。
- filters关键词一定是需要的。 如果说我们只是直接和el与data平等的地位上定义了lowercase,那显然是不合理的,并且这种调用只能是使用$来调用,而{{}}只支持表达式,不支持语句。
8. 计算属性
虽然使用模板语法可以对文字进行简单的操作,但是如果操作复杂一些,那么就会难以控制,如下所示:
<div id="example"> {{ message.split('').reverse().join('') }} </div>
由此,计算属性营运而生:
<div class="wrap"> <p>{{message}} </p> <p>{{reverseMessage}}</p> </div> <script> var vm = new Vue({ el: ".wrap", data: { message: "hello world!", title: "myTitle" }, computed: { reverseMessage: function () { return this.message.split("").reverse().join("" ) } } }); console.log(vm.reverseMessage);//!dlrow olleh </script>
可以看到,计算属性并没有太多不同的地方,只是把这个方法定义在了computed对象中。 值得注意的是: vm代表着其中的data,但是还可以访问到这个计算属性的方法,其值为返回值。
另外,如果在控制台中输入 vm.message = "ajaj" 那么就可以看到页面的渲染立马成了jaja,即计算方法中的值始终依赖于前者。并且,我们使用了this,注意这里的this就代表着vm。(个人理解~)
我们还可以使用设定方法来实现,如下所示:
<div class="wrap"> <p>{{message}} </p> <p>{{reverseMessage()}}</p> </div> <script> var vm = new Vue({ el: ".wrap", data: { message: "hello world!", title: "myTitle" }, methods: { reverseMessage: function () { return this.message.split("").reverse().join("" ) } } }); console.log(vm.reverseMessage);//!dlrow olleh </script>
这样的效果和上面(使用computed计算属性)是一样的,但是区别在哪里呢?
我们可以将同一函数定义为一个 method 而不是一个计算属性。对于最终的结果,两种方式确实是相同的。然而,不同的是计算属性是基于它们的依赖进行缓存的。计算属性只有在它的相关依赖发生改变时才会重新求值。这就意味着只要
message
还没有发生改变,多次访问reversedMessage
计算属性会立即返回之前的计算结果,而不必再次执行函数。相比而言,只要发生重新渲染,method 调用总会执行该函数。
8. 观察watchers
<div class="wrap"> <p>{{message}}</p> <p>{{another}}</p> </div> <script> var vm = new Vue({ el: ".wrap", data: { message: "time", another: "" }, watch: { message: function () { this.another = "改变了" } } }); </script>
即watch用于检测data中的一个属性是否发生了变化。 这里是watch数据data中的message,一旦message发生了变化,就执行后面的函数。
9. class绑定
<div class="foo" v-bind:class="{active: isActive, larger: isLarger}" ></div> <script> var vm = new Vue({ el: ".foo", data: { isActive: true, isLarger: false } }); </script>
最终渲染出的class有foo(自身就有的,不会影响)、active(因为isActive的值是true), larger不会有,因为isLarger是false。
值得注意的是: 对于绑定,我们可以看到,绑定元素内部的变量始终和data的第一层变量相对应。 如果我们给class绑定一个对象,那么data下面的第一层也应当是对象,如下所示:
<div class="foo" v-bind:class="classObj"></div> <script> var vm = new Vue({ el: ".foo", data: { classObj: { active: true, larger: false } } }); </script>
这个效果和上面的效果是一样的,这个并不难理解,另外, 更为强大的是, 还可以给class使用v-bind绑定计算属性,如下所示:
<div class="foo" v-bind:class="computedClass">{{message}}</div> <script> var vm = new Vue({ el: ".foo", data: { isActive: true, isLarger: false, message: "hello world!" }, computed: { computedClass: function () { return { active: this.isActive, larger: this.isLarger }; // return 一个对象很好理解: 因为这样和前面的几个例子都是一样的。 } } });
计算属性的使用是我们可以操纵更为复杂的场景称为可能。 同时this还是只vm这个实例。 当然computed计算属性下的computedClass最终也可以返回一个字符串,就是类名,这个很容易理解。如下:
<div class="foo" v-bind:class="computedClass">{{message}}</div> <script> var vm = new Vue({ el: ".foo", data: { isActive: true, isLarger: false, message: "hello world!" }, computed: { computedClass: function () { return "active footer"; } } }); </script>
最终的效果还是一样的。
另外,还可以传入一个数组,但是这里和对象的意义就不同的,不再是指true或false。
<div class="foo" v-bind:class="[class1, class2]">{{message}}</div> <script> var vm = new Vue({ el: ".foo", data: { class1: "active", class2: "larger", message: "hello world!" } }); </script>
最终的效果还是一样的。
最后需要说明的是,这样的绑定方法也可以用在组件上。后面讲到组件时会详细讲解。
10. 绑定style内联样式
对象语法 --- 即内联为一个js对象,然后在vue中的data下定义变量值。 CSS 属性名可以用驼峰式(camelCase)或短横分隔命名(kebab-case)。如下:
<div class="wrap" v-bind:style="{color: myColor, fontSize: myFontSize}">{{message}}</div> <script> var vm = new Vue({ el: ".wrap", data: { myColor: "red", myFontSize: "30px", message: "hello world!" } }); </script>
当然,我们也可以直接绑定一个对象,和之前介绍class时是一样的。
数组语法 --- 即一个数组中有多个对象,我们再定义对象即可,如下所示:
<div class="wrap" v-bind:style="[styleObj1, styleObj2]">{{message}}</div> <script> var vm = new Vue({ el: ".wrap", data: { styleObj1: { color: "red", fontSize: "30px" }, styleObj2: { margin: 0, padding: 0 }, message: "hello world!" } }); </script>
11. 条件渲染
<div class="wrap"> <p v-if="type == 'a'"> 这是a </p> <p v-else-if="type == 'b'"> 这是b </p> <p v-else-if="type == 'c'"> 这是c </p> <p v-else> 不是a也不是b也不是c </p> </div> <script> var vm = new Vue({ el: ".wrap", data: { type: "b" } }); </script>
在data中type为b时, 就会输出这是b, 即vue中支持 if、 if-else、 else这些语句,使用起来非常方便。
12. v-show指令与v-if指令
看下面这个例子:
<div class="wrap"> <p v-show="ifShow"> show </p> </div> <script> var vm = new Vue({ el: ".wrap", data: { ifShow: true } }); </script>
最终show会渲染出来,但是如果ifShow为false,show就不会渲染出来。
另外,我们将v-show修改为v-if,最终效果也是一样的,那么两者的区别在哪里呢?
我们通过审查元素可以看到: v-if为false时,dom中不会出现p的dom,如下:
但是使用v-show,就会发现,其中的dom还是存在的,只是通过控制 display: none来使之没有渲染到页面上,如下:
官网上是这样解释两者的区别的:
v-if
是“真正的”条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
v-if
也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。相比之下,
v-show
就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。一般来说,
v-if
有更高的切换开销,而v-show
有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用v-show
较好;如果在运行时条件不太可能改变,则使用v-if
较好。
2017年5月31日补充:
可以理解: if为是否存在,即有就是有,没有就是没有;而show是存在的情况下,要不要展示出来。
显然if为true时,需要插入、显示等,比使用show有更高的切换开销,所以在频繁切换时最好使用show,而不是if。
13 列表渲染
<div class="wrap"> <p v-for="(item,index) in items"> {{item + " " + index}} </p> <p v-for="list of lists"> {{list.message}} </p> </div> <script> var vm = new Vue({ el: ".wrap", data: { items: [ "first", "second", "third" ], lists: [ {message: "message1"}, {message: "message2"}, {message: "message3"} ] } }); </script>
可以看到: v-for的作用是循环列表,并且可以使用 of 替换其中的in, 既然是列表,就需要使用数组, 所以列表名下都是数组。 数组中的元素可以是一般的字符串,也可以是对象。 另外,wrap元素一定要包含列表元素,即列表元素的上层不可以是body。 还可以看到, 对于in之前,我们可以使用item(数组中的每一个值)或者index(每一个元素的索引)。
另外,刚刚说到,循环的是一个数组(列表),但是我们知道 for in 的用法是更多是用来遍历对象的属性的, 之所以数组也这么用,大概有希望统一的意味吧。 如下所示:
<div class="wrap"> <p v-for="(value,key,index) in objects"> {{value + "-" + key + "-" + index}} </p> </div> <script> var vm = new Vue({ el: ".wrap", data: { objects: { first: "one", second: "two", third: "three" } } }); </script>
最终渲染的结果如下:
整数迭代:(类似于for(var i = 0; i < 10; i++)来迭代模板),如下所示:
<div class="wrap"> <ul v-for="value in 10"> <li>第{{value}}个</li> </ul> </div> <script> var vm = new Vue({ el: ".wrap", }); </script>
最终效果如下所示:
注意: v-for的优先级高于v-if
14. 事件处理器
vue中可以使用v-on来监听一些dom事件从而触发一些事件方法。
<div class="wrap"> <button v-on:click="alertSomething">按钮</button> </div> <script> var vm = new Vue({ el: ".wrap", methods: { alertSomething: function () { alert('clicked'); } } }); </script>
这就是一种最为简单、常用的触发事件的形式。
15. 事件修饰符
事件中,我们可能常常需要使用到e.stopPropagation() 或者 e.preventDefault() 方法,这在method中显然很容易实现,但是vue是使用了事件修饰符的方法即通过(.)的形式添加事件修饰符。
<!-- 阻止单击事件冒泡 --> <a v-on:click.stop="doThis"></a> <!-- 提交事件不再重载页面 --> <form v-on:submit.prevent="onSubmit"></form> <!-- 修饰符可以串联 --> <a v-on:click.stop.prevent="doThat"></a> <!-- 只有修饰符 --> <form v-on:submit.prevent></form> <!-- 添加事件侦听器时使用事件捕获模式 --> <div v-on:click.capture="doThis">...</div> <!-- 只当事件在该元素本身(而不是子元素)触发时触发回调 --> <div v-on:click.self="doThat">...</div>
2.1.4中新增了once修饰符,即只触发一次。
如下所示:
<div class="wrap"> <div> <span v-on:click="doanother"> <a href="https://www.baidu.com/" v-on:click.stop.prevent="dosomething">百度一下</a>
<button v-on:click.once="alertsomething">触发一次</button> </span> </div> </div> <script> var vm = new Vue({ el: ".wrap", methods: { dosomething: function () { console.log('clicked'); }, doanother: function () { console.log('bubbled'); },
alertsomething: function () {
alert('once');
}
}
});
</script>
如上所示: 我们给a标签绑定了一个事件,并且通过stop阻止了事件冒泡,通过prevent阻止了默认事件(定向到百度)发生,即支持串联(链式调用)。
16. 按键修饰符
我们常常需要监测键值,如按下enter来提交等等,在vue中通过按键修饰符很好的解决了这个问题。如下:
<div class="wrap"> <div> <span v-on:click="doanother"> <input v-on:keyup.space="alertsomething" type="text" placeholder="tab for alert" value=""> <input v-on:keyup.enter="alertsomething" type="text" placeholder="enter for alert" value=""> </span> </div> </div> <script> var vm = new Vue({ el: ".wrap", methods: { alertsomething: function () { alert('click'); } } }); </script>
即使用v-on绑定事件,keyup是任何按键弹起都会触发,所以进一步使用按键修饰符。
全部的按键修饰符有:
- .enter
- .tab
- .delete
- .esc
- .space
- .up
- .down
- .left
- .right
我们还可以通过config.keyCode对象来自定义按键修饰符名称,如:
// 可以使用 v-on:keyup.f1 Vue.config.keyCodes.f1 = 112
又如:
<div class="wrap"> <div> <span> <input v-on:keyup.f2="alertsomething" type="text" placeholder="enter for alert" value=""> </span> </div> </div> <script> Vue.config.keyCodes.f2 = 113; var vm = new Vue({ el: ".wrap", methods: { alertsomething: function () { alert('click'); } } }); </script>
注意: 这时我们可以将v-on:keyup.f2简写为@:keyup.f2
对照表如下:
在vue的2.1.0中新增了下面几个常用的控制按键:
- .ctrl
- .shift
- .alt
- .meta
注意:在Mac系统键盘上,meta对应命令键 (⌘)。在Windows系统键盘meta对应windows徽标键(⊞)。在Sun操作系统键盘上,meta对应实心宝石键 (◆)。在其他特定键盘上,尤其在MIT和Lisp键盘及其后续,比如Knight键盘,space-cadet键盘,meta被标记为“META”。在Symbolics键盘上,meta被标记为“META” 或者 “Meta”。
例如:
如果我们将上面的例子中的<input v-on:keyup.f2="alertsomething" type="text" placeholder="enter for alert" value="">修改为下面的代码:
<input v-on:keyup.ctrl.alt.f2="alertsomething" type="text" placeholder="enter for alert" value="">
那么我们必须同时按下 ctrl + alt + f2 才能触发事件。
17. 表单控件绑定
我们再vue中听的最多的就是双向数据绑定了,使用 v-model 就可以实现双向数据绑定, 且必须在input中使用,如下所示:
<div class="wrap"> <input type="text" v-model="message" placeholder="edit me"> <p>双向数据绑定:{{message}}</p> </div> <script> Vue.config.keyCodes.f2 = 113; var vm = new Vue({ el: ".wrap", data: { message: "" } }); </script>
即v-model的值就是我们希望绑定的值,另外,message必须在创建vue实例时定义,否则就不会有这个数据,会出错。
注: input是单行文本,我们也可以使用textarea实现多行文本。
不仅如此,同样是input的单选框也可以使用。
<div class="wrap"> <input type="radio" id="first" value="first" v-model="picked"> <label for="first">one</label> <br> <input type="radio" id="second" value="second" v-model="picked"> <label for="second">two</label> <p>双向数据绑定:{{picked}}</p> </div> <script> var vm = new Vue({ el: ".wrap", data: { picked: "" } }); </script>
效果如下,效果还是非常好的~
对于选择列表我们可以这么定义:
<div id="example-5" class="demo"> <select v-model="selected"> <option>A</option> <option>B</option> <option>C</option> </select> <span>Selected: {{ selected }}</span> </div>
绑定value
对于复选框而言,如下所示:
<div class="wrap"> <input id="s" type="checkbox" v-model="toggle" v-bind:true-value="a" v-bind:false-value="b" > <label for="s">选择</label> </div> <script> var vm = new Vue({ el: ".wrap", data: { toggle: "", a: "select", b: "notSelect" } }); </script>
即当选中的时候, toggle的值为“select”,否则为“notSelect”。
对于单选框而言,如下所示:
<div class="wrap"> <input type="radio" v-model="one" v-bind:value="aaa"> </div> <script> var vm = new Vue({ el: ".wrap", data: { one: "", aaa: "hahaha" } }); </script>
一旦单选框被选中,那么vm.one的值就成了vm.aaa的值。
表单修饰符
包括 .number .trim .lazy
18. vue组件注册
组件(Component)是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素, Vue.js 的编译器为它添加特殊功能。在有些情况下,组件也可以是原生 HTML 元素的形式,以 is 特性扩展。
注册:
组件的渲染分为两步,第一: 通过 Vue.component() 注册组件; 第二: 通过new Vue() 创建根实例使用组件。举例如下:
<div class="wrap"> <my-component></my-component> </div> <script> Vue.component('my-component', { template: '<h3> hello world! </h3>' }); var vm = new Vue({ el: '.wrap' }); </script>
这就是创建一个模板最简单的过程,注意:1. Vue.component()接受两个参数,第一个是自定义的名称,第二个是template下内容和其他。 2. 无论是否使用模板,使用vue,就一定要创建vue实例。
局部注册:
这一块不知所云。。
另外,如果包裹元素是 ol ul table等时,可能会出现问题,那就可以使用is属性,如下:
<div class="wrap"> <table> <tr is="my-component"></tr> </table> <!-- <table> <my-component></my-component> </table> --> </div> <my-component></my-component> <script> Vue.component('my-component', { template: '<h3> hello world! </h3>' }); var vm = new Vue({ el: '.wrap' }); </script>
如果我们需要给模板中传递一些数据,那么就要在模板的options中添加data(注意: data必须是一个函数,返回一个对象,对象中包含名值对即可), 和react类似,如果模板中希望出现多个标签,就一定要使用一个根标签包裹起来,如下所示:
<div class="wrap"> <my-component></my-component> </div> <script> Vue.component('my-component', { template: '<div><span>{{ message }}</span><h3>{{ another }}</h3></div>', data: function () { return { message: "hello world!", another: "hjj" } } }) var vm = new Vue({ el: '.wrap' }); </script>
即其中的data必须是一个函数,否则报错; 另外如果tamplate中没有div包裹,也会提示错误。
另外,文档上也举例了一个很好的例子,就是在 模板 中return一个对象时,如果return事先创建好的对象,那么就会所有的组件引用这个对象,状态相同,如果return一个{}对象,那么状态就是独立的,因为这样会创建一个实例就创建一个对象。不会共享。
19. 父组件与子组件
我们很容易就可以将两个组件写在一起,如下所示:
<div class="wrap"> <outer-component></outer-component> </div> <script> Vue.component('outer-component', { template: '<div><h3>{{outerMessage}}</h3><inner-component></inner-component></div>', data: function () { return { outerMessage: "I AM THE OUTERMESSAGE!" } } }) Vue.component('inner-component', { template: '<span>{{innerMessage}}</span>', data: function () { return { innerMessage: "I AM THE INNERMESSAGE!" } } }) var vm = new Vue({ el: '.wrap' }); </script>
但是这是最简单不过的组件形式了,大多数情况下,父组件都要向子组件传递消息,而子组件也需要向父组件告知变化, 并且两者必须是解耦的,这样才能保证重用。
在vue中使用props down从父组件向子组件传递消息(和vue一样), 使用event up从子组件向父组件告知事件。 如下所示:
20. prop
通过在Vue.component中添加props属性,我们就可以通过组件向内部传递信息了:
<div class="wrap"> <inner-component propmessage="good" another="another"></inner-component> </div> <script> Vue.component('inner-component', { template: '<span>{{innerMessage}} --- {{propmessage}} --- {{another}}</span>', props: ['propmessage','another'], data: function () { return { innerMessage: "I AM THE INNERMESSAGE!" } } }) var vm = new Vue({ el: '.wrap' }); </script>
props和data的区别在哪呢? --- 前者是通过属性(property)来传递信息, 而后者是通过内部的data传递信息。
21. camelCase vs. kebab-case
camelCase是指驼峰式写法, 而kebab-case是指短横线的写法,在使用props时,如果其中有驼峰写法,那么在dom中,要改成短横线式的写法。如果不转换,就会报错:
<div class="wrap"> <my-component propMessage="good"></my-component> </div> <script> Vue.component('my-component', { template: '<span>{{propMessage}}</span>', props: ['propMessage'], }) var vm = new Vue({ el: '.wrap' }); </script>
控制台报错如下:
即提示我们需要使用 prop-message 而不是 propMessage, 即改写如下:
<div class="wrap"> <my-component prop-message="good"></my-component> </div>
这样就可以正确渲染了。
22. 动态prop
即我们可以通过v-model(input中的)和组件的prop动态数据绑定,如下:
<div class="wrap"> <input type="text" v-model="message"> <!-- <div>{{message}}</div> --> <my-component v-bind:prop-message="message"></my-component> </div> <script> Vue.component('my-component', { template: '<span>{{propMessage}}</span>', props: ['propMessage'], }) var vm = new Vue({ el: '.wrap', data: { message: '' } }); </script>
即不仅可以和普通的div数据双向绑定,还可以和 组件进行数据双向绑定, 规则都是在input使用v-model。
另外,如果我们传递一个数值,不能直接使用prop,而必须使用v-bind。 看下面的例子:
<div class="wrap"> <my-component prop-message="1"></my-component> <br/> <my-component v-bind:prop-message="1"></my-component> </div> <script> Vue.component('my-component', { template: '<span>{{typeof propMessage}}</span>', props: ['propMessage'], }) var vm = new Vue({ el: '.wrap', data: { message: '' } }); </script>
结果如下:
可以看出第一个传进去的1是string, 而第二个穿进去的1是number。 因为使用v-bind后,它的值会被当成JavaScript表达式来计算。 也就是说,<my-component v-bind:prop-message="'1'"></my-component>这之中的1才是字符串。
23. vue中prop的单项数据流
prop是单项绑定的, 即父组件发生变化时,会将状态传递给子组件,但是不会反过来, 因为这样可以防止子组件无意间修改父组件的状态,这样会让数据流难以理解。 --- 简直和react一模一样。。。。
另外,每次父组件更新时,子组件的所有 prop 都会更新为最新值。这意味着你不应该在子组件内部改变 prop 。如果你这么做了,Vue 会在控制台给出警告。
那么什么情况下我们可能会犯修改子组件内部的prop的错误呢?
- prop作为初始值传进来以后, 子组件希望把它当做局部数据来用 --- 不可以
- prop作为初始值传入后,子组件希望处理成其他数据输出。 --- 不可以
虽然这两种方式都是不可行的,但是我们都有相应的解决方法!
对于第一种情况,我们可以定义一个局部变量,并用prop的值初始化它,如下:
props: ['initialCounter'], data: function () { return { counter: this.initialCounter } }
这样,我们只是获取了这个prop值,并没有修改它。
对于第二种情况,我们可以定义一个计算属性, 处理后返回即可,如下:
props: ['size'], computed: { normalizedSize: function () { return this.size.trim().toLowerCase() } }
注意在 JavaScript 中对象和数组是引用类型,指向同一个内存空间,如果 prop 是一个对象或数组,在子组件内部改变它会影响父组件的状态。
23. prop验证
传递prop时,我们可以进行验证格式,如果有问题,就报错!
<div class="wrap"> <my-component v-bind:prop-message="1" v-bind:another="100"></my-component> </div> <script> Vue.component('my-component', { template: '<span>{{typeof propMessage}} {{typeof another}}</span>', props: { propMessage: String, another: { type: Number // default: 100 } } }) var vm = new Vue({ el: '.wrap' }); </script>
之前我们定义props时使用的是数组形式,即一次直接定义多个props,但是如果我们希望验证格式,我们就可以使用 {} 的形式,这样具有的灵活性更好一些。 如上,我们可以使用String定义必须接受String类型,或者是 再创建一个对象,不仅可以使用type指定接受类型,还可以使用default设定默认值。 这里我们希望propMessage接受一个String,但是实际上接受了一个Number,控制台报错如下:
当然,type不仅仅是String和Number,还可以是下面的几种类型:
24.
http://www.yyyweb.com/4541.html
https://cn.vuejs.org/v2/guide/