Vue笔记
vue简介
1.vue是什么
一套用于构建用户界面的渐进式javascript框架
构建用户界面:拿到的数据转换为用户可以看到的数据
渐进式:vue可以自底向上逐层用 从一个轻量小巧的库逐渐递进到使用各式各样的vue插件
2.vue开发者(老二次元了,哈哈
2013 | 受到Angular的启发,尤雨溪开发出了一款轻量框架Seed同年12月,Seed更名为vue 版本号0.6.0 |
---|---|
2014 | vue正式对外发布,版本0.8.0 |
2015 | 10月27日,正式发布vue1.0.0 Evangelion(新世纪福音战士) |
2016 | 10月1日,正式发布vue2.0.0 Ghost in the Shell(攻壳机动队) |
2020 | 10月27日,正式发布vue1.0.0 One Piece(海贼王) |
3.vue的特点
采用组件化模式,提高代码的复用率,且代码更好的维护
声明式编码 让编码人员无需操作DOM,提高开发效率
声明式编码和命令式编码区别
1.命令式:举个例子就是说一下做一下不说就不做
2.声明式:举个例子就是口有点干,说一声口有点干 然后就会有人给我泡茶倒水端到我跟前
4.虚拟DOM
- 虚拟DOM就是内存中的一个数据vue可以最后转换成真实的DOM
把代码转换为虚拟的DOM然后虚拟DOM转换为真实DOM,如果数据中新添加了赵六,vue会创建一个新的DOM,然后会跟旧的DOM作比较(通过Diff算法)没有改变的数据直接复用,然后转换为页面的真实DOM
vue开发环境
1.引入vue文件
<script type="text/javascript" src="https://unpkg.com/vue"></script><!--这里引入的是vue的cnd->
2.下载插件
在浏览器扩展里面搜索Vue.js devtools插件 下载(注意:在详细信息里面勾选 允许访问文件 URL选项)
vue基础语法
1.插值语法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<!-- 引入vue.js文件 -->
<script src="../static/js/vue.js"></script>
<body>
<!--
容器
vue实例和容器是一一对应的
{{}}插值语法 不仅可以读取到vue实例中的data里的属性 也可以写入js表达式比如:{{1+1}}
-->
<div id="root">
<h1>{{name}}</h1>
</div>
<script>
//创建vue实例对象
new Vue({
//el指定当前vue实例为当前那个容器服务,值通常为css选择器字符串
el: "#root",
//data用于存储数据 数据供el提供的容器使用
data: {
name: "初始vue",
},
})
</script>
</body>
</html>
- 当vue开始工作的时候把容器拿过来解析,解析容器里有没有vue的语法,里面有一个插值语法,然后找到name把属性值赋值给容器里面的name,然后生成了全新的一个容器,在把解析完的容器放到页面当中
2.模板语法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<!-- 引入vue.js文件 -->
<script src="../static/js/vue.js"></script>
<body>
<div id="root">
<h1>两年前</h1>
<h2>{{name}}</h2>
<h1>两年后</h1>
<!-- 指令语法:也可以简写为:href 在属性前面加:就是v-bind指令语法-->
<a v-bind:href="onepicec.url">{{onepicec.name}}</a>
</div>
<script>
new Vue({
el: "#root",
data: {
name: "梅利号",
onepicec: {
name: "万里阳光号",
sex: "男",
url: "https://one-piece.com/",
},
},
});
</script>
</body>
</html>
1.插值语法:
功能:用于解析标签体内容
2.指令语法:
功能:用于解析标签(标签属性、标签体内容、绑定事件....)
2.数据绑定
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<!-- 引入vue.js文件 -->
<script src="../static/js/vue.js"></script>
<body>
<div id="root">
单项绑定:<input type="text" v-bind:value="name">
<br/>
双向绑定:<input type="text" v-model:value="name">
<br>
单项绑定简写:<input type="text" :value="name">
<br/>
双向绑定简写:<input type="text" v-model="name">
</div>
<script>
new Vue({
el: "#root",
data: {
name: "海贼王",
},
});
</script>
</body>
</html>
vue中的两种绑定方式
1.单项绑定
数据只能从data流向页面
2.双向绑定
数据不仅能从data流向页面 而且还可以从页面流向data
双向绑定一般应用在表单元素上
v-model默认绑定的就是value 所以可以简写为v-model
3.el和data的两种写法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<!-- 引入vue.js文件 -->
<script src="../static/js/vue.js"></script>
<body>
<div id="root1">
<h1>{{name}}</h1>
</div>
<div id="root2">
<h1>{{name}}</h1>
</div>
<script>
//第一种el和data的写法
new Vue({
el: "#root1",
data: {
name: "火影忍者",
},
});
//第二种el和data的写法
const vm=new Vue({
data(){
return{
name: "鬼灭之刃"
}
}
});
vm.$mount("#root2");
</script>
</body>
</html>
el的两种
1.newVue的时候被指el属性
2.先创建vue实例然后在通过vm.$mount("#root2")指定el的值
data的两种
1.对象式
2.函数式
3.注意:
-
data以后学习到组件的时候必须使用函数时不然会报错
-
vue管理的函数不要写箭头函数不然this指向就不是vu实例了
4.MVVM
1.M:模型(Model):对应data中的数据
2.V:视图(View):模板
3.VM:视图模型(ViewModel):Vue实例对象
5.数据代理
1.回顾object.defineProperty
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script src="../static/js/vue.js"></script>
<body>
<script>
let nums=18;
let arrays={
name: "张三",
sex: "男",
};
Object.defineProperty(arrays,'age',{
/*
value: 18,
// 设置属性是否可以枚举
enumerable:true,
//设置属性是否可以被修改
writable:true,
// 设置属性是否可以删除
configurable:true,
*/
// 当读取age属性 就调用get方法
get(){
console.log("读取了get")
return age=nums;
},
// 当修改age属性 就调用set方法
set(value){
console.log("修改了age")
return nums=value;
},
});
for(let array in arrays){
console.log(array);
};
</script>
</body>
</html>
数据代理:通过一个对象代理另一个对象中属性的操作(读/写)
2.vue中的数据代理
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script src="../static/js/vue.js"></script>
<body>
<div id="root">
<h1>{{name}}</h1>
<h1>{{sex}}</h1>
</div>
<script>
let datavm={
name: "蒙奇.D.路飞",
sex: "女",
}
const vm = new Vue({
el: "#root",
data: datavm,
});
</script>
</body>
</html>
比较_data是否是data
vm._data === datavm
true
vue中的数据代理
通过vm对象来代理data对象中的属性的操作(读/写)
好处
更加方便的操作data里面的数据
基本原理
通过Object.defineProperty把data对象中所以的属性添加到vm对象中,为每一个添加到vm身上的属性添加getter/setter
通过getter/setter,内部去操作data中对应的属性
事件处理
1.事件基本使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script src="../static/js/vue.js"></script>
<body>
<div id="root">
<h1>{{name}}</h1>
<button v-on:click="showInfo1()">梅利</button>
<button @click="showInfo2($event,666)">桑尼</button>
</div>
<script>
const vm=new Vue({
el: "#root",
data: {
name: "梅利号"
},
methods: {
showInfo1(){
alert("你好!梅利号");
},
showInfo2(event,nums){
alert("你好!万里阳光号"+nums);
console.log(event);
},
},
});
</script>
</body>
</html>
-
v-on:事件 可以简写为@事件
-
事件的回调需要配置在methods对象中
2.事件修饰符
- 修饰符
prevent 阻止事件的默认事件
stop 阻止冒泡
once 事件只触发一次
captrue 事件捕获是触发
self 操作的是当前的事件才触发
passive事件的默认行为立即执行
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script src="../static/js/vue.js"></script>
<style>
*{
margin-top: 40px;
}
.box{
width: 100%;
height: 80px;
background-color: aquamarine;
}
.box1{
width: 100%;
height: 80px;
background-color: rgb(173, 58, 38);
}
.box2{
width: 100%;
height: 30;
background-color: rgb(15, 37, 163);
}
.box3{
width: 200px;
height: 300px;
overflow: auto;
}
.box3 >li {
width: 200px;
height: 100px;
background-color: blue;
}
</style>
<body>
<div id="root">
<a href="https://www.bilibili.com" @click.prevent="showInfo()">白胡子</a>
<div class="box" @click="showInfo">
<button @click.stop="showInfo">冒泡</button>
</div>
<button @click.once="one">罗杰</button>
<div class="box1" @click.capture="two(1)">
div1
<div class="box2" @click="two(2)">
div2
</div>
</div>
<div class="box" @click.self="there">
<button @click="there">事件</button>
</div>
<!--wheel 鼠标滚轮触发事件-->
<!--scroll 滚动条事件-->
<ul @scroll.passvie="four" class="box3">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
</div>
<script>
new Vue({
el: "#root",
methods: {
showInfo(){
alert("one pirece 是真实存在的");
},
one(){
alert("我的宝藏都放在哪里了去寻找吧");
},
two(a){
console.log(a);
},
there(event){
console.log(event.target);
},
four(){
for (let i = 0; i < 100000; i++) {
console.log("one pirece")
}
},
},
});
</script>
</body>
</html>
3.键盘事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script src="../static/js/vue.js"></script>
<body>
<div id="root">
<input type="text" placeholder="输入数字" value="" @keydown.enter.y="showInfo"/>
</div>
<script>
new Vue({
el: "#root",
methods: {
showInfo(event){
// keyCode打印键盘的编码 key打印键盘名字
console.log(event.keyCode+"------------"+event.key);
console.log(event.target.value);
},
},
})
</script>
</body>
</html>
- keydown事件 按下去触发事件
- keyup事件 按下去不触发 然后弹上来触发事件
- 回车 => enter
- 删除 => delete
- 退出 => esc
- 空格 => space
- 换行 => tab(特殊配合keydown使用 这个键会切换焦点)
- 上 => up
- 下 => down
- 左 => left
- 右 => right
- 大写切换必须使用两个字母首字母小写中间用 - 拼接
- Vue.config.keycodes.huiche=13 自定义键名
计算属性
1.methods计算
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script src="../static/js/vue.js"></script>
<body>
<div id="root">
姓:<input type="text" v-model="firstName"/><br/>
名:<input type="text" v-model="latsName"/><br/>
<h1>{{ fullName() }}</h1><br/>
</div>
<script>
new Vue({
el: "#root",
data: {
firstName: "张",
latsName: "三",
},
methods: {
fullName(){
return this.firstName+"-"+this.latsName;
}
},
})
</script>
</body>
</html>
2.computed计算
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script src="../static/js/vue.js"></script>
<body>
<div id="root">
姓:<input type="text" v-model="firstName"/><br/>
名:<input type="text" v-model="latsName"/><br/>
<h1>{{ fullName }}</h1><br/>
</div>
<script>
new Vue({
el: "#root",
data: {
firstName: "张",
latsName: "三",
},
computed:{
fullName:{
get(){
// 返回值会作为fullName的值
return this.firstName+"-"+this.latsName;
}
},
},
/*简介写法 只读不改的情况下使用简写方式
fullName(){
// 返回值会作为fullName的值
return this.firstName+"-"+this.latsName;
},*/
})
</script>
</body>
</html>
计算属性
-
定义:要用的属性不存在 要通过已有属性计算得来
-
原理:借助了底层的object.defineproperty方法提供的getter/setter
-
get函数什么使用调用
1.初次读取的时候调用一次
2.当依赖的数据发生变化是在调用一次
-
更methods相比内部有缓存机制(服用) 效率更高 调式方便
-
计算属性最终会出现在vue的实例上 直接读取就可以使用
监视属性
1.天气案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script src="../static/js/vue.js"></script>
<body>
<div id="root">
<h2>我是{{ isName }}</h2>
<button @click="is()">切换人物</button>
</div>
<script>
const vm = new Vue({
el: "#root",
data: {
name:true,
},
computed:{
isName(){
return this.name==true? "海贼王路飞" : "大剑豪索隆" ;
}
},
methods: {
is(){
return this.name = !this.name;
}
},
// watch: {
// isName:{
// // 监视的属性发生变化时调用
// handler(newValue,oldValue){
// console.log("isName被修改了"+newValue+oldValue);
// }
// }
// }
})
vm.$watch('isName',{
handler(newValue,oldValue){
console.log("isName被修改了"+newValue+oldValue);
}
});
</script>
</body>
</html>
-
当监视属性变化时 回调函数自动调用
-
监视的属性必须存在才能监视
-
两种写法
-
1.vue实例里面写入watch配置对象
2.通过vm.$watch()监视
2.深度监视
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script src="../static/js/vue.js"></script>
<body>
<div id="root">
<h2>a:{{ numbers.a }}</h2>
<button @click="(numbers.a)++">加</button>
<h2>b:{{ numbers.b }}</h2>
<button @click="(numbers.b)--">减</button>
<button @click=" numbers={a:2000,b:3000}">替换numbers</button>
</div>
<script>
const vm = new Vue({
el: "#root",
data: {
numbers:{
a: 1,
b: 100,
},
},
watch: {
// 'numbers.a':{
// // 监视的属性发生变化时调用
// handler(newValue,oldValue){
// console.log("a被修改了"+newValue+"---"+oldValue);
// }
// },
// 'numbers.b':{
// // 监视的属性发生变化时调用
// handler(newValue,oldValue){
// console.log("b被修改了"+newValue+"---"+oldValue);
// }
// }
numbers:{
// 深度监视 可以监视多层属性
deep:true,
handler(newValue,oldValue){
console.log("numbers被修改了"+newValue+"---"+oldValue);
}
},
}
})
</script>
</body>
</html>
- vue中的watch默认不监视对象内部的变化(一层)
- 配置deep:true,可以监视对象内部变化(多层)
- vue可以检测对象内部的变化,但是vue提供的watch默认不可以
监视属性简写
numbers(newValue,oldValue){
console.log("numbers被修改了"+newValue+"---"+oldValue);
},
3.watch和computed的区别
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script src="../static/js/vue.js"></script>
<body>
<div id="root">
姓:<input type="text" v-model="firstName"/><br/>
名:<input type="text" v-model="latsName"/><br/>
<h1>{{ fullName }}</h1><br/>
</div>
<script>
new Vue({
el: "#root",
data: {
firstName: "张",
latsName: "三",
fullName:"张-三"
},
watch: {
firstName(newValue){
//箭头函数没有this 往外找 找到了vue管理的firstName函数 所以当前this是vue
setTimeout(()=>{
this.fullName = newValue + "-" + this.latsName;
},2000);
},
latsName(newValue){
this.fullName = this.firstName + "-" + newValue;
},
},
})
</script>
</body>
</html>
区别
- 计算属性可以完成功能的监视属性都可以完成
- 监视属性可以完成的功能 计算属性未必完成 计算属性- 异步操作
样式绑定
1.:class的绑定
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script src="../static/js/vue.js"></script>
<style>
.basic{
width: 400px;
height: 100px;
border: 1px solid black;
}
.happy{
border: 4px solid red;;
background-color: rgba(255, 255, 0, 0.644);
background: linear-gradient(30deg,yellow,pink,orange,yellow);
}
.sad{
border: 4px dashed rgb(2, 197, 2);
background-color: gray;
}
.normal{
background-color: skyblue;
}
.onepiece1{
background-color: yellowgreen;
}
.onepiece2{
font-size: 30px;
text-shadow:2px 2px 10px red;
}
.onepiece3{
border-radius: 20px;
}
</style>
<body>
<div id="root">
<!-- 绑定样式 ----- 字符串写法 适用于类名不确定 需要动态的指定 -->
<div class="basic" :class="mood" @click="Mood()">{{name}}</div>
<br/>
<br/>
<!-- 绑定样式 ----- 数组写法 适用于绑定的个数不确定 名字不确定 -->
<div class="basic" :class="arrMood">{{name}}</div>
<br/>
<br/>
<!-- 绑定样式 ----- 对象写法 适用于绑定的个数确定 名字确定 但要动态的决定要不要 -->
<div class="basic" :class="objectMood">{{name}}</div>
<br/>
<br/>
<!-- 绑定样式 ----- 对象写法 -->
<div class="basic" :style="objectStyle">{{name}}</div>
<br/>
<br/>
<!-- 绑定样式 ----- 数组写法 -->
<div class="basic" :style="arrStyle">{{name}}</div>
</div>
<script>
new Vue({
el: "#root",
data: {
name: "One Piece",
mood: "normal",
arrMood:['onepiece1','onepiece2','onepiece3'],
objectMood:{
onepiece1:true,
onepiece2:false,
},
objectStyle:{
fontSize: '50px',
color: 'red',
},
arrStyle:[
{fontSize:'40px'},
{color:'yellow'},
],
},
methods: {
Mood(){
const arr=['happy','sad','normal'];
const index = Math.floor(Math.random()*3);
this.mood=arr[index];
},
},
});
</script>
</body>
</html>
渲染
1.条件渲染
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script src="../static/js/vue.js"></script>
<body>
<div id="root">
<h2>现在index的值为:{{index}}</h2>
<button @click="index++">按钮加+</button>
<!--
v-show
<h3 v-show="index===1">蒙奇.D.路飞</h3>
<h3 v-show="index===2">罗罗诺亚.索隆</h3>
<h3 v-show="index===3">文斯莫克.山治</h3>
-->
<!--
v-if
<h3 v-if="index===1">蒙奇.D.路飞</h3>
<h3 v-if="index===2">罗罗诺亚.索隆</h3>
<h3 v-if="index===3">文斯莫克.山治</h3>
-->
<!--
v-if
v-if-else
<h3 v-if="index===1">蒙奇.D.路飞</h3>
<h3 v-else-if="index===1">罗罗诺亚.索隆</h3>
<h3 v-else-if="index===3">文斯莫克.山治</h3>
-->
<!-- template配合v-if使用 -->
<template v-if="index===3">
<h3>蒙奇.D.路飞</h3>
<h3>罗罗诺亚.索隆</h3>
<h3>文斯莫克.山治</h3>
</template>
</div>
<script>
new Vue({
el: "#root",
data:{
index:0,
},
});
</script>
</body>
</html>
总结
-
v-if
写法
-
v-if='表达式'
-
v-else='表达式'-if
-
v-else='表达式'
适用于:切换频率较低的场景
特点:不展示的DOM直接移除
注意:v-if可以和v-else-if和v-else配合使用 但结构不能被打断
-
-
v-show
写法:v-show='表达式'
适用于:切换频率较高的场景
特点:不展示的DOM不移除而是隐藏
-
使用v-if时 元素可能无法获取 而使用v-show一定能获取到
2.列表渲染
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script src="../static/js/vue.js"></script>
<style>
#root>ul>li{
font-size: 20px;
color: green;
list-style-type: none;
text-align: center;
}
</style>
<body>
<div id="root">
<ul>
<!--遍历数组-->
<li v-for="(p,index) in persons">
{{index}}-{{p.name}}-{{p.sex}}
</li>
<hr />
<!--遍历对象-->
<li v-for="(value,key) of car">
{{key}}:{{value}}
</li>
<hr/>
<!--遍历字符串-->
<li v-for="(value,key) of Luffy">
{{key}}:{{value}}
</li>
<hr/>
<!--遍历数字-->
<li v-for="(value,key) of 10">
{{key}}:{{value}}
</li>
</ul>
</div>
<script>
new Vue({
el: '#root',
data: {
persons:[
{id:001,name:'蒙奇.D.路飞',sex:'男'},
{id:002,name:'罗罗诺亚.索隆',sex:'男'},
{id:003,name:'文斯莫克.山治',sex:'男'},
],
car:{
name:'万里阳光号',
type:'船',
money:'$100亿贝利',
},
Luffy:"I'm Luffy, I'm the man who wants to be the pirate king",
},
});
</script>
</body>
</html>
总结
- 用于展示列表数据
- 语法:v-for="(item,index) in 遍历的数组"
3.key作用以及原理
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script src="../static/js/vue.js"></script>
<style>
#root>ul>li{
font-size: 20px;
color: green;
list-style-type: none;
text-align: center;
}
</style>
<body>
<div id="root">
<ul>
<button @click="add">添加</button>
<!--遍历数组-->
<li v-for="(p,index) in persons" :key="p.id">
{{index}}-{{p.name}}-{{p.sex}}
<input type="text"/>
</li>
</ul>
</div>
<script>
new Vue({
el: '#root',
data: {
persons:[
{id:001,name:'蒙奇.D.路飞',sex:'男'},
{id:002,name:'罗罗诺亚.索隆',sex:'男'},
{id:003,name:'文斯莫克.山治',sex:'男'},
],
},
methods: {
add(){
const p = {id:'004',name:'娜美',sex:'女'};
this.persons.unshift(p);
},
},
});
</script>
</body>
</html>
总结
面试题:react、vue中的key有什么作用?(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是没有问题的
4.列表过滤
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script src="../static/js/vue.js"></script>
<style>
#root>ul>li{
font-size: 20px;
color: green;
list-style-type: none;
}
</style>
<body>
<div id="root">
<ul>
<input type="text" v-model="keyModel"/>
<!--遍历数组-->
<li v-for="(p,index) in filterArrs" :key="p.id">
{{index}}-{{p.name}}-{{p.sex}}
</li>
</ul>
</div>
<script>
new Vue({
el: '#root',
data: {
persons:[
{id:001,name:'蒙奇D路飞',sex:'男'},
{id:002,name:'哥儿D艾斯',sex:'男'},
{id:003,name:'哥儿罗杰',sex:'男'},
{id:003,name:'杰斯',sex:'男'},
],
keyModel:'',
filterArr: [],
},
//监视属性
// watch:{
// keyModel:{
// immediate:true,
// handler(newValue){
// this.filterArr = this.persons.filter((p)=>{
// return p.name.indexOf(newValue)!==-1;
// });
// },
// },
// },
//计算属性
computed:{
// 初始化的时候调用 依赖的数据发生变化再次调用
filterArrs(){
return this.persons.filter((p)=>{
return p.name.indexOf(this.keyModel) !== -1;
})
}
},
});
</script>
</body>
</html>
列表排序
computed:{
// 初始化的时候调用 依赖的数据发生变化再次调用
filterArrs(){
const arr = this.persons.filter((p)=>{
return p.name.indexOf(this.keyModel) !== -1;
})
arr.sort((p1,p2)=>{
if(this.sortType){
return this.sortType !== 1 ? p1.id-p2.id : p2.id-p1.id
}
})
return arr
}
},
数据监视
1.数据监视
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Vue数据监视</title>
<style>
button{
margin-top: 10px;
}
</style>
<script type="text/javascript" src="../static/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:'娜美',
age:18,
hobby:['抽烟','喝酒','烫头'],
friends:[
{name:'索隆',age:35},
{name:'路飞',age:36}
]
}
},
methods: {
addSex(){
Vue.set(this.student,'sex','女');
},
addFriend(){
this.student.friends.unshift({name:'乌索普',age:19});
},
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((smk)=>{
// 过滤掉抽烟 不等于抽烟的全部返回
return smk!=='抽烟'
})
},
}
})
</script>
</html>
Vue监视数据的原理
vue会监视data中所有层次的数据
如何监测对象中的数据?
-
通过setter实现监视,且要在new Vue时就传入要监测的数据
-
对象中后追加的属性,Vue默认不做响应式处理
-
如需给后添加的属性做响应式,请使用如下API:
Vue.set(target,propertyName/index,value)
vm.$set(target,propertyName/index,value)
如何监测数组中的数据
通过包裹数组更新元素的方法实现,本质就是做了两件事:
- 调用原生对应的方法对数组进行更新
- 重新解析模板,进而更新页面
- 在Vue修改数组中的某个元素一定要用如下方法:
//使用APl
push()、pop()、shift()、unshift()、splice()、sort()、reverse()
Vue.set() 或 vm.$set()
特别注意:Vue.set() 和 vm.$set() 不能给vm 或 vm的根数据对象(data等) 添加属性
表单数据
1.收集表单数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script src="../static/js/vue.js"></script>
<style>
*{
margin-top: 20px;
}
</style>
<body>
<div id="root">
<form @submit.prevent="demo">
账号:<input type="text" v-model.trim="user.username">
<br/>
密码:<input type="password" v-model="user.password">
<br/>
<!-- 虽然v-model默认绑定的是value 但是要手动写value的值 -->
性别:<input type="radio" v-model="user.sex" value="男">男
<input type="radio" v-model="user.sex" value="女">女
<br>
<!-- vue实例接收要用数组 还是要手动写value -->
爱好:<input type="checkbox" v-model="user.hobby" value="海贼王">海贼王
<input type="checkbox" v-model="user.hobby" value="火影忍者">火影忍者
<input type="checkbox" v-model="user.hobby" value="鬼灭之刃">鬼灭之刃
<br/>
所属校区:
<select v-model="user.city">
<option value="">请选择校区</option>
<option value="dong">东海</option>
<option value="xi">西海</option>
<option value="bei">北海</option>
<option value="nan">南海</option>
</select>
<br>
其他信息:
<textarea v-model.lazy="user.textform"></textarea>
<br>
<br>
<input type="checkbox" v-model="user.public">阅读并接受<a href="http://www.bilibili.com">《用户协议》</a>
<br>
<input type="submit" value="提交">
</form>
</div>
<script>
new Vue({
el: "#root",
data: {
user:{
username: '',
password: '',
sex: '男',
hobby: [],
city:'dong',
textform: '',
public: 'true',
},
},
methods: {
demo(){
console.log(JSON.stringify(this.user));
}
},
});
</script>
</body>
</html>
收集表单数据:
若:<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组成的数组
v-model的三个修饰符:
lazy:失去焦点后再收集数据
number:输入字符串转为有效的数字
trim:输入首尾空格过滤
过滤器
1.过滤器
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>过滤器</title>
</head>
<script type="text/javascript" src="../static/js/vue.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.10.6/dayjs.min.js"></script>
<body>
<div id="root">
<h2>时间</h2>
<h3>当前时间戳:{{time}}</h3>
<h3>转换后时间:{{time | timeFormater()}}</h3>
<h3>转换后时间:{{time | timeFormater('YYYY-MM-DD HH:mm:ss')}}</h3>
<h3>截取年月日:{{time | timeFormater() | mySlice}}</h3>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false
//全局过滤器
Vue.filter('mySlice',function(value){
return value.slice(0,11)
})
new Vue({
el:'#root',
data:{
time:1626750147900,
},
//局部过滤器
filters:{
// str当str不传参是默认就是"YYYY年MM月DD日 HH:mm:ss 如果传入参数就按参数的格式来
timeFormater(value, str="YYYY年MM月DD日 HH:mm:ss"){
return dayjs(value).format(str)
}
}
})
</script>
</html>
事件转换的js文件
<script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.10.6/dayjs.min.js"></script>
过滤器
-
定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)。
-
语法:
-
注册过滤器:Vue.filter(name,callback) 或 new Vue{filters:
-
使用过滤器:{{ xxx | 过滤器名}} 或 v-bind:属性 = "xxx | 过滤器名"
- 备注:
- 过滤器可以接收额外参数,多个过滤器也可以串联
- 并没有改变原本的数据,而是产生新的对应的数据
内置指令
1.v-text指令
目前学过的指令
- v-bind 单项绑定表达式
- v-model 双向数据绑定
- v-on 绑定事件
- v-for 遍历对象、数组、字符串
- v-if (条件渲染)动态控制节点是否存在
- v-else (条件渲染)动态控制节点是否存在
- v-show (条件渲染)动态控制节点是否展示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script src="../static/js/vue.js"></script>
<body>
<div id="root">
<div>{{name}}</div>
<div v-text="name">onepiece</div>
</div>
<script>
new Vue({
el: "#root",
data: {
name: "海贼王",
},
});
</script>
</body>
</html>
v-text指令总结
- 向其所在的节点中渲染文本内容
- 于插值语法的区别 v-text会替换节点中的文本 插值语法不会
2.v-html指令
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script src="../static/js/vue.js"></script>
<body>
<div id="root">
<div v-html="h3">onepiece</div>
<div v-html="a">onepiece</div>
</div>
<script>
new Vue({
el: "#root",
data: {
h3: "<h3>我是h3标签</h3>",
a: "<a href='https://bilibili.com?'+document.cookie>点击</a>",
},
});
</script>
</body>
</html>
v-html指令总结
- 作用
- 向指定节点渲染包含html结构的内容
- 与插值语法的区别
-
v-html会替换节点中所以的内容 {{}}插值语法不会
-
v-html结构会识别html结构
- v-html有安全性问题
-
在网站上动态渲染HTML是非常危险的 容器导致xss攻击
-
一定在可信的内容上使用v-html 不要用在用户提交的内容上
3.v-cloak指令
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script src="../static/js/vue.js"></script>
<style>
[v-cloak]{
display: none;
}
</style>
<body>
<div id="root">
<div v-cloak>{{name}}</div>
</div>
<script>
new Vue({
el: "#root",
data: {
name: "海贼王",
},
});
</script>
</body>
</html>
v-cloak指令总结(没有值)
- 本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性
- 使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题
4.v-once指令
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script src="../static/js/vue.js"></script>
<body>
<div id="root">
<h1 v-once>n的初始值为:{{n}}</h1>
<h1>n的值为:{{n}}</h1>
<button @click="n++">n+1</button>
</div>
<script>
new Vue({
el: "#root",
data: {
n: 1,
},
});
</script>
</body>
</html>
v-once指令总结(没有值)
-
v-once所在节点在初次动态渲染后,就视为静态内容了
-
以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能
5.v-pre指令
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script src="../static/js/vue.js"></script>
<body>
<div id="root">
<h1 v-pre>蒙奇.D.路飞</h1>
<h1 v-pre>{{name}}</h1>
</div>
<script>
new Vue({
el: "#root",
data: {
name: "海贼王",
},
});
</script>
</body>
</html>
v-pre指令总结(没有值)
- 跳过其所在节点的编译过程。
- 可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译
自定义指令
1.函数式指令
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script src="../static/js/vue.js"></script>
<body>
<div id="root">
<h1>当前n的值:{{n}}</h1>
<h1>n的10倍值:<span v-big="n"> </span></h1>
<button @click="n++">n+1</button>
</div>
<script>
new Vue({
el: "#root",
data: {
n:1,
},
directives: {
//big函数什么时候调用 指令与元素绑定成功时 指令所在的模板被重新解析时
big(element,bigding){
console.log(element,bigding),
element.innerText=(bigding.value)*10
}
}
});
</script>
</body>
</html>