在 Vue 的使用过程中会遇到各种场景,当普通使用时觉得没什么,但是或许优化一下可以更高效更优美地进行开发。下面有一些我在日常开发的时候用到的小技巧。
1. 多图表resize事件去中心化
1.1 一般情况
有时候我们会遇到这样的场景,一个组件中有几个图表,在浏览器 resize 的时候我们希望图表也进行 resize,因此我们会在 父容器组件中写:
mounted() {
setTimeout(() => window.onresize = () => {
this.$refs.chart1.chartWrapperDom.resize()
this.$refs.chart2.chartWrapperDom.resize()
// ...
}, 200)
destroyed() { window.onresize = null }
这样子图表组件如果跟父容器组件不在一个页面,子组件的状态就被放到父组件进行管理。为了维护方便,我们自然希望子组件的事件和状态由自己来维护,这样在添加删除组件的时候就不需要去父组件挨个修改。
1.2 优化
这里使用了 lodash 的节流 throttle 函数,也可以自己实现,这篇文章也有节流的实现可以参考一下。以 Echarts 为例,在每个图表组件中:
computed: {
/**
* 图表DOM
*/
chartWrapperDom() {
const dom = document.getElementById('consume-analy-chart-wrapper')
return dom && Echarts.init(dom)
},
/**
* 图表resize节流,这里使用了lodash,也可以自己使用setTimout实现节流
*/
chartResize() {
return _.throttle(() => this.chartWrapperDom && this.chartWrapperDom.resize(), 400)
}
},
mounted() {
window.addEventListener('resize', this.chartResize)
},
destroyed() {
window.removeEventListener('resize', this.chartResize)
}
1.3 再次优化
感谢 @JserWang 的提醒,这里因为多个 chart 实例都使用同一套初始化逻辑,可以使用 extends 来考虑复用,因此我想到了 Vue 提供的 Mixins,所以我在这里做了点优化,可以让每个同类型的 chart 组件更优雅一点,新建一个 mixin.js 文件:
import Echarts
然后在每个 chart 组件中:
其实通过配置 transformToRequire
后,就可以直接配置,这样 vue-loader 会把对应的属性自动 require 之后传给组件。
{
vue: {
transformToRequire: {
avatar: ['default-src']
}
}
}
于是我们代码就可以简化不少。
<div><avatar default-src="./assets/default-avatar.png">avatar>div>
</template>
在 vue-cli 的 webpack 模板下,默认配置是:
transformToRequire: {
video: ['src', 'poster'],
source: 'src',
img: 'src',
image: 'xlink:href'
}
可以举一反三进行一下类似的配置。
vue-loader 还有很多实用的 API 例如最近加入的 自定义块,感兴趣的各位可以去文档里找找看。
8. render 函数
在某些场景下你可能需要 render 渲染函数带来的完全编程能力来解决不太容易解决的问题,特别是要动态选择生成标签和组件类型的场景。
8.1 动态标签
(1)一般情况
比如根据 props 来生成标签的场景。
<div><div v-if="level === 1"> <slot>slot> div><p v-else-if="level === 2"> <slot>slot> p><h1 v-else-if="level === 3"> <slot>slot> h1><h2 v-else-if="level === 4"> <slot>slot> h2><strong v-else-if="level === 5"> <slot>slot> stong><textarea v-else-if="level === 6"> <slot>slot> textarea>div>
</template>
其中 level 是 data 中的变量,可以看到这里有大量重复代码,如果逻辑复杂点,加上一些绑定和判断就更复杂了,这里可以利用 render 函数来对要生成的标签加以判断。
(2)优化
使用 render 方法根据参数来生成对应标签可以避免上面的情况。
<div><child :level="level">Hello world!child>div>
</template>
示例可以查看 CodePen(https://codepen.io/SHERlocked93/pen/mLEJPE)。
8.2 动态组件
当然 render 函数还有很多用法,比如要使用动态组件,除了使用 :is
之外也可以使用 render 函数。
<div><button @click='level = 0'>嘻嘻button><button @click='level = 1'>哈哈button><hr><child :level="level">child>div>template>