前端修仙路- vue基础进阶
前端修仙路- 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”。
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改变时,重新计算属性,实现了数据的双向绑定,也实现了跨组件传值。
这期到此结束 😃
- 前端基础进阶(十):面向对象实战之封装拖拽对象
- 前端基础进阶(十二):深入核心,详解事件循环机制
- 前端基础进阶(四):详细图解作用域链与闭包
- 前端基础进阶(一):内存空间详细图解
- 前端基础进阶(九):详解面向对象、构造函数、原型与原型链
- 【前端基础进阶系列】学习笔记
- 2019六星前端基础课程(Html+Css+Javascript+Vue)
- 前端基础进阶(十三):透彻掌握Promise的使用,读这篇就够了
- 前端基础进阶:内存空间详细图解
- 前端基础进阶(一):内存空间详细图解
- 前端基础进阶(三):变量对象详解
- 前端基础进阶(一):内存空间详细图解
- 前端基础进阶(九):图例详解那道setTimeout与循环闭包的经典面试题
- 前端基础进阶(七):函数与函数式编程
- 前端基础进阶(十四):es6常用基础合集
- 前端基础进阶系列
- vue前端开发基础
- 前端基础进阶(二):执行上下文详细图解
- 前端基础进阶(十):深入核心,详解事件循环机制
- 前端基础进阶(六):在chrome开发者工具中观察函数调用栈、作用域链与闭包