文章目录
第2章:vue2基础 – 指令
2.1如何使用vue
如何使用Vue:
1、引入Vue的核心JS文件
2、准备Dom结构
3、实例化组件
通过el属性,挂载元素,绑定id为app的html元素
通过data属性,定义数据,可以在html代码段中显示的数据
4、获取数据
数据绑定最常见的形式就是使用“Mustache”语法 (双大括号) 的文本插值
2.2vue模板语法
<div id="app">
<h1>插值语法</h1>
<h1>{{name}}-{{address}}</h1>
<hr>
<h1>指令语法</h1>
<a v-bind:href="url">点我跳转百度</a>
<a :href="url"></a>
</div>
2.3文本渲染 (都是针对标签属性)
2.3.1 v-text
注意点1:v-text=’msg’会拿msg的值替换标签体的值,换句话说如果设置了v-text标签且无论msg是否为空,那么标签体的内容“你好”就失效了,不会显示
比如data中msg值为Hello World,那么页面会显示Hello World,如果msg=’ ’值为空,那么h3整个标签都不会显示,更不会显示标签体内容“你好”
<h3 v-text=’msg’>你好</h3>
2.3.2 v-once
注意点1:切记不要弄混了文本渲染v-once和事件修饰符的.once
文本渲染v-once:指页面只渲染一次
事件修饰符的.once:指的是方法只调用一次有效
2.3.3 v-html
注意点1(重点关注):使用v-html存在安全隐患,比如下面图片举例说明,str2是一个黄色钓鱼网址链接,如果使用v-html,那么会解析标签内容结构到页面上变成一个链接,如果用户点击了该链接,那么恶意网站就能获取用户登录cookie(cookie包含了你的用户名密码),那么恶意网站就会做坏事了,比如盗号、恶意转账盗钱等。所以为了避免安全隐患,请谨慎使用v-html标签,如果你确定代码部分是安全的,不会有乱七八糟的东西,那么使用v-html标签也没事。而v-text就不会解析html元素,就不会把str2变成链接地址,这样因为跳转不了,恶意软件也就无法获取用户cookie 了,也就做到了避免安全隐患。
2.4数据绑定
v-bind 指令可以绑定元素的属性,动态给属性赋值。比如: v-bind:class、
v-bind:style、 v-bind:href 形式。
注意点1:v-bind标签不仅可以传属性值,还可以传方法
v-bind:是单项绑定,下图中黄线存在,粉线不存在
注意点2:总结:v-bind单向绑定 v-model双向绑定
v-model只能用于表单元素,换句话说只作用于有value属性的标签(表单元素)
2.5el和data两种写法
说明点1:el两种用哪个都可以,但是data两种方式分情况,后续使用组件,data使用方式必须使用“函数式”,不然会报错。
data写法函数式的普通方式:data:function () {}
data:function () {
console.log('@@@',this) //指代vue对象
return{
name:"尚硅谷",
address:"哈尔滨",
}
}
data写法函数式的简化普通方式:data() {}
data() {
console.log('@@@',this) //指代vue对象
return{
name:"尚硅谷",
address:"哈尔滨",
}
}
data的第二种写法箭头函数式:data:()=> {}
data:()=> {
console.log('@@@',this) //指代window对象
return{
name:"尚硅谷",
address:"哈尔滨",
}
}
针对函数式,箭头函数方式this指代window对象,普通方式this指代vue对象
2.6MVVM模型
2.7数据代理
2.7.1回顾Object.defineProperty()
回顾Object.defineProperty()方法,该方法可动态设置属性。
defineProperty(目标对象, key, {config})
注意点1:defineProperty中如果定义使用get()和set(),那么属性value和writable:true必须注释掉,不然报错
注意点2:如果defineProperty中只定义value属性,那么控制台赋值无效,即必须设置writable:true才能对person属性实现更新
let number = 18
let person = {
name:"张三",
sex:"男"
}
Object.defineProperty(person, "age", {
value:18,
}
如果defineProperty()方法设置属性enumerable:true、writable:true、configurable:true就可实现跟局部定义变量属性一样的效果,可增删改
Object.defineProperty(person, "age", {
value:18,
enumerable:true, //控制属性是否可以枚举(也就是是否可以遍历访问到),默认值是false
writable:true, //控制属性是否可以被修改,默认值是false
configurable:true, //控制属性是否可以被删除,默认值是false
}
defineProperty()方法定义get()和set()
Object.defineProperty(person, "age", {
//当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值
get() {
console.log('有人读取age属性了')
return number
},
// //当有人修改person的age属性时,set函数(setter)就会被调用,且会收到修改的具体值
set(value) {
console.log('有人修改age属性了')
number = value
}
})
2.7.2何为数据代理
数据代理:通过一个对象代理对另一个对象中属性的操作(读/写)
let obj = {x:100}
let obj2 = {y:200}
Object.defineProperty(obj2, "x", {
get() {
return obj.x
},
set(value) {
obj.x = value
}
})
2.7.3vue中的数据代理
问题:数据代理干了啥?
答案:
简单说:通过Object.defineProperty()方法把data对象所有属性添加到vm(Vue原型)对象上,且为每个属性指定一个getter/setter。
复杂说:首先vue把data对象所有属性添加到命名为_data的对象中,通过Object.defineProperty()方法把_data对象所有属性添加到vm(Vue原型)对象上,并为每一个添加到vm上的属性,都指定一个getter/setter,这样vm对象就有了属性name和address,不然你想操作属性只能使用_data.name_或者data.address,这样很不方便。
2.8事件处理
2.8.1事件的基本使用
注意点1:定义事件函数时,普通函数this指代vue对象,而箭头函数中this指代Window对象。
注意点2:定义事件没参数小括号()可省略,但是用在插值表达式使用一个函数返回值就必须带小括号(),比如 全名:{{fullName()}}。
注意点3:不被vue所管理的函数那么请使用箭头函数。
代码:
<button v-on:click="showInfo1">点我提示信息1(不传参)</button>
<button @click="showInfo2($event, 66)">点我提示信息2(不传参)</button>
var vm = new Vue({
el: "#app",
data: {},
methods:{
showInfo1(event) {
console.log(event);
},
showInfo2(event, number) {
console.log(event); //指代事件对象
console.log(number);
console.log(this); //箭头函数中指代Window对象,普通方法指代vue对象
}
}
})
2.8.2 $event 对象
在事件处理函数中访问 DOM 原生事件 event 对象,可以使用特殊变量$event 对象传
入。
2.8.3事件的修饰符
事件修饰符举例说明:
1.默认<a>标签会跳转,想实现点击不跳转就设置@click.prevent=”事件函数”或者<a href="javascript:void(0);" >
2.阻止事件冒泡
捕获阶段:指由外往内
冒泡阶段:指由内到外
举例:2个div1,div2,都有点击事件,如果不设置事件修饰符stop,那么点击div2触发事件完成之后,还会触发div1事件,而设置stop修饰符后,不会触发冒泡阶段。
3.once:事件只触发一次(常用),即无论点击多少次按钮,按钮只触发一次。
4.capture:设置使用事件的捕获模式,不设置使用冒泡模式(由内向外触发事件函数);
使用事件的捕获模式 :不设置.capture,先执行showMsg(2),再执行showMsg(1),设置之后先执行showMsg(1),再执行showMsg(2)
<div class="box1" @click.capture="showMsg(1)">
div1
<div class="box2" @click="showMsg(2)">
div2
</div>
</div>
showInfo(e){
console.log(e.target)
}
5.self:只有event.target是当前操作的元素时才触发事件
举例:div和button都设置事件函数,如果div标签不设置.self,那么点击button按钮会调用2次函数,且输出event.target为:<button>点我提示信息</button>,如果div标签设置了.self那么只有点击div才会触发事件且输出event.target为:<div class="demo1"><button>点我提示信息</button></div>,而只点击button只会触发button的事件且输出event.target为:<button>点我提示信息</button>。
<div class="demo1" @click.self="showInfo">
<button @click="showInfo">点我提示信息</button>
</div>
6.passive:事件的默认行为立即执行,无需等待事件回调执行完毕
举例:定一个事件会计算10W次,如果不设置.passive,那么会等事件全部结束后,滚轮才会向下移动一个位置,而设置了.passive,那么滚轮会先移动而不会去等待事件执行是否结束。
<ul @wheel.passive="demo" class="list">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
demo(){
for (let i = 0; i < 100000; i++) {
console.log('#')
}
console.log('累坏了')
}
2.8.4键盘事件(键值修饰符)
两个隐藏小知识点:
1.事件修饰符和串行,比如:@click.stop.once
2.对于键盘按键想实现按Ctrl+y才调用,则使用@keyup.ctrl.y=”showInfo”
2.9条件渲染
注意点1:使用v-if和v-else-if和v-else时中间不可以中断,否则无效,比如:
注意点2:
假设我有3个<h2>标签想实现条件渲染,有3种方式可以实现并说明不同优缺点
方式1:<h2>标签加条件,缺点:太重复了
方式2:3个<h2>标签外绑定div条件控制,缺点:div也得知晓并设置样式,否则<h2>有样式而被div包裹后样式没了,即会改变结构
方式3(推荐):使用<template>标签,元素加载解析时会自动去掉<template>标签只保留<h2>标签,即不会改变结构,注意:<template>标签中只可以使用v-if,不能使用v-show,否则报错
2.10列表渲染
锚点
2.10.1 v-for
<li v-for="item in items">{{item.name}}</li>
列表渲染
v-for
可以把一组值进行列表渲染,语法形式: item in items,
items 是源数据数组并且 item 是数组元素迭代的别名。
在 v-for 块中,对父作用域属性的完全访问权限。v-for 还支持一个可选的第二个参数为当前项的索引。
v-for也可以遍历对象,可以指定三个形参:
形式: v-for="(value, key, index) in object"
value: 对象的值
key: 对象的键
index: 遍历的索引
2.10.2 key 属性(非常重要)
用 v-for 渲染列表时, 使用 key 属性给每个指定一个唯一的 ID 表示,那么可以在
下次数据渲染时,提高渲染速度。
<li v-for="item in items" :key="item.id">{{item.name}}</li>
注意:在 v-for 中:key非常重要,推荐每次都写:key
举例说明:默认存在3个标签且有值,有一个按钮效果是在最上面新增一行标签,此时会容易发生问题
点击按钮前:
点击按钮后:
结果:顺序乱了?详细原因如下图,对比相同就复用,对比不同就重新生成DOM
注意点1:默认不写:key时,解析DOM会自动加上数组index
注意点2::key最好绑定数据唯一标识,身份证、手机号、库表id等,这样无论在数组什么位置插入,哪怕是数组开头或者数组结尾,都不会影响结构。
注意点3:虚拟DOM存在于内存中,而用户操作的页面标签属于真实DOM
2.10.3 取值范围
v-for 也可以指定整数,用来重复多次使用模板。
<li v-for="i in 5">第 {{i}} 次</li>
2.10.4列表过滤
举例:针对
注意点1:列表过滤使用.filter(),它和自定义过滤器不是同一个东西。
列表过滤器.filter()用在方法中,而自定义过滤器用在插值表达式和 v-bind 表达式中。
注意点2:.filter会生成新数据,不会修改原数据结构。
注意点3:如果computed和watch两种方式都可以实现,推荐优先使用计算属性computed
方式一:computed
<div id="root">
<h2>人员列表</h2>
<input type="text" placeholder="请输入名字" v-model="keyWord">
<ul>
<li v-for="(p,index) of filPerons" :key="index">
{{p.name}}-{{p.age}}-{{p.sex}}
</li>
</ul>
</div>
new Vue({
el:'#root',
data:{
keyWord:'',
persons:[
{id:'001',name:'马冬梅',age:19,sex:'女'},
{id:'002',name:'周冬雨',age:20,sex:'女'},
{id:'003',name:'周杰伦',age:21,sex:'男'},
{id:'004',name:'温兆伦',age:22,sex:'男'}
]
},
computed:{
filPerons(){
return this.persons.filter((p)=>{
return p.name.indexOf(this.keyWord) !== -1
})
}
}
})
方式二:watch
new Vue({
el:'#root',
data:{
keyWord:'',
persons:[
{id:'001',name:'马冬梅',age:19,sex:'女'},
{id:'002',name:'周冬雨',age:20,sex:'女'},
{id:'003',name:'周杰伦',age:21,sex:'男'},
{id:'004',name:'温兆伦',age:22,sex:'男'}
],
filPerons:[]
},
watch:{
keyWord:{
immediate:true,
handler(val){
this.filPerons = this.persons.filter((p)=>{
return p.name.indexOf(val) !== -1
})
}
}
}
})
2.10.5列表排序
注意点1:列表排序使用.sort()方法,其中sort(参数1,参数2)有两个参数,参数2-参数1为降序,参数1-参数2为升序,具体查看。
https://blog.csdn.net/weixin_46665162/article/details/112966823
注意点2:会引起自身数据的改变。
举例:对列表过滤的数据进行升降序
注意点3:.sort()方法会更改原数据结构,比如更改原数组顺序
<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) of filPerons" :key="p.id">
{{p.name}}-{{p.age}}-{{p.sex}}
<input type="text">
</li>
</ul>
</div>
new Vue({
el:'#root',
data:{
keyWord:'',
sortType:0, //0原顺序 1降序 2升序
persons:[
{id:'001',name:'马冬梅',age:30,sex:'女'},
{id:'002',name:'周冬雨',age:31,sex:'女'},
{id:'003',name:'周杰伦',age:18,sex:'男'},
{id:'004',name:'温兆伦',age:19,sex:'男'}
]
},
computed:{
filPerons(){
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
}
}
})
2.10.6 Vue监测“对象”数据改变的原理
注意点1:vue监测数据原理就是,给每个data属性添加get()和 set()方法,即data属性改变 =》调用set() =》 重新渲染页面值改变。
注意点2:加载流程:
1)加载data属性,加工封装get()和 set()方法
2)vue._data=data,这样控制台点开vue实例就会看到一堆属性及方法了
举例:模拟data对象属性值改变了,页面值也跟着改变,即实现vue监测数据改变效果
let data = {
name:'尚硅谷',
address:'北京',
}
//第1步:创建一个监视的实例对象,用于监视data中属性的变化
const obs = new Observer(data)
console.log(obs)
//第2步:准备一个vm实例对象
let vm = {}
vm._data = data = obs
//第3步:定义观察者函数
function Observer(obj){
//汇总对象中所有的属性形成一个数组
const keys = Object.keys(obj)
//遍历
keys.forEach((k)=>{
Object.defineProperty(this,k,{ //this指代观察者对象,而不是vue实例
get(){
return obj[k]
},
set(val){
console.log(`${k}被改了,我要去解析模板,生成虚拟DOM.....我要开始忙了`)
obj[k] = val
}
})
})
}
2.10.7 Vue.set()或者vm.$set()动态新增标签
锚点
Vue.set()和vm.$set() =》 相同效果。
主要讲解Vue.set()方法是什么?
注意点 1:Vue.set()方法有局限性,不能给vue实例或者data的直接属性进行添加,只能作用于data下面的某个属性对象。
<body>
<!-- 准备好一个容器-->
<div id="root">
<h1>学校信息</h1>
<h2>学校名称:{{school.name}}</h2>
<h2>学校地址:{{school.address}}</h2>
<h2>校长是:{{school.leader}}</h2>
<hr/>
<h1>学生信息</h1>
<button @click="addSex">添加一个性别属性,默认值是男</button>
<h2>姓名:{{student.name}}</h2>
<h2 v-if="student.sex">性别:{{student.sex}}</h2>
<h2>年龄:真实{{student.age.rAge}},对外{{student.age.sAge}}</h2>
<h2>朋友们</h2>
<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:{
school:{
name:'尚硅谷',
address:'北京',
},
student:{
name:'tom',
age:{
rAge:40,
sAge:29,
},
friends:[
{name:'jerry',age:35},
{name:'tony',age:36}
]
}
},
methods: {
addSex(){
// Vue.set(this.student,'sex','男')
this.$set(this.student,'sex','男')
}
}
})
</script>
2.10.8Vue监测“数组”数据改变的原理
问题1:vue实例对象针对数组元素并没有提供类似get和set方法,为啥也会实现页面响应式监听?
答案:因为vue对数组的部分基本方法进行了二次封装,在继承方法的使用效果同时,也进行了响应式更新DOM。
<div id="root">
<h2>爱好</h2>
<ul>
<li v-for="(h,index) in student.hobby" :key="index">
{{h}}
</li>
</ul>
</div>
const vm = new Vue({
el:'#root',
data:{
student:{
hobby:['抽烟','喝酒','烫头']
}
}
})
2.10.9总结vue数据监测
问题:什么叫数据劫持?
定义:指的是在访问或者修改对象的某个属性时,通过一段代码拦截这个行为,进行额外的操作或者修改返回结果。比如:拦截data各属性,添加额外的get和set方法到vue实例的_data对象中。
2.11 表单输入绑定
锚点
用 v-model 指令在表单控件元素上创建双向数据绑定。它会根据控件类型自动选取
正确的方法来更新元素。
小技巧:
1.针对input输入框想实现点击名字,光标自动定位到输入框,label设置for属性和input设置id属性即可
<label for="account">账号:</label>
<input type="text" id="account" v-model.trim="userInfo.account"> <br/><br/>
2.针对radio想实现二选一,需要设置相同name属性值,同时配置value值
3.针对radio或者select标签想实现“默认选中”,不用设置checked,只需要设置data中属性值即可
4.表单提交方式
方式1:button绑定事件
<button @click=”xx”></button>
--------------------------------------------------------------------------------------------
方式2:<form>标签设置<form @submit.prevent="demo">
5.阻止表单提交后刷新页面操作,使用事件修饰符.prevent
6.form表单提交中如何一口气获取全部数据打印输出?
方式1:定义对象接收全部参数
new Vue({
el:'#root',
data:{
userInfo:{
account:'',
password:'',
age:18,
sex:'female',
hobby:[],
city:'beijing',
other:'',
agree:''
}
}
console.log(JSON.stringify(this.userInfo))
--------------------------------------------------------------------------------------------
方式2:使用this._data,虽说this._data除了属性还有get和set方法,但是打印的时候不会输出这些,并不影响。
console.log(JSON.stringify(this._data))
7.针对年龄标签,防止输入字母,或者防止默认是数字但重新输入后传值为字符串,需同时设置type=”number”和v-model.number
<input type="number" v-model.number="userInfo.age">
8.针对checkbox注意点1,考虑是否需要配置input标签的value值,比如:如果是爱好等多选就需要设置;如果是是否同意协议等check标签就不需要设置
9.针对checkbox注意点2,data属性值默认设置字符串和数组效果时不一样的
2.11.1 文本 text
2.11.2 复选框
单个使用时 v-model 是逻辑值: true 和 false,多个一起使用需要指定 value 值,
选中结果绑定 v-model 的数组。
2.11.3 单选框
2.11.4选择列表
2.11.5修饰符
2.12计算属性与监听属性
2.12.1计算属性computed
注意点1:只要data任意值发生改变,vue肯定会重新解析模板。比如{{fullName()}},插值表达式使用fullName()函数,那么当vue重新解析模板时,就会重新执行一遍fullName()函数,因为data任意值改变了,vue也不知道fullName()函数中是否引用了data中改变的属性,所以会选择直接重新执行一遍fullName()函数。
注意点2:默认提供了缓存机制,实际上计算属性就是调用了fullName的get()方法,get什么时候调用?1.初次读取fullName时 2.所依赖的数据发生变化时。
注意点3:既然fullName是个对象,那我插值表达式可以使用{{fullName.get()}}?
答案:不能这样使用,只有data配置和methods配置可以调用,计算配置不能这么调用,会报错fullName中get()方法不存在。
注意点4:methods定义的方法,在插值表达式使用要加(),{{fullName()}},如果是计算属性中监听的属性,则写成{{fullName}}
举例:计算“全名”标签,由“姓-名”构成
思路:
方式1:用插值表达式拼,(缺点:万一对字符串进行分割、转换大小写、截取长度等等操作显得表达式太长,不易解读)
全名:{{firstName}}-{{lastName}}
方式2:定义函数写在methods配置中(缺点:不提供缓存,有几个fullName()调用就会执行几次)
全名:
{{fullName()}}
全名:
{{fullName()}}
方式3:定义计算属性(推荐使用,有缓存),代吗如下↓
全名:<span>{{fullName}}</span> <br/><br/>
computed:{
fullName:{
//get有什么作用?当有人读取fullName时,get就会被调用,且返回值就作为fullName的值
//get什么时候调用?1.初次读取fullName时。2.所依赖的数据发生变化时。
get(){
console.log('get被调用了')
// console.log(this) //此处的this是vm
return this.firstName + '-' + this.lastName
},
//set什么时候调用? 当fullName被修改时。
set(value){
console.log('set',value)
const arr = value.split('-')
this.firstName = arr[0]
this.lastName = arr[1]
}
}
}
2.12.2(简写)计算属性
注意点1:计算属性只有在没有set方法时才能使用简写
注意点2:
问题:插值表达式中使用data配置、methods配置和计算配置时,区分何时带()?何时不能带()?
答案:
针对data配置都不带()
针对methods配置有形参带(),没有形参()可省略
针对计算配置也不带(),带()会报错
全名:<span>{{fullName}}</span> <br/><br/>
computed:{
//完整写法
fullName:{
get(){
console.log('get被调用了')
return this.firstName + '-' + this.lastName
},
set(value){
console.log('set',value)
const arr = value.split('-')
this.firstName = arr[0]
this.lastName = arr[1]
}
}
//简写
fullName(){
console.log('get被调用了')
return this.firstName + '-' + this.lastName
}
}
2.12.3计算属性-天气案例
该案例为了讲述1个坑,1个技巧
<div id="root">
<h2>今天天气很{{info}}</h2>
<!-- 绑定事件的时候:@xxx="yyy" yyy可以写一些简单的语句 -->
<!-- <button @click="isHot = !isHot">切换天气</button> -->
<button @click="changeWeather">切换天气</button>
</div>
const vm = new Vue({
el:'#root',
data:{
isHot:true,
},
computed:{
info(){
return this.isHot ? '炎热' : '凉爽'
}
},
methods: {
changeWeather(){
this.isHot = !this.isHot
}
},
})
注意点1:(1个坑指的是),假设页面显示的是“今天天气很好”,也就是页面压根没用到info属性,而代码中却定义了计算属性及方法,那么会发生的坑是,点击按钮后Vue插件显示结果没变动,但是实际控制台info结果已经改变了,也就是说因为页面没用到属性所以插件就不更新值了,但是实际info值已经改变了。
注意点2:(1个技巧指的是),假设定义方法逻辑很简单,可以直接这样写@click=“isHot = !isHot”,也是生效的。
2.12.4监听属性watch
写法1:.new Vue是配置
const vm = new Vue({
watch:{
isHot:{
immediate:true, //初始化时让handler调用一下
//handler什么时候调用?当isHot发生改变时。
handler(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue)
}
}
}
写法2:首先保证vue实例已经创建完了,在vue实例下面,通过vm.$watch配置
vm.$watch('isHot',{
immediate:true, //初始化时让handler调用一下
//handler什么时候调用?当isHot发生改变时。
handler(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue)
}
})
注意点1:什么场景下使用写法1 和写法2呢?
答案:创建vue实例时已经明确知道监听什么属性时就使用写法1,而如果创建vue实例时不知道监视谁,而是后续根据用户业务行为才知道要监视谁就使用写法2
注意点2:vm.$watch(参数1,参数2)有两个参数,参数2为{}配置对象,参数1表示你要监视的属性名,注意名字要加引号“引号”标识,如果直接写vm.$watch(isHot,参数2)这是错误的,会报如下错误,原因在于写法1中的isHot不会触发“读取变量”,而写法2会触发“读取变量”,所以写法2中属性名必须加“引号”。
2.12.5监听属性watch-深度监听
举例:data配置numbers对象,其中有属性a和b,我想监听numbers,只要numbers中任意属性值改变了,我就打印一条语句。
<h3>a的值是:{{numbers.a}}</h3>
<button @click="numbers.a++">点我让a+1</button>
<h3>b的值是:{{numbers.b}}</h3>
<button @click="numbers.b++">点我让b+1</button>
const vm = new Vue({
el:'#root',
data:{
numbers:{
a:1,
b:1
}
},
watch:{
numbers:{
deep:true, //开启深度监视,监视多级结构中所有属性的变化
handler(){
console.log('numbers改变了')
}
}
}
})
注意点1:默认deep为false,不进行深度监视,这样效率快
注意点2:如果如图1这么写,不配置deep=true的话,那么watch配置会让vue实例监视的是整个numbers的地址,而不是咱们想实现的监视numbers对象内部任意属性值a或者b的变化,因为如图2,watch配置会让vue实例默认监视的是“粉色框”的地址值是否改变,而不是监视“绿色框”中属性a和b的值是否改变,哪怕属性a或者b值改变了,但是numbers对象整体地址没改变,那么被watch配置的vue实例就会觉得监视值未改变,所以如果想实现深度结构监控,请设置deep=true
记住:配置watch是为了作用于vue实例怎么怎么怎么地。
2.12.6监听属性watch-(简写)深度监听
watch和 vm.$watch都有2种写法:
问题:什么情况下使用简写方式?
答案:当监听属性中只用到handler()方法,而没有其他配置(比如immediate或者deep)时,就可以使用简写方式。
watch:{
//正常写法
isHot:{
// immediate:true, //初始化时让handler调用一下
// deep:true,//深度监视
handler(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue)
}
},
//简写
isHot(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue,this)
}
}
-------------------------------------------------------------------------------------------------
//正常写法
vm.$watch('isHot',{
immediate:true, //初始化时让handler调用一下
deep:true,//深度监视
handler(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue)
}
})
-------------------------------------------------------------------------------------------------
//简写
vm.$watch('isHot',function(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue,this)
})
2.12.7计算属性和监视属性区别
举例说明:天气案例
计算属性
data:{
firstName:'张',
lastName:'三'
},
computed:{
info(){
return this.firstName + “-” + this.lastName
}
},
监视属性
data:{
firstName:'张',
lastName:'三',
fullName:'张-三'
},
watch:{
firstName(val){
this.fullName = val + '-' + this.lastName
},
lastName(val){
this.fullName = this.firstName + '-' + val
}
}
区别:
注意点1:如果计算属性computed和监视属性watch都可以实现,推荐使用计算属性,因为代码最少
注意点2:计算属性computed不能使用异步操作,比如睡一秒再执行操作等,而监视属性watch可以进行异步操作
注意点3:为了使用this指代vue对象,那么使用计算属性computed的同步操作,必须写普通函数(因为计算属性computed被vue管理),如果使用监视属性watch的异步操作等(不被vue所管理的函数)那么请使用箭头函数,
(即:
计算属性使用同步操作的普通函数,this => vue,
计算属性使用同步操作的箭头函数,this => window
监视属性使用同步操作的普通函数,this => vue,
监视属性使用同步操作的箭头函数,this => window,
监视属性使用异步操作的普通函数,this => window,
监视属性使用异步操作的箭头函数,this => vue,具体原因看下面图
)。
2.13绑定样式
2.13.1绑定class
data:{
name:'尚硅谷',
mood:'normal',
classArr:['atguigu1','atguigu2','atguigu3'],
classObj:{
atguigu1:false,
atguigu2:false,
}
}
2.13.2绑定style
data:{
styleObj:{
fontSize: '40px',
color:'red',
},
styleObj2:{
backgroundColor:'orange'
},
styleArr:[
{
fontSize: '40px',
color:'blue',
},
{
backgroundColor:'gray'
}
]
}
2.14自定义过滤器
Vue允许自定义过滤器,可被用作一些常见的文本格式化。
过滤器可以用在两个地方:mustache 插值表达式和 v-bind 表达式 (后者从 2.1.0+ 开始支持)。
注意点1:过滤器无形参时,默认也会把前面参数传给过滤器,举例:{{time | timeFormater}},默认会把time当作第一个参数传给timeFormater
注意点2:过滤器有形参时,前面的参数还是当作第一个参数,而形参默认当作第二个参数,举例:{{time | timeFormater(‘YYYY_MM_DD’)}},time 为形参1,’YYYY_MM_DD’为形参2
注意点3:过滤器可串行使用:{{ message | filterA | filterB }}
注意点4:过滤器并没有改变原本数据
注意点5:“ES6默认参数”机制(可用在方法中) =》举例:timeFormater方法的第二个参数str,如果有传值就用传递过来的值,如果str为空,就用默认的值YYYY年MM月DD日 HH:mm:ss
filters:{
timeFormater(value,str='YYYY年MM月DD日 HH:mm:ss'){
return dayjs(value).format(str)
}
}
注意点6:过滤器应该被添加在 JavaScript 表达式的尾部,由“管道符”指示:
<!-- in mustaches -->
{{ message | capitalize }}
<!-- in v-bind -->
<div v-bind:id="name| upperCase ">hei</div>
注意点7:使用Vue.filter定义全局过滤器,使用filters在组件内指定局部过滤器。
<div id="root">
<h4>{{name | upperCase | length | test('A-','-B')}}</h4>
</div>
<script>
/***
* filter:过滤器
* */
var vm = new Vue({
el: '#root',
data: {
name: 'hello'
},
filters: {
upperCase: function (value) {
return value.toUpperCase();
},
length: function (value) {
return value+value.length;
},
//在value两边加点东西
test: function (value, begin, end) {
console.log(value, begin, end);
return begin+value+end;
}
}
});
</script>
2.15内置指令
就是介绍下vue自带的但是我们不常用到的指令
2.15.1 v-cloak指令
举例说明:比如网页上方有个{{name}}属性,在<div>标签下面</body>的上面写个js引入文件,如果js引入出现网络延迟,那么出现的现象是页面只显示{{name}},而没有走到实例化vue去解析页面内容,这样用户体验极差,正常效果是要么不显示name,要么解析好了直接显示name属性值。
解决方案:标签设置 v-cloak特殊属性,并配合css样式display:none进行隐藏内容,默认网页元素加载时隐藏{{name}}属性所在的标签,当实例化vue完毕后会自动删除v-cloak特殊属性,从而达到显示name属性值的作用。
<head>
<meta charset="UTF-8" />
<title>v-cloak指令</title>
<style>
//[v-cloak]代表选中所有带v-cloak的标签
[v-cloak]{
display:none;
}
</style>
<!-- 引入Vue -->
</head>
<body>
<!-- 准备好一个容器-->
<div id="root">
<h2 v-cloak>{{name}}</h2>
</div>
<script type="text/javascript" src="http://localhost:8080/resource/5s/vue.js"></script>
</body>
<script type="text/javascript">
console.log(1)
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
new Vue({
el:'#root',
data:{
name:'尚硅谷'
}
})
</script>
2.15.2 v-pre指令
注意点1:加了v-pre后,vue解析到红色框时,就会跳过该行了,不会去判断当前行是否有指令和插值表达式之类的。
2.16.自定义指令
除了默认设置的核心指令 (v-model 和 v-show),Vue 也允许注册自定义指令。
2.16.1基本使用
1)定义
注意点1:定义全局指令使用Vue.directive,定义局部指令使用directives。
注意点2:自定义指令时不需要加v-,而标签使用时需要加v-自定义指令名
注意点3:只定义指令可以用在很多地方,包括:标签属性、标签体内容、绑定事件…
注意点4:
问题:自定义函数何时被调用?
答案:
1)指令与元素成功绑定时(一上来)
2)指令所在的模板被重新解析时,比如下方图片,无论data中属性name或者属性n只要其中任意一个发生值改变,上面的红框div模板就会进行重新解析
注意点5:自定义指令有两个形参,形参1代表:自定义指令所在的标签,如图1,形参2:代表绑定的所有信息封装一个成对象给你,如图2,既然形参1能获取自定义指令所在的标签,那么指令用在标签属性、标签体内容、绑定事件上,就都可以实现了。
图1:形参1
图2:形参2
//自定义全局指令v-focus
Vue.directive('focus',{
//当绑定元素插入到DOM调用
inserted: function (el) {
//元素获取焦点
el.focus();
}
});
使用directive定义,第一个参数为指令名,使用时加上v-前缀才能生效。inserted属性指当绑定元素插入到DOM时调用。
定义局部指令使用directives:
//定义局部指令使用directives
var app = new Vue({
el:'#app',
directives:{
focus:{
inserted: function (el) {
//元素获取焦点
el.focus();
}
}
}
});
2)使用
<div id="app">
<input type="text" v-focus>
</div>
2.16.2钩子函数
指令定义函数提供了几个钩子函数 (可选):
- bind:只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。
- inserted:被绑定元素插入父节点时调用 (父节点存在即可调用,不必存在于 document 中)。
- update:所在组件的 VNode 更新时调用,但是可能发生在其孩子的 VNode 更新之前。指令的值可能发生了改变也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 。
- componentUpdated:所在组件的 VNode 及其孩子的 VNode 全部更新时调用。
- unbind:只调用一次,指令与元素解绑时调用。
钩子函数的参数有4个:
1)el:当前指令绑定元素
2)binding:当前指令绑定的所有信息对象,有以下属性:
- name:指令名,不包括 v- 前缀。
- value:指令的绑定值,例如:v-my-directive=“1 + 1”, value 的值是 2。
- oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
- expression:绑定值的字符串形式。例如 v-my-directive=“1 + 1” ,expression 的值是 “1 + 1”。
- arg:传给指令的参数。例如 v-my-directive:foo,arg 的值是 “foo”。
- modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar, 修饰符对象 modifiers 的值是 { foo: true, bar: true }。
3)vnode:Vue 编译生成的虚拟节点
4)oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated
钩子中可用。
<div id="app">
<input type="text" v-demo:arg.a.b="1+1">
</div>
<script>
Vue.directive('demo',{
bind: function (el,binding) {
console.log(el);
console.log(binding);
}
});
var app = new Vue({
el:'#app'
});
</script>
2.16.3实例图片懒加载
谷歌图片的加载做得非常优雅,在图片未完成加载前,用随机的背景色占位,图片加载完成后才直接渲染出来,用自定义指令可以非常方便的实现这个功能。
1)样式
<style>
.item, .item img{
width: 200px;
height: 120px;
float: left;
}
</style>
2)自定义v-img指令
//定义全局自定义指令v-img
Vue.directive('img',{
bind: function (el,binding) {
//生成随机颜色
var color = parseInt(Math.random()*0xFFFFFF).toString(16);
//设置当前元素的背景,提前进行占位等待图片加载
el.style.background = '#'+color;
//setTimeout模拟图片加载的延时情况
setTimeout(function () {
//创建图片对象
var img = new Image();
//通过binding对象获取真实的图片url
img.src = binding.value;
//将图片元素插入DOM结构
el.appendChild(img);
//随机延时
},Math.random()*3000+500);
}
});
3)模拟数据
var app = new Vue({
el:'#app',
data:{
//定义模拟数据
imgs:[
{url:'img/01.jpg'},
{url:'img/02.jpg'},
{url:'img/03.jpg'},
{url:'img/04.jpg'}
]
}
});
4)使用
<div id="app">
<div v-img="item.url" v-for="item in imgs" class="item"></div>
</div>
5)效果
本人其他相关文章链接
1.《基础篇第1章:vue2简介》包含Vue2知识点、个人总结的使用注意点及碰到的问题总结
2.《基础篇第2章:vue2基础》包含Vue2知识点、个人总结的使用注意点及碰到的问题总结
3.《进阶篇第3章:vue进阶-组件》包含组件、自定义事件、插槽、路由等等扩展知识点
7.vue2知识点:列表渲染(包含:v-for、key、取值范围、列表过滤、列表排序、vue监视对象或数组的数据改变原理、总结vue数据监测)
9.vue2知识点:生命周期(包含:生命周期介绍、生命周期钩子、整体流程图详解)
13.vue2知识点:组件的props属性、非props属性、props属性校验
16.vue2知识点:动态组件
17.vue2知识点:混入
19.vue2知识点:全局事件总线(GlobalEventBus)
23.vue2知识点:路由
25.vue组件通信案例练习(包含:父子组件通信及平行组件通信)
26.vue表单案例练习:vue表单创建一行数据及删除数据的实现与理解
27.vue2基础组件通信案例练习:待办事项Todo-list案例练习
28.vue2基础组件通信案例练习:把案例Todo-list改写成本地缓存
29.vue2基础组件通信案例练习:把案例Todo-list改成使用自定义事件
30.vue2基础组件通信案例练习:把案例Todo-list改成使用全局事件总线
31.vue2基础组件通信案例练习:把案例Todo-list改成使用消息订阅与发布
32.vue2基础组件通信案例练习:把案例Todo-list新增编辑按钮
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/106209.html