Vue2学习笔记(尚硅谷张天禹老师)Day-02

8、class与style绑定

8.1、理解

(1)在应用界面中,某个(些)元素的样式是变化的 (2)class/style绑定就是专门用来实现动态样式效果的技术

8.2、绑定class

(1)绑定class样式–字符串写法,适用于:样式的类名不确定,需要动态指定 (2)绑定class样式–数组写法,适用于:要绑定的样式个数不确定、名字也不确定 (3)绑定class样式–对象写法,适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用

例如:

 
<style>
         .basic {
             width: 300px;
             height: 60px;
             margin: 10px;
             border: 1px solid black;
         }
         .happy {
             background-color: pink;
             border: 1px solid black;
         } 
         .sad {
             background-color: rgb(70, 67, 68);
             border: 1px solid black;
         }
         .wu {
             background-color: rgb(236, 3, 42);
             border: 1px solid black;
         }
         .at1 {
             background-color: green;
             border: 4px solid black;
         }
         .at2 {
             background-color: green;
             border: 4px dashed black;
         }
         .at3 {
             background-color: green;
             border: 4px solid blue;
         }
     </style>
 ​
 <div id="root">
     <!-- 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定 -->
     <div class="basic" :class="classStr">{{name}}</div>
     <!-- 绑定class样式--数组写法,适用于:要绑定的样式个数不确定、名字也不确定 -->
     <div class="basic" :class="classArr">{{name}}</div>
     <!-- 绑定class样式--对象写法,适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用 -->
     <div class="basic" :class="classObj">{{name}}</div>
 </div>
 Vue.config.productionTip = false; //设置为 false 以阻止 vue 在启动时生成生产提示。
         const vm = new Vue({
             el: "#root",
             data: {
                 name: "test",
                 classStr: "happy",
                 classArr: ['at1', 'at2', 'at3'],
                 classObj: {
                     at1: true,
                     at2: false
                 }
             }
         })
 

8.3、style绑定

(1)绑定style样式–对象写法 ,属性名改为小驼峰命名 (2)绑定style样式–数组写法(不常用),数组其中是对象 例如:

 
<style>
     .basic {
         width: 300px;
         height: 60px;
         margin: 10px;
         border: 1px solid black;
     }
 </style>
 <div id="root">
     <!-- 绑定style样式--对象写法 -->
     <div class="basic" :style="styleObj">{{name}}</div>
     <!-- 绑定style样式--数组写法(不常用) -->
     <div class="basic" :style="styleArr">{{name}}</div>
 </div>
 const vm = new Vue({
         el: "#root",
         data: {
             name: "test",
             styleObj: {
                 fontSize: '40px',
                 color: "red",
                 backgroudColor: "yellow"
             },
             styleArr: [{
                     fontSize: '40px',
                     color: "red"
                 }, {
                     backgroudColor: "yellow"
                 }
 ​
             ]
         }
     })

9、条件渲染

9.1、v-if

写法:

  • v-if=“表达式”

  • v-else-if=“表达式”

  • v-else 适用于:切换频率较低的场景 特点:不展示的DOM元素直接被删除 注意:v-if可以和v-else-if、v-else一起使用,但要求结构不能被打断

 
<!DOCTYPE html>
 <html>
     <head>
         <meta charset="UTF-8" />
         <title>条件渲染</title>
         <script type="text/javascript" src="../js/vue.js"></script>
     </head>
     <body>
         <div id="root">
             <h2>当前的n值是:{{n}}</h2>
             <button @click="n++">点我n+1</button>
             
         <h2 v-show="true">Hello,{{name}}!</h2>
 ​
         <div v-if="n === 1">Angular</div>
         <div v-else-if="n === 2">React</div>
         <div v-else>Vue</div>
     </div>
 </body>
 ​
 <script type="text/javascript">
     Vue.config.productionTip = false
 ​
     const vm = new Vue({
         el:'#root',
         data:{
             name:'jojo',
             n:0
         }
     })
 </script>
 </html>

< template>配合v-if使用:

     
<template v-if="true">
         <h3>你好,{{name}}</h3>
         <h3>你好,{{name}}</h3>
         <h3>你好,{{name}}</h3>
     </template>

< template>不会渲染到DOM结构中,且只有和v-if配合使用才可以起到整套删除整套显示的效果。

