同样的,我们也可以在 <template> 上使用 v-for 指令,这种方式还能解决 v-for 和 v-if 同时使用报出的警告问题。
<template v-for="item in 10"> <div v-if="item % 2 == 0" :key="item">{{item}}</div> </template>,
过滤器被用于一些常见的文本格式化,被添加在表达式的尾部,由“管道”符号指示。
<div>{{ text | capitalize }}</div> export default { data() { return { text: 'hello' } }, filters: { capitalize: function (value) { if (!value) return '' value = value.toString() return value.charAt(0).toUpperCase() + value.slice(1) } } }试想一个场景,不仅模板内用到这个函数,在 method 里也需要同样功能的函数。但过滤器无法通过 this 直接引用,难道要在 methods 再定义一个同样的函数吗?
要知道,选项配置都会被存储在实例的 $options 中,所以只需要获取 this.$options.filters 就可以拿到实例中的过滤器。
export default { methods: { getDetail() { this.$api.getDetail({ id: this.id }).then(res => { let capitalize = this.$options.filters.capitalize this.title = capitalize(res.data.title) }) } } }除了能获取到实例的过滤器外,还能获取到全局的过滤器,因为 this.$options.filters 会顺着 __proto__ 向上查找,全局过滤器就存在原型中。
自定义指令获取实例有的情况下,当需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令。像是项目中常用的权限指令,它能精确到某个模块节点。大概思路为获取权限列表,如果当前绑定权限不在列表中,则删除该节点元素。
Vue.directive('role', { inserted: function (el, binding, vnode) { let role = binding.value if(role){ const applist = sessionStorage.getItem("applist") const hasPermission = role.some(item => applist.includes(item)) // 是否拥有权限 if(!hasPermission){ el.remove() //没有权限则删除模块节点 } } } })自定义指令钩子函数共接收3个参数,包括 el (绑定指令的真实dom)、binding (指令相关信息)、vnode (节点的虚拟dom)。
假设现在业务发生变化,applist 存储在 vuex 里, 但指令内想要使用实例上的属性,或者是原型上的 $store。我们是没有办法获取到的,因为钩子函数内并没有直接提供实例访问。vnode 作为当前的虚拟dom,它里面可是绑定到实例上下文的,这时候访问 vnode.context 就可以轻松解决问题。
Vue.directive('role', { inserted: function (el, binding, vnode) { let role = binding.value if(role){ // vnode.context 为当前实例 const applist = vnode.context.$store.state.applist const hasPermission = role.some(item => applist.includes(item)) if(!hasPermission){ el.remove() } } } }) 优雅注册插件插件通常用来为 Vue 添加全局功能。像常用的 vue-router、vuex 在使用时都是通过 Vue.use 来注册的。Vue.use 内部会自动寻找 install 方法进行调用,接受的第一个参数是 Vue 构造函数。
一般在使用组件库时,为了减小包体积,都是采用按需加载的方式。如果在入口文件内逐个引入组件会让 main.js 越来越庞大,基于模块化开发的思想,最好是单独封装到一个配置文件中。配合上 Vue.use,在入口文件使用能让人一目了然。
vant.config.js:
import { Toast, Dialog } from 'vant' const components = { Toast, Button } const componentsHandler = { install(Vue){ Object.keys(components).forEach(key => Vue.use(components[key])) } } export default componentsHandlermain.js:
import Vue from 'vue' import vantCompoents from '@/config/vant.config' Vue.config.productionTip = false Vue.use(vantCompoents) new Vue({ render: h => h(App) }).$mount('#app')参考文档
自动化引入模块在开发中大型项目时,会将一个大功能拆分成一个个小功能,除了能便于模块的复用,也让模块条理清晰,后期项目更好维护。
像 api 文件一般按功能划分模块,在组合时可以使用 require.context 一次引入文件夹所有的模块文件,而不需要逐个模块文件去引入。每当新增模块文件时,就只需要关注逻辑的编写和模块暴露,require.context 会帮助我们自动引入。
需要注意 require.context 并不是天生的,而是由 webpack 提供。在构建时,webpack 在代码中解析它。
import Request from '../service/request' let importAll = require.context('./modules', false, /\.js$/) class Api extends Request{ constructor(){ super() //importAll.keys()为模块路径数组 importAll.keys().map(path =>{ //兼容处理:.default获取ES6规范暴露的内容; 后者获取commonJS规范暴露的内容 let api = importAll(path).default || importAll(path) Object.keys(api).forEach(key => this[key] = api[key]) }) } } export default new Api()require.context 参数:
文件夹路径
是否递归查找子文件夹下的模块
模块匹配规则,一般匹配文件后缀名