目录
【前文回顾】👉 vue动态样式绑定详解_05
一. 自定义指令
1. 问题: 希望在页面加载完之后,自动给元素执行一些初始化的DOM操作。但是,在vue中几乎没有提供任何查找办法!我们就找不到DOM元素,就无法执行任何DOM相关的操作
2. 解决: 今后,只要在页面加载完之后,希望对元素执行一些初始化的DOM操作,比如: 让元素自动获得焦点,都用自定义指令。
3. 如何: 2步
(1). 定义自定义指令:
指令
Vue.directive("自定义指令名",{//指令名: 千万不要加v-开头!
//回调函数: 当new Vue()将当前元素添加页面上之后,自动执行。
//自动将当前带有该指令的元素对象传给回调函数的形参
//插入后 ↓
inserted(domElem){
对当前带有这个自定义指令的DOM元素,自动执行DOM操作。
}
})
(2). 使用自定义指令: 将自定义指令添加到DOM元素上
<元素 v-自定义指令名>
强调: 虽然定义自定义指令时,不能加v-前缀。但是使用自定义指令时,必须加v-前缀的!
4. 原理:
(1). Vue.directive(),创建一个新指令,并保存到Vue大家庭中备用。
(2). new Vue()扫描到带有这个指令的元素时,自动执行其中的inserted(),并自动将当前带有这个指令的DOM元素传给inserted()函数的形参。
(3). 在inserted()回调函数内,可以对当前带有这个指令的元素执行任意原生的DOM操作!
5. 自定义指令名: 不要用驼峰命名,应该一律小写,并且用-分割多个单词
(1). 原因: 整个HTML语法不区分大小写的!
比如: 对于HTML来说: MyFocus 和myfocus 和myFocus是一样的!无法区分!
(2). 所以: 今后,凡是要用在HTML中的名称,都不能用驼峰命名!必须用-分割多个单词!
6. 示例: 自定义指令,让当前元素自动获得焦点:
3_directive.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
<input v-my-focus><button>百度一下</button>
</div>
<script>
//1. 创建一个可让当前元素自动获得焦点的自定义指令
Vue.directive("my-focus",{
//当当前元素被加入到DOM树之后,立刻自动执行该函数
//并将当前元素自动传给domElem形参
inserted(domElem){
//对当前元素执行DOM操作: 自动获得焦点
domElem.focus();
}
});
new Vue({
el:"#app"
})
</script>
</body>
</html>
运行结果:
二. 计算属性
1. 问题: 页面上需要绑定一个值,但是这个值不是现成的!需要根据其他变量的值,经过复杂的计算(分支和循环)才能计算出来。
2. 解决: 今后只要页面上需要一个值,但是这个值必须经过复杂计算才能得到,都用计算属性!
3. 如何: 2步:
(1). 定义计算属性:
new Vue({
el:"#app",
data:{ ... },
methods:{ ... },
watch:{ ... },
//计算后的
computed:{
属性名(){ //但是本质却是一个函数
//根据其他变量的值,经过复杂计算,得出一个结果。
return 计算结果
}
}
})
(2). 使用计算属性:
<元素>xxxx{{属性名}}xxxx</元素>
强调: 使用计算属性时,一定不要加()
4. 问题: computed vs methods
(1). methods的执行结果不会被vue缓存,每调用一次,就会重复计算一次!——没必要的,效率低!
(2). computed的执行结果会被vue缓存,反复使用,避免重复计算。除非计算属性所依赖的其它变量值发生了改变,vue才会自动重新计算计算属性的新值,重新缓存起来反复使用。
5. 总结:
(1). 如果更侧重于使用一个函数的执行结果值时,首选computed。比如: 在页面上显示总价
(2). 如果更侧重于执行一个操作,不太关心具体的结果值时,首选methods。比如: 发送ajax请求
6. 示例: 显示订单总价:
4_computed.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
<h3>总价: ¥{{total.toFixed(2)}}</h3>
<ul>
<li v-for="(p,i) of cart" :key="i">
{{p.pid}} || {{p.pname}} || ¥{{p.price.toFixed(2)}} || {{p.count}} || 小计:¥{{(p.price*p.count).toFixed(2)}}
</li>
</ul>
<h3>总价: ¥{{total.toFixed(2)}}</h3>
</div>
<script>
new Vue({
el:"#app",
data:{
cart:[
{pid:1, pname:"华为",price:5888, count:2},
{pid:2, pname:"苹果",price:9888, count:1},
{pid:3, pname:"小米",price:3888, count:3},
]
},
methods:{
},
computed:{
total(){
console.log(`执行了一次遍历和求和的操作`)
var result=0;
for(var p of this.cart){
result+=p.price*p.count;
}
return result;
}
}
})
</script>
</body>
</html>
运行结果:
三. 过滤器
1. 问题: 有些数据不能直接给人看,需要先加工之后,再给人看。但是,又不愿意每次使用这种数据时,都把加工的过程重新写一遍!——繁琐
2. 解决: 今后实际项目中,只要一个数据,不能直接给人看,需要先加工再显示时,都用过滤器。
3. 如何: 2步
(1). 定义过滤器:
↓
Vue.filter("过滤器名", function(形参){
← return 返回值
})
(2). 使用过滤器:
<元素>{{变量 | 过滤器名 }}</元素>
4. 原理:
(1). Vue.filter()创建一个过滤器,保存到内存中vue大家庭中备用。
(2). 当new Vue()扫描到带有过滤器的元素时,就会去Vue大家庭中找是否包含想用的过滤器。
(3). 如果找到同名的过滤器,就自动调用过滤器函数,同时:
a. 自动传入|前的变量的原始值
b. 在过滤器函数内,经过加工后,返回新值
(4). new Vue()就会把过滤后返回的新值,显示在元素内容中
5. 过滤器命名: 因为过滤器名是写在HTML中的{{}}内部,属于js的地盘。所以,过滤器名不能用-分割多个单词,应该用驼峰命名。
<!--HTML | js | HTML-->
<h3>性别:{{sex | sexFilter}}</h3>
6. 示例: 使用过滤器过滤性别:
5_filter.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
<!--HTML | js | HTML-->
<h3>性别:{{sex|sexFilter}}</h3>
</div>
<script>
//1. 创建过滤器
Vue.filter("sexFilter", function (oldVal) {
return oldVal == 1 ? "男" : "女";
});
new Vue({
el: "#app",
data: {
sex: 0,
},
});
</script>
</body>
</html>
运行结果: 性别:女
7. 过滤器传参: 2步:
(1). 定义过滤器时:
变量的原始值
预留
↓
Vue.filter("过滤器名",function(oldVal, 自定义形参,...){
return 返回值
})
(2). 使用过滤器时:
<元素>{{变量 | 过滤器名(实参值) }}</元素>
(3). 示例: 根据不同实参值,过滤不同语言的性别
5_filter2.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
<h3>性别:{{sex | sexFilter}}</h3>
<h3>性别:{{sex | sexFilter("en")}}</h3>
</div>
<script>
//1. 创建过滤器
// "en","cn"
// ↓ ↓
Vue.filter("sexFilter",function(oldVal,yuyan){
if(yuyan=="en"){
return oldVal==1?"Male":"Female"
}else{
return oldVal==1?"男":"女"
}
});
new Vue({
el:"#app",
data:{
sex:1
}
})
</script>
</body>
</html>
运行结果:
性别:男
性别:Male
8. 多个过滤器连用:
(1). <元素>{{变量 | 过滤器1 | 过滤器2 | ... }}
(2). 强调:
a. 定义后一个过滤器时,充分考虑所有可能的传入的值。
b. 后一个过滤器不能只return新值,应该将新值和旧值合并返回。
(3). 示例: 过滤性别,即显示性别名,又显示性别图标: 看过滤器sexIcon即可
5_filter3.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
<h3>性别:{{sex | sexIcon }}</h3>
<h3>性别:{{sex | sexFilter | sexIcon}}</h3>
<h3>性别:{{sex | sexFilter("en") | sexIcon}}</h3>
</div>
<script>
// 1,0,男,女,Male,Female
// \ /
Vue.filter("sexIcon",function(oldVal){
if(oldVal==1||oldVal==0){
return oldVal==1?"♂":"♀";
}else if(oldVal=="男"||oldVal=="Male"){
return oldVal+"♂"
}else{
return oldVal+"♀"
}
})
//1. 创建过滤器
// "en","cn"
// ↓ ↓
Vue.filter("sexFilter",function(oldVal,yuyan){
if(yuyan=="en"){
return oldVal==1?"Male":"Female"
}else{
return oldVal==1?"男":"女"
}
});
new Vue({
el:"#app",
data:{
sex:1
}
})
</script>
</body>
</html>
运行结果:
性别:♂
性别:男♂
性别:Male♂
💥 扩展:this判断—8种指向
this 8种指向: 判断this,一定不要看定义在哪儿!只看调用时!
➡️ 1. obj.fun() this->obj
➡️ 2. fun() 或 (function(){ ... })() 或 多数回调函数 或 定时器函数 this->window
➡️ 3. new Fun() this->new正在创建的新对象
➡️ 4. 类型名.prototype.共有方法=function(){ ... } this->将来谁调用指谁,同第一种情况
➡️ 5. DOM或jq中事件处理函数中的this->当前正在触发事件的DOM元素对象
如果需要使用简化版函数,必须$(this)
➡️ 6. 箭头函数中的this->箭头函数外部作用域中的this
➡️ 7. jQuery.fn.自定义函数=function(){ ... } this->将来调用这个自定义函数的.前的jQuery子对象,不用再$(this)
➡️ 8. new Vue()中methods中的函数中的this->当前new Vue()对象
⬛ 总结:知识点提炼
1. MVVM: 界面View+模型Model+视图模型ViewModel
2. Vue绑定原理: 访问器属性+虚拟DOM树
变量被修改时: 访问器属性发出通知,虚拟DOM树扫描并仅更新受影响的元素
3. 虚拟DOM树优点:
(1). 小: 只包含可能变化的元素。
(2). 遍历查找快
(3). 修改效率高: 只修改受影响的元素。
(4). 避免重复编码: 已封装DOM增删改查代码
4. Vue功能3步:
(1). 先创建增强版的界面:
a. 整个界面必须包含在一个唯一的父元素下:
通常是<div id="app">
b. 可能变化的元素内容用{{自定义变量名}}标记
c. 触发事件的元素用@click="自定义处理函数名"标记
(2). 再创建new Vue()对象,其中el:指向new Vue()要监控的页面区域
(3). 在new Vue()对象内定义模型对象data和methods
a.界面所需的所有变量都放在data中
b.界面所需的所有事件处理函数都放在methods中
5. 总结: 绑定语法+13种指令
(1). 如果元素的内容需要随变量自动变化: {{}}
(2). 如果元素的属性值需要随变量自动变化: :
(3). 控制一个元素显示隐藏: v-show //使用display:none隐藏元素
(4). 控制两个元素二选一显示: v-if v-else //使用删除元素方式隐藏元素
(5). 多个元素多选一显示: v-if v-else-if v-else
(6). 只要反复生成多个相同结构的元素组成列表时: v-for :key="唯一标识"
强调: 为什么必须加:key="i"?给每个元素副本添加唯一标识。修改数组中某个元素值时,避免重建整个列表,只需要修改一个DOM元素副本即可!提高修改效率。
(7). 只要绑定事件: @ $event
(8). 防止用户短暂看到{{}}: v-cloak和v-text
(9). 只要绑定原始HTML代码片段内容: v-html
(10). 如果元素的内容只在首次加载时绑定一次,之后都不会改变: v-once
优化: 减少虚拟DOM树中元素个数。
(11). 保护内容中的{{}}不被编译: v-pre
(12). 今后只要想获得表单元素的值或状态: v-model
6. 绑定样式:
(1). 需要精确修改某一个css属性,就绑定style:
a. <元素 style="固定样式" :style="{css属性:变量名, ...}"
data:{
变量名:css属性值
... : ...
}
b. <元素 style="固定样式" :style="变量名"
data:{
变量名:{
css属性名: 属性值,
... : ...
}
}
(2). 只要批量修改一个元素的多个css属性就绑定class
a. <元素 class="固定class" :class="{class名:变量名, ...}"
data:{
变量名:true或false,
... : ...
}
b. <元素 class="固定class" :class="变量名"
data:{
变量名:{
class名:true或false,
... : ...
}
}
7. 只要希望在页面加载时自动对元素执行一些初始化操作时就用自定义指令:
(1). 添加自定义指令:
Vue.directive("自定义指令名",{
inserted(domElem){
对domElem执行DOM操作
}
})
(2). 使用自定义指令:
<元素 v-自定义指令名>
8. 今后只要根据其他变量的值动态计算出一个属性值就用计算属性:
<元素>{{计算属性}}</元素>
new Vue({
el:"#app",
data:{...},
methods:{...},
computed:{
计算属性名(){
计算过程
return 计算结果
}
}
})
9. 希望将变量的原始值先加工后再显示给用户看时就用过滤器:
Vue.filter("过滤器名",function(oldVal, 自定义形参,...){
return 加工后的新值
})
<元素>{{ 变量 | 过滤器(实参值, ...) | ... }}</元素>
【后文传送门】👉 vue中axios的使用及vue生命周期详解_07
如果这篇【文章】有帮助到你,希望可以给【青春木鱼】点个赞👍,创作不易,相比官方的陈述,我更喜欢用【通俗易懂】的文笔去讲解每一个知识点,如果有对【前端技术】感兴趣的小可爱,也欢迎关注❤️❤️❤️【青春木鱼】❤️❤️❤️,我将会给你带来巨大的【收获与惊喜】💕💕!