返回

Vue学习笔记|Vue基础06

class与style绑定、条件渲染、列表渲染、侦听原理

考虑一个场景:点击区域后样式style改变

绑定样式

  • class样式
    • 写法:class="xxx"xxx可以是字符串、对象、数组
      • :v-bind
    • 字符串写法适用于:类名不确定,要动态获取
    • 对象写法适用于:要绑定多个样式,个数不确定,名字也不确定
    • 数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用
  • style样式(用的不多)
    • :style="{fontSize: xxx}",其中xxx是动态值
    • :style="[a,b]",其中a、b是样式对象
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<!-- 六种样式 -->
<style>
    .basic{...}
    .happy{...}
    .sad{...}
    .normal{...}
    .atguigu1{...}
    .atguigu2{...}
    .atguigu3{...}
</style>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<!-- 准备好一个容器-->
<div id="root">
    <!-- 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定 -->
    <div class="basic" :class="mood" @click="changeMood">{{name}}</div> <br/><br/>

    <!-- 绑定class样式--数组写法,适用于:要绑定的样式个数不确定、名字也不确定 -->
    <div class="basic" :class="classArr">{{name}}</div> <br/><br/>

    <!-- 绑定class样式--对象写法,适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用 -->
    <div class="basic" :class="classObj">{{name}}</div> <br/><br/>

    <!-- 绑定style样式--对象写法 -->
    <div class="basic" :style="styleObj">{{name}}</div> <br/><br/>
    <!-- 绑定style样式--数组写法 -->
    <div class="basic" :style="styleArr">{{name}}</div>
</div>
 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
28
29
30
31
32
33
34
35
const vm = new Vue({
    el:'#root',
    data:{
        name:'wyatt',
        mood:'normal',
        classArr:['atguigu1','atguigu2','atguigu3'],
        classObj:{
            atguigu1:false,
            atguigu2:false,
        },
        styleObj:{
            fontSize: '40px',
            color:'red',
        },
        styleObj2:{
            backgroundColor:'orange'
        },
        styleArr:[
            {
                fontSize: '40px',
                color:'blue',
            },
            {
                backgroundColor:'gray'
            }
        ]
    },
    methods: {
        changeMood(){
            const arr = ['happy','sad','normal']
            const index = Math.floor(Math.random()*3)
            this.mood = arr[index]
        }
    },
})

条件渲染

  • v-if
    • 写法:
      • v-if="表达式"
      • v-else-if="表达式"
      • v-else="表达式"
    • 适用于:切换频率较低的场景
    • 特点:不展示的DOM元素直接被移除
    • 注意:v-if可以和:v-else-ifv-else一起使用,但要求结构不能被『打断』
  • v-show
    • 写法:v-show="表达式"
    • 适用于:切换频率较高的场景
    • 特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉
  • 备注:使用v-if的时,元素可能无法获取到,而使用v-show则一定可以获取到
 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
<!-- 准备好一个容器-->
<div id="root">
    <h2>当前的n值是:{{n}}</h2>
    <button @click="n++">点我n+1</button>
    <!-- 使用v-show做条件渲染 -->
    <h2 v-show="true">欢迎来到{{name}}</h2>
    <h2 v-show="1 === 1">欢迎来到{{name}}</h2>

    <!-- 使用v-if做条件渲染 -->
    <h2 v-if="t">欢迎来到{{name}}</h2>
    <h2 v-if="1 === 1">欢迎来到{{name}}</h2> 

    <!-- v-else和v-else-if -->
    <div v-if="n === 1">Angular</div>
    <div v-else-if="n === 2">React</div>
    <div v-else-if="n === 3">Vue</div>
    <div v-else>哈哈</div>

    <!-- v-if与template的配合使用 -->
    <template v-if="n === 1">
        <h2>hello</h2>
        <h2>wyatt</h2>
        <h2>xi'an</h2>
    </template>
</div>
  • 编码时用template包裹元素,等页面实际渲染时,template会被去掉
1
2
3
4
5
6
7
const vm = new Vue({
    el:'#root',
    data:{
        name:"xi'an",
        n:0
    }
})

列表渲染

  • v-for指令
    • 用于展示列表数据
    • 语法:v-for="(item, index) in xxx" :key="yyy"
    • 可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少)
 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
