第四章 vue模板基本语法
- 插值操作
- 绑定属性
- 计算属性
- 事件监听
- 条件判断
- 循环遍历
- 其他语法
4.1 插值、指令
-
插值:
{{}}
-
指令:
v-
- 在
{{}}
和v-
指令进行数据绑定时,支持js单个表达式 <p v-once>{{msg}}</p>
数据只第一次显示,不响应式<p v-pre>{{msg}</p>}
内容原封不动地展示,也就会显示{{}}<p v-text='msg'></p>
相当于插值表达式的功能- **
<p v-html='title'></p>
**可以解析数据中的标签
- 在
-
绑定属性:
v-bind:
可以写在标签属性前,这样属性值可以直接写变量,无需{{}}
,语法糖:标签属性前直接加:
-
通过绑定属性,可以实现通过改变变量来动态改变标签样式
- 绑定class属性,字符串、数组、对象、方法
- 绑定style属性
-
样式可以拼接字符串、数组格式、json格式
-
属性名有
-
可以整个属性名加''
或者去掉-
采用驼峰命名 -
相同的属性名,后面的会把前面的覆盖掉
<template> <div> <!--Vue2-3 模板中的基本语法--> <h1>插值</h1> <hr> <p>{{title}}</p> <p>{{str}}</p> <p>{{arr[0]}}-{{arr[1]}}</p> <p>{{obj.name}}-{{obj.age}}</p> <p>{{fun(111)}}</p> <!--插值中可以使用简单的运算符号以及js基本语法 但不常用--> <p>{{title+obj.name+'hello'}}</p> <p>{{title.substring(5,10)}}</p> <div v-once>num:{{num}}</div> <div>num:{{num}}</div> <button @click="num++">+</button> <div v-html="html"></div> <!--绑定属性--> <a href="#" :title="str">{{title}}</a> <!--动态改变样式--> <div style="background: #42b983" :style="'width:'+width+'px; height:'+height+'px'" @click="width+=10, height+=10" > ddd </div> <div style="background: cornflowerblue" :style="[width1, height1]" > fff </div> <!--还可以采用json格式--> <div style="background: powderblue" :style="{width:width+'px',height:height+'px'}" > sss </div> <div style="background: powderblue" :style="{'background-color':'yellow',fontSize:'30px'}" > ssss </div> <div style="background: powderblue" :style="[width1,height1,{'background-color':'gray',fontSize:'30px'}]" > ssss </div> <!--真假值使用--> <div class="one three" :class="two"></div> <div class="one" @click="show=!show" :class="[two,'three']"></div> <!--点击一次实现隐藏或显示,属性(show)值可以是布尔型--> <div class="one two three" :class="['hide',{show}]"></div> </div> </template> <script> export default { name: 'HelloWorld', data(){ //这里返回的相当于整个组件的成员属性,成员属性在模板不需要this,但在本身方法里里需要this return{ title:'this is msg', html: 'this is <a href="#">html</a>', str:'abc', arr:['aaa','ddd'], obj:{ name:'ddd', age:21 }, num:0, width: 200, height: 100, width1:'width:100px', height1:'width:100px', show:true, two:'two' } }, /*****vue2*****/ // data:{ // // } methods:{ fun(index){ return "abc"+index; } } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped lang="scss"> .one{ color: red; font-size: 30px; } .two{ width: 100px; height: 100px; } .three{ background-color: yellow; box-shadow: 5px 5px 8px #ccc; } .hide{ display: none; } .show{ display: block; } </style>
-
4.2 计算属性
-
关键词:
computed
-
计算属性处理一些复杂逻辑很有用
-
计算属性是基于它的依赖进行缓存的。只有当计算属性的相关依赖发生变化时,计算属性才会重新计算。例如,在计算属性的函数中使用
console.log
语句时,它只会在计算属性首次执行时被调用,因为后续的依赖变化并不会触发计算属性的重新计算,从而导致console.log
语句只执行一次。 -
案例:
computed:{ //属性名称,调用该属性相当于调用以下get函数 demo1:{ // 逻辑 get(){ console.log('##########') return this.arr[0]+this.arr[1]; }, /*set: function(newValue){ }*/ }, //写法二,这样默认调用get函数,这种写法使用较多 demo2(){ console.log('2##########') return this.arr[0]+this.arr[0]; }
<template> <div> <h1>计算属性</h1> <hr> {{arrsum()}} <br> {{demo1}} {{demo1}} <br> {{demo2}} {{demo2}} </div> </template>
4.3 事件监听
-
前端开发中,需经常和用户交互
-
绑定事件监听器指令:v-on
-
缩写:
@
(语法糖) -
参数:
$event
可以得到该事件对象,键盘事件可能会需要这样的参数 -
v-on
事件修饰符号,事件修饰符号可以连用.stop
阻止事件冒泡.self
当事件在该元素本身触发时才触发事件.capture
添加事件侦听器时,使用事件捕获(由父到子)模式,只要捕获就触发事件,因此和事件冒泡顺序相反.prevent
阻止默认事件.once
事件只触发一次
<h1 @mouseenter="ent" @mouseleave="lev" :style="{display: show ? 'block':'none'}">事件监听</h1> <!-- mouseenter mouseleave 只监听最外层父组件,bug较少--> <hr> <button v-on:click="showtitle()">button</button> <br> <button @click="showtitle()">button</button> <br> <!--阻止默认事件,跳转链接--> <a href="#" @click.prevent="fu1()">one</a> <!--模拟事件冒泡 添加.stop阻止了该事件冒泡--> <div @click.stop="fu3()" class="box3"> box3 <div @click.stop ="fu2()" class="box2"> box2 <div @click.stop="fu1()" class="box1"> box1 </div> </div> </div>
methods:{ fun(index){ return "abc"+index; }, arrsum(){ // 方法里需要使用this return this.arr[0]+this.arr[1]; }, showtitle(){ this.show =!this.show; }, ent(){ console.log('1111111'); }, lev(){ console.log('2222222'); }, fu1(){ console.log('1111111111') }, fu2(){ console.log('2222222222') }, fu3(){ console.log('3333333333') } }
.box3{ width: 300px; height: 300px; background-color: red; } .box2{ width: 200px; height: 200px; background-color: orangered; } .box1{ width: 100px; height: 100px; background-color: orange; }
4.4 条件分支指令
-
v-if
和v-show
v-if
是真正的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。本元素标签和它子元素标签均受该条件控制v-show
不管初始条件是什么,元素总是会被渲染,并且只是简单地基于CSS进行切换
-
v-if
v-else
-
v-if
v-else-if
v-else
-
案例:
<!--条件分支--> <button @click="tabs=1">one</button> <button @click="tabs=2">two</button> <button @click="tabs=3">three</button> <button @click="tabs=4">four</button> <hr> <div v-if="tabs==1" class="box1"></div> <div v-else-if="tabs==2" class="box2"></div> <div v-else-if="tabs==3" class="box3"></div> <div v-else class="box1">444</div> <br> <hr> <button @click="show=!show">显示</button> <!--v-if 元素销毁和重建--> <div v-if="show" class="box2"></div> <!--v-show 只是元素样式改变 display:none --> <div v-show="!show" class="box3"></div>
data(){ //这里返回的相当于整个组件的成员属性,成员属性在模板不需要this,但在本身方法里里需要this return{ tabs:1, show:true, title:'this is msg', html: 'this is <a href="#">html</a>', str:'abc', arr:['aaa','ddd'], .....
4.5 循环遍历指令
-
v-for
遍历指令 -
v-for="(item,[index]) in 数组"
遍历数组 -
v-for="(value,[key],[index] in 对象)"
遍历对象 -
进行循环时标签还要添加**
:key="唯一标识"
**,唯一标识可以是item里面的id、index- Vue将
templete
抽象为一个虚拟DOM(结构就像DOM树,实际是一个对象,对象中包含多个标签,各自的名字属性内容和子标签)。接着script
(Model)修改虚拟DOM之后,再通过Vue转化达到修改页面效果 - 实现从虚拟DOM到页面上响应式数据变化,采用diff算法,虚拟DOM和真实DOM进行对比,有变化则只更新差异部分,故能提高渲染效率
- 比较时,相同层次的DOM节点一层一层进行比较
- 增加
key
就可以唯一标识各个DOM节点,实现节点的高度复用(key
相同的地方要维持原来的状态),更新虚拟DOM效率更高。如果没有设置key
,Vue只能通过位置索引来匹配和更新节点,这可能导致不必要的节点销毁和创建,影响性能。避免使用随机数或索引作为key
,因为它们在列表项顺序变化时可能会导致问题。
- Vue将
-
案例:
-
<template> <div> <!-- 控制整个标签元素,包括它的子元素,遍历多少次则子元素就要“重现”多少次 --> <div v-for="item in 10"> <h2>########{{item}}</h2> </div> <div v-for="item in myarr.slice(3,4)"> <h2>########{{item}}</h2> </div> <!--可选择添加索引--> <!--可以有运算符--> <div v-for="(item,index) in 'abcdef' "> <h2>{{index+1}}-{{item}}</h2> </div> <!--嵌套循环遍历,建议嵌套不超过三层--> <ul> <!--循环必须加key,key是循环遍历中的唯一值--> <li v-for="(item,index) in carts" :key="index"> {{index}}--{{item.name}}--{{item.price}}--{{item.author}} <br> <div style="background-color: powderblue"> <p v-for="(item2,index) in item.comment" :key="index2"> {{item2.username}}:{{item2.content}}--{{item.name}} </p> </div> </li> </ul> <!--没有key--> <div> <input type="text" v-model="name"> <!-- 实现双向绑定 name input改变name 组件数据name改变 模板上name发生相应改变 --> <!-- 没有key 点击checkbox 但表单如果发生了增减,checkbox不会随着对应数据变化index,依旧处于原来的index位置--> <button @click="add()">add...{{name}}</button> </div> <ul> <!-- 添加一个不变的唯一值作为key--> <li v-for="(item,index) in books" :key="item.id"> <input type="checkbox"> {{index+1}} -- {{item.name}} --¥{{item.price}} </li> </ul> </div> </template> <script> export default{ name:'test', data(){ return { myarr:[ '111', '222', '333', '444', '555', '666', ], carts:[ {name:'《CSAPP》', author:'xx', price:'158', comment:[ {username:'ddd',content:'good'}, {username:'abc',content:'nice'}, {username:'def',content:'ok'} ] }, {name:'《CSAPP》', author:'xx', price:'158', comment:[ {username:'ddd',content:'good'}, {username:'abc',content:'nice'}, {username:'def',content:'ok'} ] } ], mid:6, books:[ {id:1,name:'学习前端',price:158,active:false}, {id:2,name:'学习vue',price:158,active:false}, {id:3,name:'学习js',price:158,active:false}, {id:4,name:'学习css',price:158,active:false}, {id:5,name:'学习html',price:158,active:false}, ] } }, methods:{ add(){ // this.name,使用双向绑定表单里输入的name(this就是这个vue组件,name是这个组件的data数据对象之一) this.books.unshift({id:++this.mid,name:this.name,price:150,active:false}); } } } </script> <style scoped lang="scss"> </style>
4.6 输入监听
-
v-model
负责监听用户的输入事件,从而更新数据,并对一些极端场景进行一些特殊处理。同时,v-model会忽略所有表单元素的value、checked、selected特性的初始值,将vue实例中的数据作为数据来源 -
实现原理:
<input v-bind:value="message" v-on:input="message = $event.target.value"/>
-
v-model
的修饰符号(修饰符ke’yi):.lazy
懒加载修饰符:不实时更新,确认完毕一次加载.number
修饰符让其转换为number类型.trem
修饰符可以自动过滤掉输入框的首尾空格
-
练习案例:
<template> <form action=""> {{userinfo.username}}<br> username: <input type="text" v-model.lazy="userinfo.username"> <br> password: <input type="text" v-model="userinfo.password"> </form> <button @click="login()">Login</button> <br> {{sex}} <div> <!--用name和value标记为一组内的不同值--> <label for="one"> <input id="one" type="radio" name="sex" value="1">女 </label> <label for="two"> <input id="two" type="radio" name="sex" value="2">男 </label> </div> <!--data中添加sex 不需要name属性,也可以代替checked属性,且可以设置默认值 v-model绑定还可以提交值到data中--> <br> <div> <label for="one"> <input id="one" type="radio" v-model="sex" value="1">女 </label> <label for="two"> <input id="two" type="radio" v-model="sex" value="2">男 </label> </div> <br> {{isAgree}}<br> <label for="ww"> <!--通过v-model绑定属性isAgree 默认同意 和直接写checked效果相同--> <input id="ww" v-model="isAgree" type="checkbox">同意协议 </label> <br> {{tags}} <!--点击选择,data中tags数组就会添加上相应的数据--> <label for="a"> <input id="a" type="checkbox" value="1" v-model="tags" >vue </label> <label for="b"> <input id="b" type="checkbox" value="2" v-model="tags" >React </label> <label for="c"> <input id="c" type="checkbox" value="3" v-model="tags" >Angular </label> <br> <!--添加mutiple,单选变为多选,变量变成数组,按住ctrl跳选,按住shift可以连选--> <select v-model="selectv" multiple> <option value="111">111</option> <option value="222">222</option> <option value="333">333</option> <option value="444">444</option> </select> <br> {{selectv}} </template> <script> export default { name:'login', data(){ return{ sex:1, isAgree: true, tags:[ ], selectv:[], userinfo:{username:'',password:''} } }, methods:{ login(){ console.log((this.userinfo)); } } } </script> <style scoped lang="scss"> </style>