目录
上篇内容回顾:
数据绑定
表单输入框绑定
单行文本输入框
多行文本输入框
复选框 checkbox
单选框 radio
选择框 select
数据绑定的修饰符
- .lazy
- .number
- .trim
样式绑定
class 绑定
对象语法:
数组语法:
style 绑定
对象语法:
数组语法:
补充:
事件
绑定事件
事件修饰符
按键修饰符
事件绑定的简写
补充:
vue 指令
数组操作
官网的话
补充:
Vue 的元素复用问题
数据残留问题
问题的解决:
首发日期: 2019-01-20
上篇内容回顾:
上篇内容讲了
Vue 的介绍: 优点, MVVM
Vue 的静态导入与安装, 以及 hello world
实例可定义的内容: el,data,methods, 生命周期钩子(包括计算属性, 侦听器也是可以定义在实例中的)
计算属性
侦听器
数据绑定
v-model 可以把某个实例的数据与元素的数据绑定. 这样当其中一份数据发生变化时, 与之绑定的数据也会发生变化. 比如: 把示例中的数据 (在页面中用{{}} 显示出来)与输入框的数据绑定
表单输入框有 value 这个值, 在表单输入框里使用 v-model 会把表单输入框与实例的数据进行 "智能" 绑定(为什么说智能, 因为有些输入框的数据是 value 属性, 有些不是).
表单输入框绑定
你可以用 v-model 指令在表单 <input>,<textarea> 及 < select> 元素上创建双向数据绑定. 它会根据控件类型自动选取正确的方法来更新元素. 尽管有些神奇, 但 v-model 本质上不过是语法糖. 它负责监听用户的输入事件以更新数据, 并对一些极端场景进行一些特殊处理.
v-model 会忽略所有表单元素的 value,checked,selected 特性的初始值而总是将 Vue 实例的数据作为数据来源. 如果希望输入框有初始值, 你应该在组件的 data 选项中声明初始值.
单行文本输入框
会把单行文本输入框的 value 绑定到实例的数据中, 因为 value 的数据就是单行文本输入框的数据.
- <body>
- <div id="vm">
- <input v-model="message" placeholder="edit me">
- <p>Message is: {{ message }}</p>
- <input type="text" v-bind:value="message">
- <!-- 不能使用普通的 value=message, 不然会识别不成正确的 message, 所以第三行用了 v-bind -->
- </div>
- </body>
- <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
- <script>
- var vm = new Vue({
- el: '#vm',
- data:{
- message:"hello world!"
- }
- })
- </script>
多行文本输入框
会把多行文本元素内的文本绑定到实例的数据中, 因为多行文本元素内的文本就是单行文本输入框的数据.
- <body>
- <div id="vm">
- <span>Multiline message is:</span>
- <p style="white-space: pre-line;">{{ message }}</p>
- <br>
- <textarea v-model="message" placeholder="add multiple lines"></textarea>
- </div>
- </body>
- <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
- <script>
- var vm = new Vue({
- el: '#vm',
- data:{
- message:"hello world!"
- }
- })
- </script>
在文本区域 < textarea></textarea > 使用插值表达式 {{}} 来插值并不会生效, 应该用 v-model 来代替.
复选框 checkbox
单个复选框: 复选框也有 value, 不给定 value 值的时候 value 默认是布尔值(被勾选是 true, 没有勾选是 false)
- <body>
- <div id="vm">
- <input type="checkbox" id="checkbox" v-model="checked">
- <label for="checkbox">{{ checked }}</label>
- </div>
- </body>
- <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
- <script>
- var vm = new Vue({
- el: '#vm',
- data:{
- checked:false
- }
- })
- </script>
多个复选框: 指定了 value 之后, 实例绑定的数据是对应的 value 值[由于是多个复选框绑定到同一个实例上, 所以这个实例数据应该是数组类型的.]
- <body>
- <div id='example-3'>
- <input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
- <label for="jack">Jack</label>
- <input type="checkbox" id="john" value="John" v-model="checkedNames">
- <label for="john">John</label>
- <input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
- <label for="mike">Mike</label>
- <br>
- <span>Checked names: {{ checkedNames }}</span>
- </div>
- </body>
- <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
- <script>
- var vm = new Vue({
- el: '#example-3',
- data:{
- checkedNames:[] // 值为多个 input 的 value 的数组
- }
- })
- </script>
单选框 radio
radio 也有 value, 所以与实例绑定的数据就是 value 的值
- <body>
- <div id="example-4">
- <input type="radio" id="one" value="One" v-model="picked">
- <label for="one">One</label>
- <br>
- <input type="radio" id="two" value="Two" v-model="picked">
- <label for="two">Two</label>
- <br>
- <span>Picked: {{ picked }}</span>
- </div>
- </body>
- <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
- <script>
- var vm = new Vue({
- el: '#example-4',
- data: {
- picked: ''// picked 的值为 input 的 value 值
- }
- })
- </script>
选择框 select
select 的值来源与子标签 option. 当 select 的 option 没有 value 值的时候, 默认绑定的数据为 option 元素的文本值; 当有 value 时, 默认绑定的数据为 option 元素的 value 值.
<body> <div id="example-5"> <select v-model="selected"> <option disabled value="">请选择</option> <option value ='a'>A</option> <!-- 这个用来测试有 value 的情况 --> <option>B</option> <option>C</option> </select> <span>Selected: {{ selected }}</span> </div> </body> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> var vm = new Vue({ el: '#example-5', data: { selected: "" // selected 的值为 a/B/C } }) </script>
select 框允许多选时: 那么这时候实例的数据应该是一个数组, 数组元素是 option 的文本值 (无 value 时) 或 value
<body> <div id="example-5"> <select multiple style="width: 50px;" v-model="selected"> <option disabled value="">请选择</option> <option value='a'>A</option> <option>B</option> <option>C</option> </select> <span>Selected: {{ selected }}</span> </div> </body> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> var vm = new Vue({ el: '#example-5', data: { selected: [] // 全选时: [ "a", "B", "C" ] } }) </script>
数据绑定的修饰符
.lazy
在默认情况下, v-model 在每次 input 事件触发后将输入框的值与数据进行同步 (除了输入法组合文字时, 这时候数据还没完全输入到输入框中).
你可以添加 lazy 修饰符, 从而转变为使用 change 事件进行同步:
<!-- 在 "change" 时而非 "input" 时更新 --> <input v-model.lazy="msg"> .number
如果想自动将用户的输入值转为数值类型, 可以给 v-model 添加 number 修饰符:
<input v-model.number="age" type="number">
这通常很有用, 因为即使在 type="number" 时, html 输入元素的值也总会返回字符串. 如果这个值无法被 parseFloat() 解析, 则会返回原始的值.
.trim
如果要自动过滤用户输入的首尾空白字符, 可以给 v-model 添加 trim 修饰符:
<input v-model.trim="msg">
样式绑定
我们平时也可以使用 class='xxx'或 style='xxx:xxxx'来绑定样式. 为什么要选择转去使用 Vue 的样式绑定? 因为在 Vue 中 class 或 style 也可以定义成数据, 你可能会想要 "发生 XXX 情况后, 某元素变成某样式", 这个时候你需要定义 "行为" 来切换样式了, 而这时候如果你使用 Vue 自己的样式切换会比较方便(因为首先你要获取某个元素的 class 属性, 然后再重新赋值, 这个操作可能需要自己定义一些 dom 操作).
class 绑定
使用 v-bind:class 来进行 class 绑定
对象语法:
格式一: 传入的数据格式是{ class 名: 布尔数据,.... }, 布尔数据影响 class 是否出现在元素的 class 属性中.
<div id="app"> <div v-bind:class="{ active: isActive }">haha</div> </div> <!-- var app = new Vue({ el: '#app', data: { isActive: true // 影响着 active 这个 class 是否出现 }, }) --> <!-- <style> .active { color: red; } </style> -->
格式一: 传入的数据格式是对象名, 对象的数据格式是{ class 名: 布尔数据,.... }, 布尔值影响 class 是否出现在元素的 class 属性中.
<div id="app"> <div v-bind:class="classObject">haha</div> </div> <!-- var app = new Vue({ el: '#app', data: { classObject: { active: true } }, }) --> <!-- <style> .active { color: red; } </style> -->
数组语法:
格式一:
<div id="app"> <div v-bind:class="[activeClass]">haha</div> </div> <!-- var app = new Vue({ el: '#app', data: { activeClass:'active' }, }) --> <!-- <style> .active { color: red; } </style> -->
style 绑定
使用 v-bind:style 来进行 style 绑定
对象语法:
格式一: 传入的数据格式是{ 样式名: 实例数据名(样式值), .... }
<div id="app"> <div v-bind:style="{ color: activeColor, fontSize: fontSize +'px'}">haha</div> </div> <!-- var app = new Vue({ el: '#app', data: { activeColor:'red', fontSize: 14 }, }) -->
格式二: 传入的数据是一个对象, 对象的数据格式是{ 样式名: 样式值, .... }
<div id="app"> <div v-bind:style="styleObject">haha</div> </div> <!-- var app = new Vue({ el: '#app', data: { styleObject: { color:'red', fontSize: "14px" } }, }) -->
数组语法:
传入的数据是一个数组, 数组的元素是多个对象, 对象的数据格式是{ 样式名: 样式值, .... }
<div id="app"> <div v-bind:style="[styleObject]">haha</div> </div> <!-- var app = new Vue({ el: '#app', data: { styleObject: { color:'red', fontSize: "14px" } }, }) -->
补充:
当 v-bind:style 使用需要添加浏览器引擎前缀的 CSS 属性时, 如 transform,Vue.JS 会自动侦测并添加相应的前缀.
事件
绑定事件
可以使用 v-on: 事件类型 ='函数名'来绑定事件.
<div id="app"> <button v-on:click="myclick">点击事件</button> <!-- on: 后面跟事件类型 --> </div> <!-- var app = new Vue({ el: '#app', methods: { // 注意: 是在 methods 里面定义函数 myclick:function (){ alert("message") } } }) -->
事件修饰符
事件修饰符可以影响事件的运行, 事件修饰符使用. 跟在事件类型的后面, 例如:<a v-on:click.stop="doThis"></a>.
.prevent 修饰符告诉 v-on 指令对于触发的事件, 调用 event.preventDefault()来阻止默认的元素行为, 例如默认点击 a 元素时会进行页面跳转, 如果我们给事件加了 prevent 修饰符, 那么对应的 a 元素就不会进行网页跳转了
v-on:click.prevent='myFunction' .
.stop 修饰符告诉 v-on 指令对于触发的事件, 阻止这个事件的冒泡(冒泡代表这个触发的事件也会传递给父元素这些祖宗元素)
.once 修饰符告诉 v-on 指令对于触发的事件只会触发一次.
还有好几个事件修饰符, 有兴趣的可以自查. 这个还是相对少用的.
<body> <div id="app"> <a v-on:click.prevent='myFunction' href='#'>aaa</a> <!-- 默认情况下, 点击 a 元素会进行跳转, 上面用 #来演示, 如果 url 多了一个 #说明 a 的原生事件触发了, 而我们现在用 prevent 来阻止了 a 元素原始的事件 --> </div> </body> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> var vm = new Vue({ el: '#app', methods: { myFunction: function () { alert('haha') } } }) </script>
按键修饰符
你可能需要监听键盘来触发事件, 比如最常用的就是监听 enter 键了.
按键修饰符也使用. 跟在事件类型的后面 , 例如:<input v-on:keyup.enter="submit">
.enter 代表 enter 键修饰符
.up .down .left .right 代表四个方向键的修饰符.
[上面给出了常见的 "按键修饰符别名", 是别名, 真实的值可能是一个数字]
[这里对于按键修饰符就不说那么多了, 需要用再查吧.]
事件绑定的简写
<!-- 完整语法 --> <a v-on:click="doSomething"> ... </a> <!-- 缩写 --> <a @click="doSomething"> ... </a>
补充:
还可以自定义事件[不过目前我做的一些前端项目好像都没怎么涉及, 有兴趣的可以自查]
Vue 指令
Vue 的指令是以 v - 开头的, 它们各有各的左右, 在前面已经介绍了不少了. 现在再汇总一下.
v-text: 向元素中输出文本
v-HTML: 向元素中输入 HTML 文本
v-if: 根据条件来判断是否渲染元素(同类的 v-else,v-else-if)
v-show: 根据条件来判断是否显示元素
v-for: 循环渲染元素
v-bind: 为元素绑定属性
v-model: 进行数据的双向绑定
v-on: 为元素绑定事件
v-once 用来声明元素只渲染一次.
数组操作
为什么要特意地说一下数组的操作呢? 因为数组是非常常用的数据类型, 而在 Vue 中有些数组操作并不会触发视图更新. 为了确保数据是 "响应式" 的, 所以特意讲一下这个.
下面的代码演示了使用普通数组操作方法时 "响应失败" 的情况:
<body> <div id="app"> <p>{{ myArray}}</p> <button @click='addValue1'>下标法添加</button> <button @click='addValue2'>push 法</button> <!-- 如果你点了第一个, 再点第二个, 第一个的添加会在第二个的时候再成功显示 --> </div> </body> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> var vm = new Vue({ el: '#app', data: { myArray: [1,2,3] }, methods: { addValue1: function(){ this.myArray[1]=333 }, addValue2: function(){ this.myArray.push('999999') } } }) </script>
下面这些对数组操作的方法将会触发视图更新.
push(): 向数组末尾添加元素
pop(): 从数组末尾取出一个元素
shift(): 数组的第一个元素从其中删除, 并返回第一个元素的值
unshift(): 向数组的开头添加一个或更多元素, 并返回新的长度
splice(): 从数组中添加 / 删除项目, 然后返回被删除的项目
sort(): 对数组的元素进行排序
reverse(): 对数组的元素进行逆序排序
官网的话
[官网的话] 由于 JavaScript 的限制, Vue 不能检测以下变动的数组:
当你利用索引直接设置一个项时, 例如:
vm.items[indexOfItem] = newValue
当你修改数组的长度时, 例如:
vm.items.length = newLength
为了解决第一类问题, 以下两种方式都可以实现和 vm.items[indexOfItem] = newValue 相同的效果, 同时也将触发状态更新:
Vue.set(vm.items, indexOfItem, newValue)或 vm.items.splice(indexOfItem, 1, newValue)或 vm.$set(vm.items, indexOfItem, newValue)
为了解决第二类问题, 你可以使用 splice:vm.items.splice(newLength)
补充:
还是由于 JavaScript 的限制, Vue 不能检测对象属性的添加或删除:
var vm = new Vue({ data: { a: 1 } }) // `vm.a` 现在修改 a 是响应式的 vm.b = 2 // `vm.b` 不是响应式的
有时, 我们想要显示一个数组的过滤或排序副本, 而不实际改变或重置原始数据(不改变原来的数据, 代表创建一个副本, 而 sort 会影响源数组, 所以我们需要新的数组来存储). 在这种情况下, 可以创建返回过滤或排序数组的计算属性.[如果你处理数组有多种情况, 你可以使用一个 method 方法, 用传参来定义如何处理数组]
<body> <div id="app"> <p>{{ numbers }}</p> <ul> <li v-for="n in evenNumbers">{{ n }}</li> </ul> </div> </body> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> var vm = new Vue({ el: '#app', data: { numbers: [ 1, 2, 3, 4, 5 ] }, computed: { evenNumbers: function () { return this.numbers.filter(function (number) { return number % 2 === 0 }) } } }) </script>
Vue 的元素复用问题
Vue 会尽可能高效地渲染元素, 通常会复用已有元素而不是从头开始渲染. 这么做除了使 Vue 变得非常快之外, 还有其它一些好处.
数据残留问题
而因为复用问题, 所以可能会导致以下问题. 由于输入框被复用, 所以输入框的数据残留了下来.
<template v-if="loginType ==='username'"> <label>Username</label> <input placeholder="Enter your username"> </template> <template v-else> <label>Email</label> <input placeholder="Enter your email address"> </template>
问题的解决:
Vue 为你提供了一种方式来表达 "这两个元素是完全独立的, 不要复用它们". 只需添加一个具有唯一值的 key 属性即可(没有 key 的 label 仍然被复用了):
<template v-if="loginType ==='username'"> <label>Username</label> <input placeholder="Enter your username" key="username-input"> </template> <template v-else> <label>Email</label> <input placeholder="Enter your email address" key="email-input"> </template>
当 Vue.JS 用 v-for 正在更新已渲染过的元素列表时, 它默认用 "就地复用" 策略. 如果数据项的顺序被改变, Vue 将不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素, 并且确保它在特定索引下显示已被渲染过的每个元素.
这个默认的模式是高效的, 但是只适用于不依赖子组件状态或临时 DOM 状态 (例如: 表单输入值) 的列表渲染输出.
为了给 Vue 一个提示, 以便它能跟踪每个节点的身份, 从而重用和重新排序现有元素, 你需要为每项提供一个唯一 key 属性. 理想的 key 值是每项都有的唯一 id. 这个特殊的属性相当于 Vue 1.x 的 track-by , 但它的工作方式类似于一个属性, 所以你需要用 v-bind 来绑定动态值 (在这里使用简写):
<div v-for="item in items" :key="item.id"> <!-- 内容 --> </div>
建议尽可能在使用 v-for 时提供 key, 除非遍历输出的 DOM 内容非常简单, 或者是刻意依赖默认行为以获取性能上的提升, 因为它是 Vue 识别节点的一个通用机制.
后端开发者的 Vue 学习之路(二)
来源: http://www.bubuko.com/infodetail-2927273.html