28
29
30
31
32
33
<div id="root">
    <!-- 遍历数组 -->
    <h2>人员列表(遍历数组)</h2>
    <ul>
        <li v-for="(p,index) of persons" :key="index">
            {{p.name}}-{{p.age}}
        </li>
    </ul>

    <!-- 遍历对象 -->
    <h2>汽车信息(遍历对象)</h2>
    <ul>
        <li v-for="(value,k) of car" :key="k">
            {{k}}-{{value}}
        </li>
    </ul>

    <!-- 遍历字符串 -->
    <h2>测试遍历字符串(用得少)</h2>
    <ul>
        <li v-for="(char,index) of str" :key="index">
            {{char}}-{{index}}
        </li>
    </ul>

    <!-- 遍历指定次数 -->
    <h2>测试遍历指定次数(用得少)</h2>
    <ul>
        <li v-for="(number,index) of 5" :key="index">
            {{index}}-{{number}}
        </li>
    </ul>
</div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
new Vue({
    el:'#root',
    data:{
        persons:[
            {id:'001',name:'张三',age:18},
            {id:'002',name:'李四',age:19},
            {id:'003',name:'王五',age:20}
        ],
        car:{
            name:'奥迪A8',
            price:'70万',
            color:'黑色'
        },
        str:'hello'
    }
})

key作用与原理

虚拟DOM中key的作用:

  • key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】
  • 随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:
    • 旧虚拟DOM中找到了与新虚拟DOM相同的key
      • 若虚拟DOM中内容没变,直接使用之前的真实DOM!
      • 若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM
    • 旧虚拟DOM中未找到与新虚拟DOM相同的key
      • 创建新的真实DOM,随后渲染到到页面
  • index作为key可能会引发的问题:
    • 若对数据进行:逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新 ==> 界面效果没问题,但效率低
    • 如果结构中还包含输入类的DOM:会产生错误DOM更新 ==> 界面有问题
  • 开发中如何选择key:
    • 最好使用每条数据的唯一标识作为key,比如id、手机号、身份证号、学号等唯一值
    • 如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的

列表过滤

  • 场景:通过用户的输入,过滤列表的显示结果,而不改变原列表的数据
  • 实现方法
    • watch
    • compute:代码更简单一些
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<!-- 准备好一个容器-->
<div id="root">
    <h2>人员列表</h2>
    <input type="text" placeholder="请输入名字" v-model="keyWord">
    <ul>
        <li v-for="(p,index) of filPerons" :key="index">
            {{p.name}}-{{p.age}}-{{p.sex}}
        </li>
    </ul>
</div>
  • v-model双向绑定,用户输入的数据可以由页面流向Vue实例
 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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//用watch实现
new Vue({
    el:'#root',
    data:{
        keyWord:'',
        persons:[
            {id:'001',name:'马冬梅',age:19,sex:'女'},
            {id:'002',name:'周冬雨',age:20,sex:'女'},
            {id:'003',name:'周杰伦',age:21,sex:'男'},
            {id:'004',name:'温兆伦',age:22,sex:'男'}
        ],
        filPerons:[]
    },
    watch:{
        keyWord:{
            immediate:true,
            handler(val){
                this.filPerons = this.persons.filter((p)=>{
                    return p.name.indexOf(val) !== -1
                })
            }
        }
    }
})
//用computed实现
new Vue({
    el:'#root',
    data:{
        keyWord:'',
        persons:[
            {id:'001',name:'马冬梅',age:19,sex:'女'},
            {id:'002',name:'周冬雨',age:20,sex:'女'},
            {id:'003',name:'周杰伦',age:21,sex:'男'},
            {id:'004',name:'温兆伦',age:22,sex:'男'}
        ]
    },
    computed:{
        filPerons(){
            return this.persons.filter((p)=>{
                return p.name.indexOf(this.keyWord) !== -1
            })
        }
    }
}) 
  • computed实现中,filPersons需要返回值,返回给页面调用处,即第一个retrun;第二个returnfilter方法的返回值
  • watch实现中,handlerval是用户新输入的数据,首次打开页面时,用户无输入,则val"",而indexOf方法中索引""的结果为0,故首次打开页面时,filPersons中有所有Persons的数据,显示在页面上

JavaScript Array filter() 方法

JavaScript indexOf() 方法

列表排序

  • 场景:在列表过滤后,点击按钮可以对过滤后显示的数据按某种规则进行排序
  • 实现方法:computed比较方便
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<!-- 准备好一个容器-->
<div id="root">
    <h2>人员列表</h2>
    <input type="text" placeholder="请输入名字" v-model="keyWord">
    <button @click="sortType = 2">年龄升序</button>
    <button @click="sortType = 1">年龄降序</button>
    <button @click="sortType = 0">原顺序</button>
    <ul>
        <li v-for="(p,index) of filPerons" :key="p.id">
            {{p.name}}-{{p.age}}-{{p.sex}}
        </li>
    </ul>
