跳至主要內容

03:模板语法(下)

三思原创大约 10 分钟前端vue前端vuejs

本文介绍了在Vue中使用条件判断和循环遍历的方法,包括v-if、v-else-if、v-else、v-show、v-for遍历数组和对象,以及组件的key属性的应用。通过实例和案例展示了各种情况下的效果和注意事项。

image
image

Vue自学笔记3:模板语法(下)

本文章为观看B站codewhy老师教学视频自学vuejs过程中记录的笔记,对视频进行了清晰的整理。

ps:最全最新Vue、Vuejs教程,从入门到精通_哔哩哔哩_bilibiliopen in new window(附上视频链接!)

5. 条件判断

5.1 v-if、v-else-if、v-else

总结: 该案例使用v-if这些标签并不合适, 使用计算属性( computed )更好

5.2 条件渲染案例

代码:

 <body>
     <div id="app">
         <span>{{type}}:</span>
         <input type="text" :value="type">
         <button @click="change">切换类型</button>
     </div>
     <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.min.js"></script>
     <script>
         const app = new Vue({
             el: '#app',
             data: {
                 type: '用户账号'
             },
             methods: {
                 change() {
                     if (this.type === '用户账号') {
                         this.type = '邮箱地址'
                     }
                     else {
                         this.type = '用户账号'
                     }
                 }
             }
         })
     </script>
 </body>

5.3 v-show

6. 循环遍历

6.1 v-for遍历数组

6.2 v-for遍历对象

效果:

6.3 组件的key属性

在用v-for更新已渲染的元素列表的时候,会使用就地复用的策略;这就是说列表数据修改的时候,他会根据key值去判断某个值是否修改,如果修改了就重新渲染,不然就复用之前的元素。总结一下,就是通过key值来提升渲染的效率

例子:

 const list = [
     {
         id:1,
         name:'test'
     },
     {
         id:2,
         name:'test2',
     },
     {
         id:3,
         name:'test3'
     },
 ]
 <div v-for="(item,index) in list :key="index">{{item.name}}</div>

这个场景在我们开发的时候经常会碰到,因为不加key,vue现在会直接报错,所以我使用index作为key; 下面再举两个例子来看数据更新后的情况。

1.在最后一条数据后再加一条数据

 const list = [
     {
         id: 1,
         name: 'test1',
     },
     {
         id: 2,
         name: 'test2',
     },
     {
         id: 3,
         name: 'test3',
     },
     {
         id: 4,
         name: '我是在最后添加的一条数据',
     },
 ]

此时前三条数据直接复用之前的,新渲染最后一条数据,此时用index​作为key​,没有任何问题;

2.在中间插入一条数据

 const list = [
     {
         id: 1,
         name: 'test1',
     },
     {
         id: 4,
         name: '我是插队的一条数据',
     }
     {
         id: 2,
         name: 'test2',
     },
     {
         id: 3,
         name: 'test3',
     },
 ]

此时更新渲染数据,通过index​定义的key​去进行前后数据的对比,发现

 之前的数据                         之后的数据
 key: 0  index: 0 name: test1     key: 0  index: 0 name: test1
 key: 1  index: 1 name: test2     key: 1  index: 1 name: 我是插队的一条数据
 key: 2  index: 2 name: test3     key: 2  index: 2 name: test2
                                  key: 3  index: 3 name: test3

可以发现除了第一条数据可以复用以外,另外三条数据都需要重新渲染,因为key值发生了变化; 这时候就可以体现出了一个效率问题,只插入了一条数据,却要重新渲染三条数据;

所以我们需要可以想办法让数组中不会变化的数据的key值也不变,所以不能通过index来设置key值,应该设置一个唯一的id来标识数据的唯一性;我们修改之后再来对比一下渲染的效率:

 之前的数据                              之后的数据
 key: 1  id: 1 index: 0 name: test1     key: 1  id: 1 index: 0  name: test1
 key: 2  id: 2 index: 1 name: test2     key: 4  id: 4 index: 1  name: 我是插队的那条数据
 key: 3  id: 3 index: 2 name: test3     key: 2  id: 2 index: 2  name: test
                                        key: 3  id: 3 index: 3  name: test3

