目录
目标
一、自定义指令
二、计算属性 - computed
三、侦听器 - watch
四、过滤器 - filters
五、混入 - Mixins
六、实例生命周期
目标
- 能够定义vue自定义指令
- 使用计算属性和侦听器
- 使用混入完成方法添加
- 掌握生命周期
- 能够使用axios发起网络请求
- 定义组件实现父子组件间传值
一、自定义指令
https://cn.vuejs.org/v2/guide/custom-directive.html
除了核心功能默认内置的指令,Vue也允许注册自定义指令。有的情况下,对普通 DOM?元素进行底层操作,这时候就会用到自定义指令绑定到元素上执行相关操作。
自定义指令分为:全局指令和局部指令,当全局指令和局部指令同名时以局部指令为准。
自定义指令常用钩子函数
注:指令中不能直接操作 Vue中的数据和方法 ,也就是指令中的 this 不是指令 vue对象
- bind?????第一次绑定到元素时调用
- inserted?被绑定元素插入父节点时调用?(仅保证父节点存在,但不一定已被插入文档中)
- update???数据更新时调用(所在组件的?VNode 更新时调用,但是可能发生在其子 VNode 更新之前)
- componentUpdated??指令所在组件的 VNode 及其子 VNode 全部更新后调用。
- unbind??只调用一次,指令与元素解绑时调用。
# 全局
Vue.directive('test',{
bind(el,bind){
console.log(el)
}
})
# 局部
new Vue({
directives: {
test:{
bind(el,bind){}
},
// bind/update
test2(el,bind){}
}
})
<div id="app" v-if="flag">
<h3 v-red>
<input type="text" v-model='title'>
</h3>
<button @click="flag=false">隐藏</button>
</div>
<script>
// 切面编程
// 全局指令定义
// 参数1:书写指令名称,不要加v-
// 参数2:对象(标准写法) | 函数(简写,它是bind和update合成体)
Vue.directive('red', {
// 当前指令绑定以的dom元素的dom对象
bind(el) { // 第一次绑定到元素时调用
// el.style.color = 'red'
// el.style.cssText = 'color:blue;font-size:50px;'
console.log('bind')
},
inserted(el) { // 被绑定元素插入父节点时调用
console.log('inserted')
},
update(el) { // 数据更新时调用
console.log('update')
},
componentUpdated(el) { // 指令所在组件的 VNode 及其子 VNode 全部更新后调用
console.log('componentUpdated')
},
unbind(el){ // 只调用一次 , 指令与元素解绑时调用
console.log('unbind')
}
})
const vm = new Vue({
el: '#app',
data: {
title: '你好世界',
flag: true
}
})
</script>
?案例 :?自定义指令-表单项验证
<div id="app">
<div>
<label>
账号:
<input type="text" v-model='username' v-len>
</label>
</div>
</div>
<!-- 支持es6模块化 -->
<script type="module">
import validator from './js/Validator.js'
// 全局指令定义
// 参数1:书写指令名称,不要加v-
// 参数2:对象(标准写法) | 函数(简写,它是bind和update合成体)
// 回调函数中的参数2,它就是用来获取指令参入的参数
Vue.directive('len', validator.len)
const vm = new Vue({
el: '#app',
data: {
username: '',
username_msg: ''
},
methods: {
fn(msg) {
this.username_msg = msg
}
}
})
</script>
// 默认导出,一个文件只能默认导出一次
export default {
len(el, binds) {
el.style.color = el.value.trim().length > 3 ? 'red' : '#000'
if (el.value.trim().length > 3) {
if (el.parentNode.lastChild.nodeName != 'SPAN') {
let span = document.createElement('span')
span.innerHTML = '字数超长了'
el.parentNode.appendChild(span)
}
} else {
if (el.parentNode.lastChild.nodeName == 'SPAN') {
el.parentNode.removeChild(el.parentNode.lastChild)
}
}
}
}
使用修饰符实现验证器 : ( 验证手机号及最小字符?)
<div id="app">
<input type="text" v-model="phone" v-validate.phone>
<hr>
<input type="text" v-model="username" v-validate="{min:2}">
</div>
<script type="module">
import valid from './js/Valid.js'
Vue.directive('validate', (el, binds) => {
// map forEach
Object.keys(binds.modifiers).forEach(fnName => valid[fnName](el, binds))
// 只有前面操作有值时才进行循环 它有undefined可能 js 短语运算 ts 断言
binds.value && Object.keys(binds.value).forEach(fnName => valid[fnName](el, binds))
/* if(binds.value){
Object.keys(binds.value).forEach(fnName => valid[fnName](el, binds))
} */
// 获取对象中的value值,返回一个数组
// Object.values()
// 获取地象中的key值,返回一个数组
// Object.keys()
// es6 判断是否为数组 true/false
// Array.isArray(变量)
})
const vm = new Vue({
el: '#app',
data: {
phone: '',
username: ''
}
})
</script>
export default {
phone(el, binds) {
if (!/^1[3-9]\d{9}$/.test(el.value)) {
el.style.color = '#f00'
} else {
el.style.color = '#000'
}
},
min(el, binds) {
if (binds.value.min) {
if (el.value.length <= binds.value.min) {
el.style.color = '#f00'
} else {
el.style.color = '#000'
}
}
}
}
按钮权限控制 :
inserted?被绑定元素插入父节点时调用?(仅保证父节点存在,但不一定已被插入文档中)?
二、计算属性 - computed
模板中放入太多的逻辑会让模板过重且难以维护,使用计算属性可以让模板变得简洁易于维护。计算属性是基于它们的响应式依赖进行?缓存?的?,计算属性比较适合对多个变量或者对象进行处理后返回一个结果值,也就是数多个变量中的某一个值发生了变化则我们监控的这个值也就会发生变化。
计算属性定义在 Vue 对象中,通过关键词 computed 属性对象 中定义一个个函数,并返回一个值,使用计算属性时和 data 中的数据使用方式一致
<div id="app">
<!-- 当多次调用 cfn 计算属性时只要里面的 num 值不改变,它会把第一次计算的结果
直接返回 , 直到 data 中的 num 值改变 计算属性 才会重新发生计算 -->
<div>{{ cfn }}</div>
<div>{{ cfn }}</div>
<!-- 调用 methods 中的方法的时候 他每次会重新调用 , 消耗性能 -->
<div>{{ fn() }}</div>
<div>{{ fn() }}</div>
</div>
<script type="text/javascript">
const vm = new Vue({
el: '#app',
data: {
num: 10
},
// 方法
methods: {
fn() {
console.log('methods')
return this.num
}
},
// 计算属性
computed: {
cfn() {
console.log('computed')
return this.num
}
}
})
</script>
注:只要依赖的数据源不发生改变,我就调用1次,其它使用缓存
计算属性的依赖项,可以是一对一,也可是一对多
三、侦听器 - watch
使用 watch 来侦听 data 中数据的变化, watch 中的属性一定是 data 中已经存在的数据。
当需要监听一个对象的改变时,普通的 watch 方法无法监听到对象内部属性的改变,只有 data 中的数据才能够监听到变化,此时就需要?deep?属性对对象进行 深度监听 。
<div id="app">
<input type="text" v-model='user.name'>
<span>{{num_msg}}</span>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
num: '10',
num_msg: '',
user: {
name: '张三'
}
},
// 侦听器 1对1 依赖项只有一个
watch: {
num(newValue, oldValue) {
// [^] : 非 : 表示 [^] 内的任意一个都不行
// [^] =>写在中括号中,表示取反,不是0-9的数据则匹配成功
if (/[^0-9]/.test(newValue)) {
this.num_msg = '全数字'
} else {
this.num_msg = ''
}
},
// 默认不会对于引用类型进行监听,除非你修改了引用地址
// 监听对象中的具体字段的值的变化
'user.name'(newVal, oldVal) {
console.log(newVal)
},
// 标准版本
user: {
// 深度监听
deep: true,
handler(newVal, oldVal) {
console.log(newVal)
}
},
}
})
</script>
四、过滤器 - filters
在数据被渲染之前,可以对其进行进一步处理,比如将字符截取或者将小写统一转换为大写等等,过滤器本身就是一个方法。
过滤器可以定义全局或局部
# 全局
// 回调函数中的参数1 永久是绑定的数据
Vue.filter(过滤器名称,(value,[…args])=>{ })
# 局部过滤器定义
此过滤器定义在 Vue对象的配置中的 filters 配置选项中,以方法形式来定义,参数1 永久是绑定的数据
<div id="app">
<!-- 过滤器 -->
<!-- 传递实参(5)给 len 形参 -->
<h3>{{title | substr(5)}}</h3>
<!-- 不传递参数 -->
<h3>{{title | substr}}</h3>
</div>
<script>
/* function fn() {
console.log(arguments)
}
fn(1, 2, 3, 4, 5) */
/* const fn = (...args) => {
console.log(args)
} */
// 全局过滤器
// 形参 len 设置一个 默认值
Vue.filter('substr', (value, len = 10) => {
if (value.length <= len) return value;
return value.substr(0, len) + '...'
})
const vm = new Vue({
el: '#app',
data: {
title: '这段时间娱乐圈可谓是抢占了头条,抖音,相继出现'
}
})
</script>
五、混入 - Mixins
混入( mixins )是一种分发 Vue 组件中可复用功能的非常灵活的方式。混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项。
混入分为:全局和局部
# 全局混入
Vue.mixin ( {
????????created( ){ } ,
????????methods:{ }
} )
# 局部混入
let mixinObj = { }
new Vue( {
????????mixins: [ mixinObj ]
} )
<script>
let o1 = { id: 1, fn() { console.log('o1') } } // o1
let o2 = { name: '张三', age: 20, fn() { console.log('o2') } } // o2
// o1 = { ...o2, ...o1 }
o1 = merge(o1, o2)
o1.fn()
console.log(o1.name) // 张三
function merge(o1, o2) {
let obj = { ...o1 }
for (let key in o2) {
if (typeof o2[key] === 'function') {
if (o1[key]) {
obj[key] = function () {
// 此引用地址变成新的
let f2 = o2[key]
let f1 = o1[key]
f1()
f2()
}
}
} else {
obj[key] = o2[key]
}
}
return obj
}
</script>
<div id="app">
<h3>{{title}}</h3>
<button @click="click">点击事件</button>
</div>
<script type="module">
import http from './js/http.js'
// 混入生命周期,执行顺序 全局先执行 > 局部执行 > 组件内执行
// 全局
Vue.mixin({
created() {
// 通过自定义属性对当前的实例添加了,自定义属性
this.$http = http;
console.log('全局混入---created')
}
})
// 局部混入
// 混入vue配置选项中的大部份配置,只有el不能混
// 混入时 data配置选项一定要是函数方式,且函数一定要返回一个对象
let mixinData = {
data() {
return {
title: '你好混入'
}
},
methods: {
click() {
console.log(111)
}
},
// 混入生命周期,执行顺序 全局先执行 > 局部执行 > 组件内执行
created() {
console.log('局部混入---created')
}
}
const vm = new Vue({
el: '#app',
data: {
// 数据如果本组件中有配置则以本组件为主
title: 'vue'
},
// 注册一下
mixins: [mixinData],
methods: {
click() {
console.log(this.$http);
console.log(2222)
}
},
created() {
// console.log(this.$http);
console.log('组件混入---created')
}
})
</script>
export default ({
url,
method = 'GET',
data = {}
}) => {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest;
xhr.open(method, url, true)
if (method === 'post') {
xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')
let postData = [];
for (let key in data) {
postData.push(`${key}=${data[key]}`)
}
xhr.send(postData.join('&'))
} else {
xhr.send(null)
}
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if ([200, 201, 202, 204].includes(xhr.status)) {
let json = xhr.status != 204 ? JSON.parse(xhr.responseText) : {}
resolve(json)
} else {
reject('fail')
}
}
}
})
}
六、实例生命周期
每个?Vue 实例在被创建之前都要经过一系列的初始化过程。例如需要设置数据监听、编译模板、挂载实例到 DOM、在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,给予用户机会在一些特定的场景下添加他们自己的代码。
beforeCreate | 在实例初始化之后,数据观测和事件配置之前被调用 此时 data 和 methods 以及页面的 DOM 结构都没有初始化 什么都做不了?执行1次 | created | 在实例创建完成后被立即调用此时 data 和 methods 已经可以使用 但是页面还没有渲染出来?执行1次 ?用 this 对象 | beforeMount | 在挂载开始之前被调用 此时页面上还看不到真实数据 只是一个模板页面而已??执行1 次 | mounted | el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。 数据已经真实渲染到页面上 在这个钩子函数里面可以?进行数据请求?等??执行1次 | beforeUpdate | 数据更新时调用,页面上数据还是旧的??n 次 | updated | 由于数据更新完毕,页面上数据已经替换成最新的?n 次 | beforeDestroy | 实例销毁之前调用???执行1次 | destroyed | 实例销毁后调用?????执行1次 | activated | keep-alive 组件激活时调用 | deactivated | keep-alive 组件停用时调用 | errorCaptured | 当捕获一个来自子孙组件的错误时被调用 |
|
?
?
?
|