一、计算属性
1、计算属性的概念
计算属性是依赖于源数据(data或者属性中的数据),在元数据的基础上进行逻辑运算后得到的新的数据,计算属性要依赖于源数据,源数据数据变化计算属性也会变化
2、计算属性的语法
在vue2中使用computed
这个选项完成计算属性的
javascript
<template>
<div>
<h2>购物车</h2>
<table>
<thead>
<tr>
<td>编号</td>
<td>商品</td>
<td>数量</td>
<td>价格</td>
<td>小计</td>
</tr>
</thead>
<tbody>
<tr v-for="item in filterShopcartList" :key="item.id">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>
<button @click="item.num--">-</button>
{{item.num}}
<button @click="item.num++">+</button>
</td>
<td>
{{item.price}}
</td>
<td>{{(item.price*item.num).toFixed(2)}}</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="5">
总价:{{getTotalPrice}}
</td>
</tr>
</tfoot>
</table>
</div>
</template>
<script>
export default {
data(){
return{
shopcartList:[
{
id:'1001',
name:'红富士苹果',
price:3.69,
num:1
},
{
id:'1002',
name:'威化饼干',
price:1.69,
num:1
},
{
id:'1003',
name:'康师傅方便面',
price:5.21,
num:1
}
]
}
},
computed:{
filterShopcartList:{
//get方法是为了完成获取计算值后的属性
get(){
return this.shopcartList.filter(item=>item.num>0)
}
},
getTotalPrice:{
get(){
return this.filterShopcartList.reduce((prve,cur)=>prve+cur.price*cur.num,0).toFixed(2)
}
}
}
}
</script>
<style>
table{
border-collapse: collapse;
}
td{
border:1px solid #999;
padding: 10px;
}
</style>
2、计算属性的简写形式
1)计算属性的标准写法:(很少用,需要更改原数据时才用)
javascript
computed:{
计算属性名称:{
get(){
return 新的结果
}
}
}
2)计算属性的简单写法(常用)
javascript
computed:{
计算属性名称:{
return 新的结果
}
}
javascript
<template>
<div>
<h2>购物车</h2>
<table>
<thead>
<tr>
<td>编号</td>
<td>商品</td>
<td>数量</td>
<td>价格</td>
<td>小计</td>
</tr>
</thead>
<tbody>
<tr v-for="item in filterShopcartList" :key="item.id">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>
<button @click="item.num--">-</button>
{{item.num}}
<button @click="item.num++">+</button>
</td>
<td>
{{item.price}}
</td>
<td>{{(item.price*item.num).toFixed(2)}}</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="5">
总价:{{getTotalPrice}}
</td>
</tr>
</tfoot>
</table>
</div>
</template>
<script>
export default {
data(){
return{
shopcartList:[
{
id:'1001',
name:'红富士苹果',
price:3.69,
num:1
},
{
id:'1002',
name:'威化饼干',
price:1.69,
num:1
},
{
id:'1003',
name:'康师傅方便面',
price:5.21,
num:1
}
]
}
},
computed:{
filterShopcartList:{
//get方法是为了完成获取计算值后的属性
get(){
return this.shopcartList.filter(item=>item.num>0)
}
},
getTotalPrice:{
get(){
return this.filterShopcartList.reduce((prve,cur)=>prve+cur.price*cur.num,0).toFixed(2)
}
}
}
}
</script>
<style>
table{
border-collapse: collapse;
}
td{
border:1px solid #999;
padding: 10px;
}
</style>
3、计算属性的缓存特性
计算属性具有缓存作用,在原数据不改变的情况下,计算属性多次调用只有第一次进行计算,后续都是从缓存中获取数据,如果源数据变化之后,计算属性就会重新进行计算。
4、setter和getter方法
javascript
<template>
<div>
<div>firstName:<span>{{firstName}}</span></div>
<div>middleName:<span>{{middleName}}</span></div>
<div>lastName:<span>{{lastName}}</span></div>
<div>fullName:<span>{{name}}</span></div>
<button @click="name='zhang san feng'">changeFullName</button>
</div>
</template>
<script>
export default {
data(){
return{
firstName:'zhai',
middleName:'ji',
lastName:'zhe'
}
},
computed:{
name:{
get(){
return this.firstName+" "+this.middleName+" "+this.lastName
},
set(val){
//计算属性是不能改的
console.log('val',val);
this.firstName=val.split(" ")[0]
this.middleName=val.split(" ")[1]
this.lastName=val.split(" ")[2]
}
}
}
}
</script>
<style lang="scss">
div{
span{
color: blue;
}
}
</style>
三、侦听器
1、侦听器的概念
在vue中当我们对data的数据或者计算属性进行变化的时候,专门一个选项可以随时监听data或者计算属性的变化,从而完成相应的逻辑
2、监听器的语法
监听器的语法有两种形式
- 简写写法
javascript
watch:{
//newval:变化之后的数据
//oldval:变化之前的数据
监视的数据名(newval,oldval){
}
}
案例:监视计数器num的变化
javascript
export default {
data(){
return{
num:0
}
},
watch:{
num(newval,oldval){
console.log(newval,oldval);
}
}
}
-
监听器的标准写法
语法
javascript
watch:{
监听的数据名:{
//监听的逻辑处理方法
handler(newval,oldval){
},
//是否深度监听
deep:true|false,
//是否立即监听
immediate:true|false
}
}
案例:使用标准写法完成计数器的监听
javascript
export default {
data(){
return{
num:0
}
},
watch:{
num:{
handler(newval,oldval){
console.log(newval,oldval);
}
}
}
}
3、监听对象中属性变化
如果要监听对象中属性的变化,可以有两种方式
第1种方式:通过'对象名.属性名'
的方式
javascript
<template>
<div>
<div>
{{obj.a}} <button @click="obj.a++">a+</button>
</div>
<div>
{{obj.b}} <button @click="obj.b++">a+</button>
</div>
<div>
{{obj.c}} <button @click="obj.c++">a+</button>
</div>
</div>
</template>
<script>
/*
watch:{
'对象名.属性名'(newval,oldval){
}
}
*/
export default {
data(){
return{
obj:{
a:10,
b:20,
c:30
}
}
},
watch:{
'obj.a'(newval,oldval){
console.log('obj.a',newval,oldval);
},
'obj.b'(newval,oldval){
console.log('obj.b',newval,oldval);
},
'obj.c'(newval,oldval){
console.log('obj.c',newval,oldval);
}
}
}
</script>
如上这种方式如果属性过多,它就太麻烦了
- 方式2:通过深度监听的方式来完成对对象的监听
javascript
export default {
data(){
return{
obj:{
a:10,
b:20,
c:30
}
}
},
computed:{
//新定义一个计算属性newObj,该计算属性的作用是将data对象中的obj做一个深拷贝
newObj(){
//这种深拷贝对于如果一个对象中有函数,获知时间类型是无法进行深拷贝
//JSON.stringify将JSON格式字符串(对象)转换为js对象(属性名没有双引号)
//JSON.parse将JSON字符串转为对象;
return JSON.parse(JSON.stringify(this.obj))
}
},
watch:{
//obj:要监听的对象
newObj:{
//执行监听的具体钩子函数
handler(newval,oldval){
console.log(newval,oldval);
},
//开启深度监听
deep:true
}
}
}
4、立即监听设置
通过对watch中 immediate设置为true,就会开启立即监听
javascript
watch:{
//obj:要监听的对象
newObj:{
//执行监听的具体钩子函数
handler(newval,oldval){
console.log(newval,oldval);
},
//开启深度监听
deep:true,
//开启立即监听
immediate:true
}
}
四、过滤器
1、什么是过滤器
vue中定义过滤器,主要用于文本格式化,具体可以完成如下功能
-
日期的格式化
-
货币格式化
-
小数点精确度的截取
-
大小写首字母转换等
注意:vue2中过滤器,vue3中将过滤去掉了
2、过滤器的分类
按照作用范围,可以将过滤器分成两大类
-
全局过滤器:针对项目中所有组件都有用
-
私有过滤器(局部过滤器)只针对当前组件有效
2.1、定义私有私有过滤器
- 定义私有过滤器
javascript
export default{
data(){},
methods{},
//filters:配置对象
filters:{
过滤器的名称(参数){
}
}
}
- 如何调用过滤器
使用过滤器的时候可以在两种情况下使用,第1种情况在插值表达式中使用;第2种在属性中使用
在插值表达式中使用
javascript
{{message|过滤器的2名称|过滤器2的名称}}
message代表是输出数据对象,|
这个竖杠表示的就是一个管道符,使用这个符号将插值表达式和过滤器连接在一起
使用v-bind
在属性中使用
javascript
<div v-bind:id="id的变量|过滤器的名称"></div>
案例:通过身份证获取格式化出生日期
javascript
<template>
<div>
<div>身份证号:{{idcard}}</div>
<div>生日:{{idcard|birthday}}</div>
</div>
</template>
<script>
export default {
data(){
return{
idcard:'610122198404084030'
}
},
filters:{
birthday(val){
return val.slice(6,10)+"-"+val.slice(10,12)+"-"+val.slice(12,14)
}
}
}
</script>
2.2、定义全局过滤器
定义全局过滤器的语法
javascript
Vue.filter('过滤器的名称',function(val){ return result})
定义全局过滤器的步骤
-
在src下创建一个filters的文件夹
-
在src/filters文件夹下定义过滤器的js文件
javascript
//首先先导入Vue
import Vue from 'vue'
Vue.filter('capitalize',function(val){
return val.charAt(0).toUpperCase()+val.slice(1)
})
- 在main.js中导入定义全局过滤器
javascript
import Vue from 'vue'
import App from './App.vue'
import './filters/capitalize' //在此处导入
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
- 在组件中可以使用
|
的方式来调用过滤器
五、自定义指令
之前我们已经接触过指令,在但是我们接触这些指令都是vue提供的内置指令,每一种指令有着不同的用途,如果开发者要想自定义指令,就可以使用自定义指令完成不同功能的封装
1、自定义指令的分类
-
全局自定义指令:可以作用域全局所有的组件
-
私有自定义指令:只能作用域该组件
1)私有自定义指令的语法
javascript
<template>
<div>
<h2 v-mycolor="color" @click="color='#0000ff'">Hello Giles</h2>
<!-- <h1 v-mycolor="color='#ff0000'">Hello Giles</h1>
<h1 v-mycolor="color='#00ff00'">Hello Giles</h1> -->
</div>
</template>
<script>
export default {
data(){
return{
color:'orange'
}
},
directives:{
mycolor:{
/*
当我们将指令绑定到标签的时候会调用一次,在此方法中完成初始化功能
el:所绑定指令(自定义指令)所在的DOM元素
bindings:自定义指令的配置对象
modifiers:指令的修饰符
name:指令的名称(不含v-和修饰符的)
rawName:指令的全名(v-的前缀和修饰符)
value:指定的所传递的值
vNode:更新之后的虚拟DOM节点对象
oldVnode:更新之前的虚拟DOM节点
*/
bind(el,bindings,vNode,oldVnode){
console.log('bindings',bindings.value);
el.style.color=bindings.value
},
componentUpdated(el,bindings,vNode,oldVnode){
console.log('vNode',vNode);
console.log('oldVnode',oldVnode);
el.style.color=bindings.value
el.innerHTML="Hello Woniuxy"
}
}
}
}
</script>
<style>
</style>
2)全局自定义指令的定义步骤
步骤
- 在src目录下创建directives文件夹,然后在文件夹下创建自定义指令
javascript
import Vue from 'vue'
Vue.directive('ellipses',{
bind(el,bindings){
let w;
if(bindings.value){
w=bindings.value.width
}else{
w="100px"
}
el.style.width=w
el.style.whiteSpace="nowrap"
el.style.textOverflow="ellipsis"
el.style.overflow='hidden'
}
})
- 在main.js中引入自定义指令
javascript
import Vue from 'vue'
import App from './App.vue'
import './directives/ellipses'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
- 在组件中应用
javascript
<div v-ellipses>白日依山尽,黄河入海流,欲穷千里目,更上一层楼</div>
<div v-ellipses="{width:'150px'}">白日依山尽,黄河入海流,欲穷千里目,更上一层楼</div>
<div v-ellipses="{width:'200px'}">白日依山尽,黄河入海流,欲穷千里目,更上一层楼</div>
2、自定义指令的案例
1)完成水印功能
javascript
import Vue from 'vue'
Vue.directive('waterMarker',{
bind(el,bindings){
let canvs=document.createElement('canvas')
//设置画布的大小
canvs.width=250
canvs.height=150
//获取画笔的上下文对象
let cxt=canvs.getContext('2d')
cxt.rotate((20*Math.PI)/180)
cxt.fillStyle=bindings.value.color
cxt.font="48px 宋体"
cxt.fillText(bindings.value.content,canvs.width/10,canvs.height/2)
el.appendChild(canvs)
}
})
2)完成画板功能
javascript
import Vue from 'vue'
/*
Vue.directive是用于定义全局指令的
参数有两个
参数1:自定义指令名称
参数2:自定义指令的配置对象
*/
Vue.directive('draw',{
bind(el,bindings){
console.log(bindings.value);
//创建Canvas对象
let cvs=document.createElement('canvas')
//给画布设置宽和高
cvs.width=bindings.value.width
cvs.height=bindings.value.height
//获取上下文对象
let cxt=cvs.getContext('2d')
//给画笔绑定onmousedown
cvs.onmousedown=function(e){
//获取鼠标点下去的坐标
cxt.moveTo(e.pageX-this.offsetLeft,e.pageY-this.offsetTop)
//当鼠标移动时候
cvs.onmousemove=function(e){
cxt.lineTo(e.pageX-this.offsetLeft,e.pageY-this.offsetTop)
cxt.stroke()
}
cvs.onmouseup=function(){
cvs.onmousemove=null
}
}
el.appendChild(cvs)
}
})