总结: 对比可以发现,只有一条数据发生了变化,因为其他数据的id都没变,所以key值也没变,所以只需要渲染这一条新的数据即可 所以一般推荐使用id作为key值来配合v-for使用

下面大致从虚拟DOM的Diff算法实现的角度去解释一下:

vue和react的虚拟DOM的Diff算法大致相同,其核心是基于两个简单的假设:

  1. 两个相同的组件产生类似的DOM结构,不同的组件产生不同的DOM结构。
  2. 同一层级的一组节点,他们可以通过唯一的id进行区分。基于这两点假设,使得虚拟DOM的Diff算法的复杂度从O(n^3)降到了O(n)

引用React’s diff algorithmopen in new window中的例子:

当某一层有很多相同的节点时,也就是列表节点时,Diff算法的更新过程默认情况下也是遵循以上原则。 比如一下这个情况:

我们希望可以在B和C之间加一个F,Diff算法默认执行起来是这样的:

即把C更新成F,D更新成C,E更新成D,最后再插入E,很没有效率

所以我们需要使用key来给每个节点做一个唯一标识符,Diff算法就可以正确的识别此节点,找到正确的位置区插入新的节点。

所以用一句话来概括,key的作用主要是为了高效的更新虚拟DOM。

6.4 检测数组更新

通过索引值修改数组中的元素​是无法做到响应式的,既视图不会实时更新

 <body>
     <div id="app">
         <ul>
             <li v-for="v in letters">{{v}}</li>
         </ul>
         <button @click="btnlick">按钮</button>
     </div>
     <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.min.js"></script>
     <script>
         const app = new Vue({
             el: '#app',
             data: {
                 letters: ['a', 'b', 'c', 'd']
             },
             methods: {
                 btnclick() {
                     //push()尾部插入
                     this.letters.push('abc')
                 
                     //pop()尾部删除
                     this.letters.pop()
                 
                     //unshift()头部插入
                     this.letters.unshift('abc')
                 
                     //shift()头部删除
                     this.letters.shift()
                 
                     //splice():删除元素/插入元素/替换元素
                     // 删除元素:splice(start,num)  start是开始删除的第一个位置,num是删除的元素数量(num不写则默                                                                                      认删除start后所有元素)
                     // 替换元素:splice(start,num,'a','b') start是开始替换的第一个位置,num是插入的元素数量,后面                                                                                          跟num个替换的元素
                     // 插入元素:splice(start,0,'a','b') start是开始插入的第一个位置,第二个参数置0,后面跟待插入                                                                                                     的元素
                     this.letters.splice(2)
 
                     //sort()数组排序
                     this.letters.sort()
 
                     //reverse()数组反转
                     this.letters.reverse()
                 }
             }
         })
     </script>
 </body>

7.(补充) 高阶函数

forEach 是 ES5 中操作数组的一种方法,主要功能是遍历数组,该语句需要一个回调函数,作为参数。回调函数的形参,依次为,value:遍历的数组内容;index:对应的数组索引,array:数组本身。

 <script type="text/javascript">
     // 分别对应:数组元素,元素的索引,数组本身
     var arr = ['a','b','c'];  
     arr.forEach(function(value,index,array){
         console.log(value);
         console.log(index);
         console.log(array);
         })
 </script>

8. v-model

8.1 v-model原理

8.2 v-model:radio(单选)

单选框:

 <body>
     <div id="app">
         <input type="radio" value="" v-model="sex"><input type="radio" value="" v-model="sex"> 女
         //使用v-model就不需要都取一个name了
         <br>
         {{sex}}
     </div>
     <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.min.js"></script>
     <script>
         var vm = new Vue({
             el: "#app",
             data: {
                 message: '你好啊',
                 sex:'男' //sex赋初值为男,可以实现单选框默认选择男
             }
         })
     </script>
 </body>

8.3 v-model:checkbox(复选)