9.2、v-show

写法:v-show=“表达式” 适用于:切换频率较高的场景 特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉了

使用v-if的时,元素可能无法获取到,而使用v-show一定可以获取到

10、列表渲染

10.1、基本列表

v-for指令:

  • 用于展示列表数据

  • 语法:

v-for="(item,index) in xxx" :key="xxx"

举例:

 
<!DOCTYPE html>
 <html>
     <head>
         <meta charset="UTF-8" />
         <title>基本列表</title>
         <script type="text/javascript" src="../js/vue.js"></script>
     </head>
     <body>
         <div id="root">
             <h2>人员列表(遍历数组)</h2>
             <ul>
                 <li v-for="(p,index) in persons" :key="index">
                     {{p.name}}-{{p.age}}
                 </li>
             </ul>
 ​
             <h2>汽车信息(遍历对象)</h2>
             <ul>
                 <li v-for="(value,k) in car" :key="k">
                     {{k}}-{{value}}
                 </li>
             </ul>
 ​
             <h2>遍历字符串</h2>
             <ul>
                 <li v-for="(char,index) in str" :key="index">
                     {{char}}-{{index}}
                 </li>
             </ul>
             
             <h2>遍历指定次数</h2>
             <ul>
                 <li v-for="(number,index) in 5" :key="index">
                     {{index}}-{{number}}
                 </li>
             </ul>
         </div>
 ​
         <script type="text/javascript">
             Vue.config.productionTip = false
             
             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'
                 }
             })
         </script>
     </body>
 </html>
 ​

总结:

v-for指令:

  1. 用于展示列表数据

  2. 语法:<li v-for="(item, index) in xxx" :key="yyy">,其中key可以是index,也可以是遍历对象的唯一标识

  3. 可遍历:数组、对象、字符串(用的少)、指定次数(用的少)

10.2、key的原理

我们在上面遍历数组的代码基础上,增加一个需求:点击一个按钮在张三的上面增加一行老刘的信息,并在每一行后面增加一个input框,用这个需求来分析key的原理:

 <!DOCTYPE html>
 <html>
     <head>
         <meta charset="UTF-8" />
         <title>key的原理</title>
         <script type="text/javascript" src="../js/vue.js"></script>
     </head>
     <body>
         <div id="root">
             <h2>人员列表</h2>
             <button @click.once="add">添加老刘</button>
             <ul>
                 <li v-for="(p,index) in persons" :key="index">
                     {{p.name}} - {{p.age}}
                     <input type="text">
                 </li>
             </ul>
         </div>
 ​
         <script type="text/javascript">
             Vue.config.productionTip = false
             
             new Vue({
                 el:'#root',
                 data:{
                     persons:[
                         {id:'001',name:'张三',age:18},
                         {id:'002',name:'李四',age:19},
                         {id:'003',name:'王五',age:20}
                     ]
                 },
                 methods: {
                     add(){
                         const p = {id:'004',name:'老刘',age:40}
                         this.persons.unshift(p)
                     }
                 },
             })
         </script>
 </html>
 ​

原理:

 

 

  1. 虚拟DOM中key的作用:key是虚拟DOM中对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:

  2. 对比规则:

    • 旧虚拟DOM中找到了与新虚拟DOM相同的key:

      • 若虚拟DOM中内容没变, 直接使用之前的真实DOM

      • 若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM

    • 旧虚拟DOM中未找到与新虚拟DOM相同的key:创建新的真实DOM,随后渲染到到页面

  3. 用index作为key可能会引发的问题:

    若对数据进行逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低 若结构中还包含输入类的DOM:会产生错误DOM更新 ==> 界面有问题

  4. 开发中如何选择key?

    最好使用每条数据的唯一标识作为key,比如id、手机号、身份证号、学号等唯一值 如果不存在对数据的逆序添加、逆序删除等破坏顺序的操作,仅用于渲染列表,使用index作为key是没有问题的

10.3、列表过滤

下面用两个例子(分别是用监视和计算属性)来实现列表过滤:

例子一(监视):

<div id="root">
    <input type="text" placeholder="请输入名字" v-model="keyword">
    <ul>
        <li v-for="p in person1" :key="p.id">{{p.name}}-{{p.age}}-{{p.sex}}</li>
    </ul>