</div>
 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
new Vue({
    el:'#root',
    data:{
        keyWord:'',
        sortType:0, //0原顺序 1降序 2升序
        persons:[
            {id:'001',name:'马冬梅',age:30,sex:'女'},
            {id:'002',name:'周冬雨',age:31,sex:'女'},
            {id:'003',name:'周杰伦',age:18,sex:'男'},
            {id:'004',name:'温兆伦',age:19,sex:'男'}
        ]
    },
    computed:{
        filPerons(){
            const arr = this.persons.filter((p)=>{
                return p.name.indexOf(this.keyWord) !== -1
            })
            //判断一下是否需要排序
            if(this.sortType){
                arr.sort((p1,p2)=>{
                    return this.sortType === 1 ? p2.age-p1.age : p1.age-p2.age
                })
            }
            return arr
        }
    }
})
  • 计算属性filePersons的返回值是arr,是过滤且排序后的数组
  • js中sort方法的参数是函数,该函数有两个参数,1-2是升序,2-1是降序,sort改变原数组的数据

JavaScript sort() 方法

侦听数据的原理

  • vue会侦听data中所有层次的数据
  • 如何侦听对象中的数据
    • 通过setter实现侦听,且要在new Vue时就传入要侦听的数据
    • 对象中后追加的属性,Vue默认不做响应式处理
    • 如需给后添加的属性做响应式,请使用如下API:
      • Vue.set(target,propertyName/index,value)
      • vm.$set(target,propertyName/index,value)

响应式:数据改变后,页面跟着改变

  • 如何侦听数组中的数据
    • 通过包裹数组更新元素的方法实现,本质就是做了两件事:
      • 调用原生对应的方法对数组进行更新
      • 重新解析模板,进而更新页面。
  • 在Vue修改数组中的某个元素一定要用如下方法:
    • 使用这些API:push()pop()shift()unshift()splice()sort()reverse()
    • Vue.set()vm.$set()
  • 特别注意:Vue.set()vm.$set()不能给vmvm根数据对象添加属性
 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
<!-- 准备好一个容器-->
<div id="root">
    <h1>学生信息</h1>
    <button @click="student.age++">年龄+1岁</button> <br/>
    <button @click="addSex">添加性别属性,默认值:男</button> <br/>
    <button @click="student.sex = '未知' ">修改性别</button> <br/>
    <button @click="addFriend">在列表首位添加一个朋友</button> <br/>
    <button @click="updateFirstFriendName">修改第一个朋友的名字为:张三</button> <br/>
    <button @click="addHobby">添加一个爱好</button> <br/>
    <button @click="updateHobby">修改第一个爱好为:开车</button> <br/>
    <button @click="removeSmoke">过滤掉爱好中的抽烟</button> <br/>
    <h3>姓名:{{student.name}}</h3>
    <h3>年龄:{{student.age}}</h3>
    <h3 v-if="student.sex">性别:{{student.sex}}</h3>
    <h3>爱好:</h3>
    <ul>
        <li v-for="(h,index) in student.hobby" :key="index">
            {{h}}
        </li>
    </ul>
    <h3>朋友们:</h3>
    <ul>
        <li v-for="(f,index) in student.friends" :key="index">
            {{f.name}}--{{f.age}}
        </li>
    </ul>
</div>
 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
28
29
30
31
32
33
34
35
36
37
38
39
const vm = new Vue({
    el:'#root',
    data:{
        student:{
            name:'tom',
            age:18,
            hobby:['抽烟','喝酒','烫头'],
            friends:[
                {name:'jerry',age:35},
                {name:'tony',age:36}
            ]
        }
    },
    methods: {
        addSex(){
            // Vue.set(this.student,'sex','男')
            this.$set(this.student,'sex','男')
        },
        addFriend(){
            this.student.friends.unshift({name:'jack',age:70})
        },
        updateFirstFriendName(){
            this.student.friends[0].name = '张三'
        },
        addHobby(){
            this.student.hobby.push('学习')
        },
        updateHobby(){
            // this.student.hobby.splice(0,1,'开车')
            // Vue.set(this.student.hobby,0,'开车')
            this.$set(this.student.hobby,0,'开车')
        },
        removeSmoke(){
            this.student.hobby = this.student.hobby.filter((h)=>{
                return h !== '抽烟'
            })
        }
    }
})

最后更新于 Oct 02, 2022 21:16 UTC
Built with Hugo
Theme Stack designed by Jimmy