单个勾选框: v-model即为布尔值。 此时input的value并不影响v-model的值。 多个复选框: 当是多个复选框时,因为可以选中多个,所以对应的data中属性是一个数组。 当选中某一个时,就会将input的value添加到数组中。

 <body>
     <div id="app">
         <!-- 单个复选框 -->
         <label for="">
             <input type="checkbox" v-model="isagree">同意协议
         </label>
         <h2>
             isagree是:{{isagree}}
         </h2>
 
 
         <!-- 多个复选框 -->
         <input type="checkbox" v-model="hobbies" value="篮球" id="aa"> <label for="aa">篮球</label>
         <input type="checkbox" v-model="hobbies" value="足球" id="bb"> <label for="bb">足球</label>
         <input type="checkbox" v-model="hobbies" value="橄榄球" id="cc"> <label for="cc">橄榄球</label>
         <input type="checkbox" v-model="hobbies" value="棒球" id="dd"> <label for="dd">棒球</label>
         <h2>
             你选择了:{{hobbies}}
         </h2>
     </div>
     <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.min.js"></script>
     <script>
         var vm = new Vue({
             el: "#app",
             data: {
                 isagree: false,   //默认为不同意
                 hobbies: ["足球"]  //默认选了足球
             }
         })
     </script>
 </body>

8.4 v-model:select

和checkbox一样,select也分单选和多选两种情况。 单选:只能选中一个值。 v-model绑定的是一个值。 当我们选中option中的一个时,会将它对应的value赋值到mySelect中 多选:可以选中多个值。 v-model绑定的是一个数组。 当选中多个值时,就会将选中的option对应的value添加到数组mySelects中

 <body>
     <div id="app">
         <!-- 选择一个 -->
         <select name="selectFruit" id="" v-model="fruit">
             <option value="苹果">苹果</option>
             <option value="香蕉">香蕉</option>
             <option value="榴莲">榴莲</option>
             <option value="葡萄">葡萄</option>
         </select>
         <h2>你选择的水果是:{{fruit}}</h2>
 
         <!-- 选择多个 -->
         <select name="selectFruits" id="" v-model="fruits" multiple>
             <option value="苹果">苹果</option>
             <option value="香蕉">香蕉</option>
             <option value="榴莲">榴莲</option>
             <option value="葡萄">葡萄</option>
         </select>
         <h2>你选择的水果有:{{fruits}}</h2>
     </div>
     <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.min.js"></script>
     <script>
         var vm = new Vue({
             el: "#app",
             data: {
                 fruit: '香蕉',//默认选择香蕉
                 fruits: []
             }
         })
     </script>
 </body>

效果:

8.5 值绑定

 <body>
     <div id="app">
         <!-- 多个复选框 -->
         <input type="checkbox" v-model="hobbies" value="篮球" id="aa"><label for="aa">篮球</label>
 
         <input type="checkbox" v-model="hobbies" value="足球" id="bb"><label for="bb">足球</label>
 
         <input type="checkbox" v-model="hobbies" value="橄榄球" id="cc"><label for="cc">橄榄球</label>
 
         <input type="checkbox" v-model="hobbies" value="棒球" id="dd"><label for="dd">棒球</label>
 
         <h2>
             你选择了:{{hobbies}}
         </h2>
 
 
         <!-- 值绑定 -->
         <label v-for="item in hobbies111" :for="item">
             <input type="checkbox" :value="item" :id="item" v-model="hobbies">{{item}}
         </label>
         <!--:id="item" :value:"item"就是值绑定-->
     </div>
   
     <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.min.js"></script>
     <script>
         var vm = new Vue({
             el: "#app",
             data: {
                 hobbies: ["足球"],  //默认选了足球
                 hobbies111: ['篮球', '足球', '橄榄球', '棒球']
             }
         })
     </script>
 </body

效果:

8.6 修饰符

 <body>
     <div id="app">
         <!-- 未使用lazy修饰符:实时绑定 -->
         <input type="text" v-model="message">
         <!-- 使用lazy修饰符:失去焦点,按下回车时绑定 -->
         <input type="text" v-model.lazy="message">
         <h2>{{message}}</h2>
 
 
         <!-- input标签里输入的是number类型,但是其实age是一个string类型 -->
         <input type="number" v-model="age">
         <!-- 当希望age在后面使用时是nuber类型时 -->
         <input type="number" v-model.number="age">
         <h2>{{typeof(age)}}</h2>
 
         <!-- 去除两端的空格 -->
         <input type="text" v-model.trim="name">
         <h2>{{name}}</h2>
     </div>
 
     <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.min.js"></script>
     <script>
         var vm = new Vue({
             el: "#app",
             data: {
                 message: 'hello,world',
                 age: '',
                 naem:''
             }
         })
     </script>
 </body>