前端修仙路- vue基础进阶
前言:我们大多数人在使用vue的时候,觉得很简单,但实际基础不扎实,有很多好用的特性项目中并没有用到,久而久之就忘了,特写此文铭记。
混入(mixin)
概念解释: 当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。
混入规则:
- data混入: 合并data,如果键名冲突以组件数据优先。
- 钩子混入(生命周期函数): 同名钩子合并成一个数组,依次调用,并且混入钩子优先调用。
- 值为对象的混入:如 methods、components 和 directives,将被合并为同一个对象。键名冲突时,组件数据优先。
eg:
var mixin = {
created: function () {
console.log('混入对象的钩子被调用')
},
data: function () { //混入data
return {
message: 'hello',
foo: 'abc'
}
}
}
new Vue({
mixins: [mixin], //局部混入
data: function () {
return {
message: 'goodbye',
bar: 'def'
}
},
created: function () {
console.log(this.$data)
}
})
//=> 混入对象的钩子被调用
// => { message: "goodbye", foo: "abc", bar: "def" }
全局混入:
// 为自定义的选项 'myOption' 注入一个处理器。
Vue.mixin({
created: function () {
var myOption = this.$options.myOption
if (myOption) {
console.log(myOption)
}
}
})
new Vue({
myOption: 'hello!'
})
// => "hello!"
小提示:
请谨慎使用全局混入,因为它会影响每个单独创建的 Vue 实例 (包括第三方组件)。
大多数情况下,只应当应用于自定义选项
,就像上面示例一样。推荐将其作为插件发布,以避免重复应用混入。
自定义指令(directive)
概念解释: 常见的指令有v-model,v-show等,当你需要操作dom的时候,就可以用自定义指令来处理。
钩子(指令生命周期):
bind:
只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。inserted:
被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。update:
所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新componentUpdated:
指令所在组件的 VNode 及其子 VNode 全部更新后调用。unbind:
只调用一次,指令与元素解绑时调用。
钩子参数
含有黄色标注的应该重点记忆,比较常用:
- el:指令所绑定的元素,可以用来直接操作 DOM。
binding:
一个对象,包含以下 property:name:
指令名,不包括 v- 前缀。- value:指令的绑定值,例如:v-my-directive=“1 + 1” 中,绑定值为 2。
oldValue:
指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。expression:
字符串形式的指令表达式。例如 v-my-directive=“1 + 1” 中,表达式为 “1 + 1”。- arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 “foo”。
- modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。
vnode:
Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。oldVnode:
上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
eg:
// 注册全局指令 `v-focus`
Vue.directive('focus', {
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el,binding) {
// 聚焦元素
el.focus()
}
})
//注册局部指令
export default{
// ...省略组件无关选项
directives: {
focus: {
// 指令的定义
inserted: function (el,binding) {
el.focus()
}
}
}
}
// <input v-focus> 使用指令
动态指令参数
指令的参数可以是动态的。例如,在 v-mydirective:[argument]="value"
中,argument 参数可以根据组件实例数据进行更新!
// 注册v-pin指令
Vue.directive('pin', function (el, binding) { //为函数表示触发bind和update
el.style.position = 'fixed'
var s = (binding.arg == 'left' ? 'left' : 'top')
el.style[s] = binding.value + 'px'
}
)
new Vue({
el: '#dynamicexample',
data: function () {
return {
direction: 'left'
}
}
})
// <p v-pin:[direction]="200">I am pinned onto the page at 200px to the left.</p>
过滤器(filter)
用途:过滤器常用于一些常见的文本格式化。
两种注册方式:
// 全局注册capitalize过滤器
Vue.filter('capitalize', function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
})
// 局部注册
export default{
// ...省略无关选项
filters: {
capitalize: function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
}
}
}
使用方式也有两种:
<!-- 在双花括号中 -->
{{ message | capitalize }}
<!-- 在 `v-bind` 中 -->
<div v-bind:message="message | capitalize"></div>
插件
概念解释:插件通常用来为 Vue 添加全局功能。
用途:
- 添加全局方法或者 property
- 添加全局资源:指令/过滤器/过渡等
- 通过全局混入来添加一些组件选项,如
vue-router
- 添加 Vue 实例方法,通过把它们添加到
Vue.prototype
上实现
自定义插件:
let MyPlugin = {};
MyPlugin.install = function (Vue, options) {
// 1. 添加全局方法或 property
Vue.myGlobalMethod = function () {
// 逻辑...
}
// 2. 添加全局资源
Vue.directive('my-directive', {
bind (el, binding, vnode, oldVnode) {
// 逻辑...
}
...
})
// 3. 注入组件选项
Vue.mixin({
created: function () {
// 逻辑...
}
...
})
// 4. 添加实例方法
Vue.prototype.$myMethod = function (methodOptions) {
// 逻辑...
}
}
export default MyPlugin
使用插件:
// 调用 `MyPlugin.install(Vue)`
Vue.use(MyPlugin, { someOption: true }) //第二个参数可选
函数式组件(functional)
概念解释:函数式组件用来定义那些没有响应数据,也不需要有任何生命周期的场景,它只接受一些props 来显示组件。
使用方法:
- 方式一:
Vue.component('component', {
functional: true,
// Props 是可选的
props: {
// ...
},
// 为了弥补缺少的实例
// 提供第二个参数作为上下文
render: function (createElement, context) {
// ...
}
})
- 方式二
<template functional> //render 可以改写成template
<div class="root">
hello {{props.name}} //渲染props
</div>
</template>
<script>
export default {
functional:true, //启用函数式组件
props:{
name:{
type:String,
default:'hzz'
}
},
name:'HelloWorld'
}
</script>
正因为函数组件没有响应式数据,也不需要生命周期函数,因此性能会有所提升,如果只是纯静态展示内容,推荐使用函数式组件。
提供/注入(provide/inject)
概念解释:这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。如果你熟悉 React,这与 React 的Context特性很相似。
用途:provide 和 inject 主要在开发高阶插件/组件库时使用。并不推荐用于普通应用程序代码中。
eg:
// 祖先组件
export default{
//...省略组件无关选项
provide: {
foo: 'bar'
}
}
// 子孙组件
export default{
//...省略组件无关选项
inject: ['foo'],
created () {
console.log(this.foo) // => "bar"
}
}
提示:
provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的 property 还是可响应的。
彩蛋
看vue文档,发现了一个奇特的跨组件传值方式,特分享给大家:
共享数据
import Vue from 'vue'
const state = Vue.observable({count:0})
export default state
组件A
<template>
<div class="root">
crossA count: {{this.count}}
</div>
</template>
<script>
import state from '../module/crossState';
export default {
props:{},
computed:{
count(){return state.count}
},
name:'CrossA'
}
</script>
组件B
<template>
<div @click="changeCount()" class="root">
crossB count: {{this.count}}
</div>
</template>
<script>
import state from '../module/crossState';
export default {
props:{},
methods:{
changeCount(){
state.count++
}
},
computed:{
count(){return state.count}
},
name:'CrossB'
}
</script>
当点击组件B的时候,组件A的值也会跟着改变,其核心利用了Vue.observable
定义了一个响应式对象,而计算属性依赖该对象属性,于是count改变时,重新计算属性,实现了数据的双向绑定,也实现了跨组件传值。
这期到此结束 😃