</div> 
   const vm = new Vue({
        el: "#root",
        data: {
            keyword: "",
            person: [{
                id: '001',
                name: "马冬梅",
                age: 18,
                sex: '女'
            }, {
                id: '002',
                name: "周冬雨",
                age: 28,
                sex: '女'
            }, {
                id: '003',
                name: "周杰伦",
                age: 13,
                sex: '男'
            }, {
                id: '004',
                name: "温兆伦",
                age: 45,
                sex: '男'
            }, ],
            person1: []
        },
        watch: {
            keyword: {
            	//初始状态页面没有数据显示,即初始状态person1为空,此时让handler先执行一遍,让person1得到数据
                immediate: true,
                handler(val) {
					//filter过滤器 遍历旧数组中的元素后,返回过滤后的新数组
                    this.person1 = this.person.filter((p) => {
                    	//indexOf 前一个字符串中是否包含有括号里的字符串,不包含返回-1
                        return p.name.indexOf(val) !== -1
                    })
                }
            }
        }
    })

例子二(计算属性):

<div id="root">
    <input type="text" placeholder="请输入名字" v-model="keyword">
    <ul>
        <li v-for="p in person1" :key="p.id">{{p.name}}-{{p.age}}-{{p.sex}}</li>
    </ul>
</div>
 const vm = new Vue({
        el: "#root",
        data: {
            keyword: "",
            person: [{
                id: '001',
                name: "马冬梅",
                age: 18,
                sex: '女'
            }, {
                id: '002',
                name: "周冬雨",
                age: 28,
                sex: '女'
            }, {
                id: '003',
                name: "周杰伦",
                age: 13,
                sex: '男'
            }, {
                id: '004',
                name: "温兆伦",
                age: 45,
                sex: '男'
            }, ]
        },
        computed: {
            person1() {
                return this.person.filter((p) => {
                    return p.name.indexOf(this.keyword) !== -1
                })
            }
        }

    })

10.4、列表排序

在上面用计算属性的列表过滤的基础上增加一个排序功能:

<div id="root">
    <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 in person1" :key="p.id">{{p.name}}-{{p.age}}-{{p.sex}}</li>
    </ul>
</div>
 const vm = new Vue({
            el: "#root",
            data: {
                keyword: "",
                sortType: 0, //0原顺序,1降序,2升序
                person: [{
                    id: '001',
                    name: "马冬梅",
                    age: 18,
                    sex: '女'
                }, {
                    id: '002',
                    name: "周冬雨",
                    age: 28,
                    sex: '女'
                }, {
                    id: '003',
                    name: "周杰伦",
                    age: 13,
                    sex: '男'
                }, {
                    id: '004',
                    name: "温兆伦",
                    age: 45,
                    sex: '男'
                }, ]
            },
            computed: {
                person1() {
                    const arr = this.person.filter((p) => {
                            return p.name.indexOf(this.keyword) !== -1
                        })
                        //判断是否排序
                    if (this.sortType) {
                        arr.sort((a, b) => {
                            return this.sortType === 1 ? b.age - a.age : a.age - b.age
                        })
                    }
                    return arr
                }
            }

        })

穿插:Vue监测数据的原理

1、更新时的一个问题

<div id="root">
    <ul>
        <button @click="mdm">更新马冬梅的信息</button>
        <li v-for="p in person" :key="p.id">{{p.name}}-{{p.age}}</li>
    </ul>
</div>
const vm = new Vue({
        el: "#root",
        data: {
            person: [{
                id: '001',
                name: "马冬梅",
                age: 18,
                sex: '女'
            }, {
                id: '002',
                name: "周冬雨",
                age: 28,
                sex: '女'
            }, {
                id: '003',
                name: "周杰伦",
                age: 13,
                sex: '男'
            }, {
                id: '004',
                name: "温兆伦",
                age: 45,
                sex: '男'
            }, ]
        },
        methods: {
            mdm() {
                this.person[0].name = '马老师'
                this.person[0].age = 50
                this.person[0].sex = '男'
            }
        }
    })

上述代码实现更新马冬梅的信息:

 点击按钮后成功更新:

但是将methods中的方法改为直接修改整个对象元素:

methods: {
	mdm() {
		this.person[0] = {
			id: '001',
			name: "马老师",
			age: 50,
			sex: "男"
		}
	}
}

 

这样点击按钮,信息就没有更新,其实Vue无法监测到直接给数组元素赋的值,下面说说Vue监测数据的原理。

2、监测数据的原理

①Vue会监测data中所有层次的数据,就是即使对象中的对象的属性也能递归监测

②如何监测对象中的数据 通过setter实现监测,且要在new Vue时就传入要监测的数据

(1)对象中后追加的属性,Vue默认不做响应式处理

(2)如需要给后添加的属性做响应式,请使用如下API:Vue.set(target,propertyName/index,value)或vm.$set(target,propertyName/index,value)

③如何监测数组中的数据 通过包裹数组更新的方法实现,本质就是做了两件事:

(1)调用原生对应的方法对数组进行更新

(2)重写解析模板,进行更新页面

④在Vue修改数组中的某一个元素不能直接赋值,即不能直接带下标赋值,Vue监测不到,就像上面的问题一样,一定要用如下方法:

(1)使用数组的一些API:push()/pop()/shift()/unshift()/splice()/sort()/reverse()

(2)Vue.set()或vm.$set()

当然可以直接改变整个数组。

特别注意:Vue.set()和vm.$set()不能给vm或vm的根数据对象 添加属性

例子:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>Vue数据监视</title>
		<style>
			button{
				margin-top: 10px;
			}
		</style>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<div id="root">
			<h1>学生信息</h1>
			<button @click="student.age++">年龄+1岁</button><br/>
			<button @click="addSex">添加性别属性,默认值:男</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>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

		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,'开车')
				},
				removeSmoke(){
					this.student.hobby = this.student.hobby.filter((h)=>{
						return h !== '抽烟'
					})
				}
			}
		})
	</script>
</html>

效果:

每个点击之后

  

11、收集表单数据  

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>收集表单数据</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<div id="root">
			<form @submit.prevent="demo">
				账号:<input type="text" v-model.trim="userInfo.account"> <br/><br/>
				密码:<input type="password" v-model="userInfo.password"> <br/><br/>
				年龄:<input type="number" v-model.number="userInfo.age"> <br/><br/>
				性别:
				男<input type="radio" name="sex" v-model="userInfo.sex" value="male">
				女<input type="radio" name="sex" v-model="userInfo.sex" value="female"> <br/><br/>
				爱好:
				学习<input type="checkbox" v-model="userInfo.hobby" value="study">
				打游戏<input type="checkbox" v-model="userInfo.hobby" value="game">
				吃饭<input type="checkbox" v-model="userInfo.hobby" value="eat">
				<br/><br/>
				所属校区:
				<select v-model="userInfo.city">
					<option value="">请选择校区</option>
					<option value="beijing">北京</option>
					<option value="shanghai">上海</option>
					<option value="shenzhen">深圳</option>
					<option value="wuhan">武汉</option>
				</select>
				<br/><br/>
				其他信息:
				<textarea v-model.lazy="userInfo.other"></textarea> <br/><br/>
				<input type="checkbox" v-model="userInfo.agree">阅读并接受<a href="http://www.atguigu.com">《用户协议》</a>
				<button>提交</button>
			</form>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false

		new Vue({
			el:'#root',
			data:{
				userInfo:{
					account:'',
					password:'',
					age:0,
					sex:'female',
					hobby:[],
					city:'beijing',
					other:'',
					agree:''
				}
			},
			methods: {
				demo(){
					console.log(JSON.stringify(this.userInfo))
				}
			}
		})
	</script>
</html>

总结:

  1. 收集表单数据:

  • 若:<input type="text"/>,则v-model收集的是value值,用户输入的内容就是value值

  • 若:<input type="radio"/>,则v-model收集的是value值,且要给标签配置value属性

  • 若:<input type="checkbox"/>

    • 没有配置value属性,那么收集的是checked属性(勾选 or 未勾选,是布尔值)

    • 配置了value属性:

      • v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)

      • v-model的初始值是数组,那么收集的就是value组成的数组

  1. v-model的三个修饰符:

  • lazy:失去焦点后再收集数据

  • number:输入字符串转为有效的数字

  • trim:输入首尾空格过滤

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值