原文

初衷

之前写过一篇文章,关于 Vue 属性透传的,文章中我列举了很多种方法去实现属性透传。其中包括直接设置 propsv-bind="$attrs"render function 等方式。感兴趣,详情看 【Vue进阶】——如何实现组件属性透传?
不过后来有个掘友给我留言,其实 v-bind="obj" 的方式就可以直接传递展开后对象的所有属性的,试了一下,是可以的
这让我意识到了自己对一些 Vue 技巧掌握不足,所有有了这篇文章。通过这篇文章,我总结很多能够帮助我们提高开发效率的 Vue 技巧,同时也指出这些技巧的使用场景以及使用注意事项,我坚信对于 Vue 开发者有一定的帮助

1.通过 v-bind=”$props” 以及v-bind=”$attrs” 实现属性透传

很多时候,我们会写一些嵌套组件,比如 A 的子组件是 B,B 的子组件是 C。这个时候如果 A 传递 props 给 B,B 又得传递 props 给 C,我们经常在 B 传给 C 的时候这么写

  1. <template>
  2. <child-component :someprop1="someprop1"
  3. :someprop2="someprop2"
  4. :someprop3="someprop3"
  5. :someprop4="someprop4"
  6. ...
  7. />
  8. </template>
  9. 复制代码

这样是很不优雅的,其实你可以直接使用 v-bind: $props

  1. <template>
  2. <child-component v-bind="$props"/>
  3. </template>
  4. 复制代码

这里我们利用 v-bind 可以传入一个对象的所有 property,类似 v-bind="Obj"。例如,对于一个给定的对象 post

  1. post: {
  2. id: 1,
  3. title: 'My Journey with Vue'
  4. }
  5. 复制代码

下面的模板:

  1. <blog-post v-bind="post"></blog-post>
  2. 复制代码

等价于:

  1. <blog-post
  2. v-bind:id="post.id"
  3. v-bind:title="post.title"
  4. ></blog-post>
  5. 复制代码

这个配合 v-bind="$attrs" 在封装一些组件的时候非常有用,比如实现属性透传。
vm.$attrs 包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件——在创建高级别的组件时非常有用。
比如将上面传递进来的 props 全部绑定到 el-input 中,我们可以在子组件中这么写:

  1. <template>
  2. <div>
  3. <el-input v-bind="$attrs" ></el-input>
  4. </div>
  5. </template>
  6. 复制代码

详情具体可以看【Vue进阶】——如何实现组件属性透传?

有同学可能想到了 provideinject,确实也是可以的传递 props,却做不到属性透传,而且 provideinject 绑定并不是可响应的,这一点需要额外注意一下。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的。

2.两个 component 接受同样的 props

上面例子中,要求组件 B 和组件 C 接受同样的的 props,其中 B 组件写法如下(C 组件类似):

  1. <template>
  2. <child-component v-bind="$props"/>
  3. </template>
  4. <script>
  5. import ChildComponent from '@/components/ChildComponent'
  6. export default {
  7. props:{
  8. someProp1: String,
  9. someProp2: String,
  10. someProp3: String,
  11. // and so on
  12. }
  13. }
  14. </script>
  15. 复制代码

但这样有个问题,就是 C 组件修改了 props,那么 B 组件得一起修改,这样做的一个坏处有可能会有遗漏。另外就是代码冗余,看起来不精简。其实我们可以在 B 组件中这么写

  1. <template>
  2. <child-component v-bind="$props"/>
  3. </template>
  4. <script>
  5. import ChildComponent from '@/components/ChildComponent'
  6. export default {
  7. props:{
  8. ...ChildComponent.options.props
  9. }
  10. }
  11. </script>
  12. 复制代码

3.Props 校验

由于 Javascript 是弱类型语言,在写 props 的时候,最佳实践是对 props 使用 type 指定类型以及设定默认值,如下:

  1. Vue.component('my-component', {
  2. // 带有默认值的对象
  3. propA: {
  4. type: Object,
  5. // 对象或数组默认值必须从一个工厂函数获取
  6. default: function () {
  7. return { message: 'hello' }
  8. }
  9. }
  10. })
  11. 复制代码

但是有可能我们不知道的是,props 可以自定义验证函数

  1. Vue.component('my-component', {
  2. // 自定义验证函数
  3. propF: {
  4. validator: function (value) {
  5. // 这个值必须匹配下列字符串中的一个
  6. return ['success', 'warning', 'danger'].indexOf(value) !== -1
  7. }
  8. }
  9. })
  10. 复制代码

甚至上面的 type 除了可以设置 String Number Boolean Array Object Date Function Symbol 之外,还可以自定义构造函数,其底层实现原理是通过 instanceof 去判断

  1. function Person (firstName, lastName) {
  2. this.firstName = firstName
  3. this.lastName = lastName
  4. }
  5. Vue.component('blog-post', {
  6. props: {
  7. author: Person
  8. }
  9. })
  10. 复制代码

这样来验证 author prop 的值是否是通过 new Person 创建的

4.透传所有事件监听

有时候,我们需要对一些开源库的表单组件,比如 elementUIform 进行一层包装,让它更好的为我们的业务服务,但是一旦这么包装,就出现一个问题,调用的时候如何监听到内部 form 组件暴露出来的所有事件呢?总不能一个个的绑定吧
这个时候,可以在内部 form 组件设置 v-on="$listeners"
$listeners 包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用,上面的例子可以很好解决如下:

  1. <template>
  2. <div>
  3. ...
  4. <el-form v-on="$listeners"/>
  5. ...
  6. </div>
  7. </template>
  8. 复制代码

当然如果子组件是父组件的根元素,则不需要这么写,Vue 默认已经做了这一层的操作了

5.作用域插槽实现 UI 和业务逻辑的分离

很多时候,我们想复用一个组件的业务逻辑,但是不想使用该组件的 UI,那么可以使用作用域插槽实现 UI 和业务逻辑的分离。
作用域插槽大致的思路是将 DOM 结构交给调用方去决定,组件内部只关注业务逻辑,最后将数据和事件等通过 :item ="item" 的方式传递给父组件去处理和调用,实现 UI 和业务逻辑的分离。再结合渲染函数,就可以实现无渲染组件的效果
具体可以看我的另一篇文章 【Vue 进阶】从 slot 到无渲染组件
其中父组件调用的时候可以类似这样,其中 #rowv-slot:row 的缩写

  1. <!-- 父组件 -->
  2. <template>
  3. ...
  4. <my-table>
  5. <template #row="{ item }">
  6. /* some content here. You can freely use 'item' here */
  7. </template>
  8. </my-table>
  9. ...
  10. </template>
  11. 复制代码
  1. <!-- 子组件 -->
  2. <span>
  3. <!-- 使用类似 v-bind:item="item",将子组件中的事件或者data传递给父组件-->
  4. <slot v-bind:item="item">
  5. {{ item.lastName }}
  6. </slot>
  7. </span>
  8. 复制代码

需要注意,Vue 2.6 之前使用的是 slotslot-scope,后面使用的是 v-slot

6.动态的指令参数

Vue 2.6 中提供了这样一个特性:可以动态的将指令参数传递给组件。假设你有一个组件 <my-button>,有时候你需要绑定一个点击事件 click,有时候需要绑定一个双击事件 dblclick,这个时候你可以这么写

  1. <template>
  2. ...
  3. <my-button @[someEvent]="handleSomeEvent()"/>
  4. ...
  5. </template>
  6. <script>
  7. ...
  8. data(){
  9. return{
  10. ...
  11. someEvent: someCondition ? "click" : "dblclick"
  12. }
  13. },
  14. methods:{
  15. handleSomeEvent(){
  16. // do something
  17. }
  18. }
  19. ...
  20. </script>
  21. 复制代码

7.hookEvent 的使用

Vue 2.X 当中,hooks 可以作为一种 Event,在 Vue 的源码当中,称之为 hookEvent。 利用它,我们可以模板声明式的监听子组件的生命周期钩子,从而可以给第三方组件添加生命周期处理函数
比如,我们调用了一个很耗费性能的第三方组件 List,这个组件可能需要渲染很久,为了更好的用户体验,我们想在 List组件进行更新的时候添加一个 loading 的动画效果
这个时候,我们可能会想到直接修改这个组件的源码,利用 beforeUpdateupdated 来显示 loading,但是这种办法非常不好。第一修改成本比较大,第二无法享受开源社区对这个组件的升级与维护,你需要自己手动维护
这个时候就可以通过 hookEvent 模板声明式的注入声明周期钩子函数,类似如下:

  1. <List @hook:updated="handleTableUpdated"></List >
  2. 复制代码

另外,我们还可以通过下面的方式给一个 Vue 组件添加生命周期处理函数

  1. vm.$on('hooks:created', cb)
  2. vm.$once('hooks:created', cb)
  3. 复制代码

比如我们想在组件销毁的时候,去销毁之前调用的组件,一般我们会这么做:
中级前端vue使用技巧 - 图1
但是这么做代码的可读性是不好的,我们可以修改成以下的方式,优化我们代码的可读性,精简我们的代码,这也是 Vue 3 在致力解决的问题
中级前端vue使用技巧 - 图2

8.key 值的使用

Vue 中,使用 v-for,官方建议带上 key 值,因为如果不使用 keyVue 默认会使用一种“就地复用”的策略进行更新。在一些情况下,很有可能会导致渲染不正确,之前总结过一篇 使用 key 不当踩坑的经历,感兴趣可以看下
除了 v-for, 在使用 Vue-router 做项目时,会遇到如 /path/:id 这样只改变 id 号的场景,但渲染不同的组件。由于 router-view 是复用的,单纯的改变 id 号并不会刷新 router-view,这并不是我们所期望的结果
这个时候,我们可以给每个 router-view 添加一个不相同 key 值,让 Vue 每次切换路由参数的时候,认为是不同的组件,从而得到更新

  1. <router-view :key="key"></router-view>
  2. 复制代码

实际上对于所有的 DOMVue 都有可能采取就地复用的策略,所以如果遇到了渲染顺序不正确的问题,可以往 key 值设置的方向考虑

9.自定义组件使用 v-model

我们知道,v-modelv-bind 以及 v-on 配合使用的语法糖,以下的两者的实现是一致的:

  1. <input v-model="value" />
  2. <input v-bind:value="value" v-on:input="value= $event.target.value" />
  3. 复制代码

一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,但是像单选框、复选框等类型的输入控件可能会将 value attribute 用于不同的目的。
其中 v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件:

  • text 和 textarea 元素使用 value property 和 input 事件
  • checkbox 和 radio 使用 checked property 和 change 事件
  • select 字段将 value 作为 prop 并将 change 作为事件

以上的情况,我们在自定义组件中使用的时候,就需要使用 model 选项了,按照官方的示例,写了个 demo
中级前端vue使用技巧 - 图3
这里的 lovingVue 的值将会传入这个名为 checkedprop。同时当 <base-checkbox> 触发一个 change 事件并附带一个新的值的时候,这个 lovingVueproperty 将会被更新。

10.CSS scoded 和深度作用选择器

Vue-loader 中,当 <style> 标签有 scoped 属性时,它的 CSS 只作用于当前组件中的元素,它通过使用 PostCSS 来实现以下转换,可以注意到 .example 后面添加了专属于该元素的 [data-v-f3f3eg9]

  1. <style scoped>
  2. .example {
  3. color: red;
  4. }
  5. </style>
  6. <template>
  7. <div class="example">hi</div>
  8. </template>
  9. 复制代码
  1. <style>
  2. .example[data-v-f3f3eg9] {
  3. color: red;
  4. }
  5. </style>
  6. <template>
  7. <!-- 留意data-v-f3f3eg9 -->
  8. <div class="example" data-v-f3f3eg9>hi</div>
  9. </template>
  10. 复制代码

但有时候,我们想设置混用本地和全局样式,可以在一个组件中同时使用有 scoped 和非 scoped 样式

  1. <style>
  2. /* 全局样式 */
  3. </style>
  4. <style scoped>
  5. /* 本地样式 */
  6. </style>
  7. 复制代码

但这样全局的样式就有可能产生一些副作用,我们很多时候这么设置,其实只是想设置父组件中子组件的样式。因为父组件设置了 scoped之后,父组件的样式将不会渗透到子组件中
这个时候,我们可以直接通过深度作用选择器去影响子组件,如下

  1. <style scoped>
  2. .a >>> .b { /* ... */ }
  3. </style>
  4. 复制代码

会编译成如下:

  1. .a[data-v-f3f3eg9] .b { /* ... */ }
  2. 复制代码

有些像 Sass 之类的预处理器无法正确解析 >>>。这种情况下你可以使用 /deep/::v-deep 操作符取而代之——两者都是 >>> 的别名,同样可以正常工作

11.watch immediate

有时候我们想在一个组件中 watch 一个值,进行一些初始化页面和更新页面的操作,比如 this.getDetails()
类似如下:

  1. watch: {
  2. id: {
  3. handler(newValue) {
  4. this.getDetails(newValue);
  5. }
  6. }
  7. }
  8. 复制代码

这里 watch 的一个特点是,最初绑定的时候是不会执行的,要等到 id 改变时才执行监听计算。这可能导致我们页面第一次渲染出错
想要在 watch 中声明了 id 后立即先执行 handler 方法,可以加上 immediate: true

  1. watch: {
  2. id: {
  3. handler(newValue) {
  4. this.getDetails(newValue);
  5. },
  6. // 代表在wacth里声明了id后这个方法之后立即先去执行handler方法
  7. immediate: true
  8. }
  9. }
  10. 复制代码

12.在 Vue 中使用 JSX

JSX 是一种 Javascript 的语法扩展,JSX = Javascript + XML,即在 Javascript 里面写 XML,因为 JSX 的这个特性,所以他即具备了 Javascript 的灵活性,同时又兼具 html 的语义化和直观性
有时候,我们使用渲染函数(render function)来抽象组件,而渲染函数有时候写起来是非常痛苦的,这个时候我们可以在渲染函数中使用 JSX 简化我们的代码。在 Vue 中使用 JSX,需要使用 Babel 插件,它可以让我们回到更接近于模板的语法上,详情可以看我之前总结的一篇文章【Vue进阶】手把手教你在 Vue 中使用 JSX
比如常见的指令可以书写如下:

  1. render() {
  2. {/* 指令 */}
  3. {/* v-model */}
  4. <div><input vModel={this.newTodoText} /></div>
  5. {/* v-model 以及修饰符 */}
  6. <div><input vModel_trim={this.tirmData} /></div>
  7. {/* v-on 监听事件 */}
  8. <div><input vOn:input={this.inputText} /></div>
  9. {/* v-on 监听事件以及修饰符 */}
  10. <div><input vOn:click_stop_prevent={this.inputText} /></div>
  11. {/* v-html */}
  12. <p domPropsInnerHTML={html} />
  13. }
  14. 复制代码

13.v-cloak 解决页面闪烁问题

很多时候,我们页面模板中的数据是异步获取的,在网络不好的情况下,渲染页面的时候会出现页面闪烁的效果,影响用户体验,v-cloak 指令保持在元素上直到关联实例结束编译,利用它的特性,结合 CSS 的规则 [v-cloak] { display: none } 一起使用就可以隐藏掉未编译好的 Mustache 标签,直到实例准备完毕

  1. // template 中
  2. <div class="#app" v-cloak>
  3. <p>{{value.name}}</p>
  4. </div>
  5. // css 中
  6. [v-cloak] {
  7. display: none;
  8. }
  9. 复制代码

需要注意,虽然解决了闪烁的问题,但这段时间内如果什么都不处理的话,会直接白屏,这并不是我们想要的效果,我们应该加一个 loading 或者骨架屏的效果,提升用户体验

14.v-once 和 v-pre 提升性能

我们知道 Vue 的性能优化很大部分在编译这一块,Vue 源码就有类似标记静态节点的操作,以在 patch 的过程中跳过编译,从而提升性能。另外,Vue 提供了 v-pre 给我们去决定要不要跳过这个元素和它的子元素的编译过程。可以用来显示原始 Mustache 标签。跳过大量没有指令的节点会加快编译。

  1. <span v-pre>{{ this will not be compiled }}</span> 显示的是{{ this will not be compiled }}
  2. <span v-pre>{{msg}}</span> 即使data里面定义了msg这里仍然是显示的{{msg}}
  3. 复制代码

另外,如果只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。可以使用 v-once

  1. <!-- 单个元素 -->
  2. <span v-once>This will never change: {{msg}}</span>
  3. <!-- 有子元素 -->
  4. <div v-once>
  5. <h1>comment</h1>
  6. <p>{{msg}}</p>
  7. </div>
  8. <!-- 组件 -->
  9. <my-component v-once :comment="msg"></my-component>
  10. <!-- `v-for` 指令-->
  11. <ul>
  12. <li v-for="i in list" v-once>{{i}}</li>
  13. </ul>
  14. 复制代码

15.函数式组件

函数式组件指的是无状态,无法实例化,内部没有任何生命周期处理方法的组件。因为函数式组件只是函数,所以渲染开销也低很多。可以通过声明 functional: true,表明它是一个函数式组件
在作为包装组件的时候,它们是非常有用的

  • 程序化地在多个组件中选择一个来代为渲染
  • 在将 childrenpropsdata 传递给子组件之前操作它们

看官方的一个 demo,留意注释

  1. // 根据不同的情况渲染不同的组件
  2. var EmptyList = { /* ... */ }
  3. var TableList = { /* ... */ }
  4. var OrderedList = { /* ... */ }
  5. var UnorderedList = { /* ... */ }
  6. Vue.component('smart-list', {
  7. functional: true, // 声明 functional: true,表明它是一个函数式组件
  8. props: {
  9. items: {
  10. type: Array,
  11. required: true
  12. },
  13. isOrdered: Boolean
  14. },
  15. // 为了弥补缺少的实例
  16. // 提供第二个参数作为上下文
  17. render: function (createElement, context) { // 组件中所有的一切都是通过 context 传递的
  18. // 根据不同的情况渲染不同的组件
  19. function appropriateListComponent () {
  20. var items = context.props.items
  21. if (items.length === 0) return EmptyList
  22. if (typeof items[0] === 'object') return TableList
  23. if (context.props.isOrdered) return OrderedList
  24. return UnorderedList
  25. }
  26. return createElement(
  27. appropriateListComponent(),
  28. context.data, // 传递给组件的整个数据对象
  29. context.children // `VNode` 子节点的数组
  30. )
  31. }
  32. })
  33. 复制代码

留意下,组件中所有的一切都是通过 context 传递的(render 函数的第二个参数),比如上面通过 context.data context.children 分别代表传递给组件的整个数据对象,作为 createElement 的第二个参数传入组件和VNode 子节点的数组,详细的 context 中包含的内容见官网

16.使用 Vue.observable 实现状态共享

众所众知,Vuex 就是专门用来解决多组件状态共享的情况,不过就像 Vuex 官方文档所说的,如果应用不够大,为避免代码繁琐冗余,最好不要使用它
Vue.observable( object ) 让一个对象可响应。Vue 内部会用它来处理 data 函数返回的对象。返回的对象可以直接用于渲染函数和计算属性内,并且会在发生变更时触发相应的更新。也可以作为最小化的跨组件状态存储器,用于简单的场景,有点类似小型的 Vuex
我们新建一个文件 store.js

  1. import Vue from "vue";
  2. // 创建一个小型的 store,里面的数据可以实现多组件共享
  3. export const store = Vue.observable({ count: 0 });
  4. // 模糊VueX 的 mutation
  5. export const mutations = {
  6. setCount(count) {
  7. store.count = count;
  8. }
  9. };
  10. 复制代码

在组件中使用 store 中的值以及更新 store 中的值,具体的可以看 demo

  1. <template>
  2. <div id="app">
  3. <p>count:{{count}}</p>
  4. <button @click="setCount(count+1)">+1</button>
  5. <button @click="setCount(count-1)">-1</button>
  6. </div>
  7. </template>
  8. <script>
  9. import HelloWorld from "./components/HelloWorld";
  10. import { store, mutations } from "./store";
  11. export default {
  12. name: "App",
  13. components: {
  14. HelloWorld
  15. },
  16. // 获取 store 中的数据
  17. computed: {
  18. count() {
  19. return store.count;
  20. }
  21. },
  22. // 更改 store 中的数据
  23. methods: {
  24. setCount: mutations.setCount
  25. }
  26. };
  27. </script>
  28. 复制代码

17.表单输入控制——表单修饰符/change事件/filter/指令

我们经常遇到控制表单输入内容的需求,比如输入框内一定是是数字,不能有特殊字符等等。这里我提供一些自己的一些思路,供大家选择使用

表单修饰符

如果是简单的控制输入一定是数字或者去掉用户输入的收尾空白符,可以直接使用 Vue 提供的表单修饰符 .number.trim
如果想自动将用户的输入值转为数值类型,可以给 v-model 添加 number 修饰符:

  1. <input v-model.number="age" type="number">
  2. 复制代码

如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符:

  1. <input v-model.trim="msg">
  2. 复制代码

change事件

给表单绑定事件,在事件处理中进行表单输入控制

  1. <input v-model="value2" type="text" @change="inputChange(value2)" />
  2. 复制代码
  1. methods: {
  2. inputChange: function(val) {
  3. if (!val) return ''
  4. val = val.toString()
  5. this.value2 = val.charAt(0).toUpperCase() + val.slice(1)
  6. }
  7. }
  8. 复制代码

filter

还可以通过过滤器 filter 进行

  1. <input v-model="value1" type="text" />
  2. 复制代码
  1. Vue.filter('capitalize', function (value) {
  2. if (!value) return ''
  3. value = value.toString()
  4. return value.charAt(0).toUpperCase() + value.slice(1)
  5. })
  6. 复制代码
  1. watch: {
  2. value1(val) {
  3. this.value1 = this.$options.filters.capitalize(val);
  4. }
  5. }
  6. 复制代码

详情可以看这个 demo

指令

声明一个全局的指令

  1. // 只能输入正整数,0-9的数字
  2. Vue.directive('enterIntNumber', {
  3. inserted: function (el) {
  4. let trigger = (el, type) => {
  5. const e = document.createEvent('HTMLEvents')
  6. e.initEvent(type, true, true)
  7. el.dispatchEvent(e)
  8. }
  9. el.addEventListener("keyup", function (e) {
  10. let input = e.target;
  11. let reg = new RegExp('^\\d{1}\\d*$'); //正则验证是否是数字
  12. let correctReg = new RegExp('\\d{1}\\d*'); //正则获取是数字的部分
  13. let matchRes = input.value.match(reg);
  14. if (matchRes === null) {
  15. // 若不是纯数字 把纯数字部分用正则获取出来替换掉
  16. let correctMatchRes = input.value.match(correctReg);
  17. if (correctMatchRes) {
  18. input.value = correctMatchRes[0];
  19. } else {
  20. input.value = "";
  21. }
  22. }
  23. trigger(input, 'input')
  24. });
  25. }
  26. });
  27. 复制代码

使用指令控制

  1. <!--限制输入正整数-->
  2. <input v-enterIntNumber placeholder="0" type="number">
  3. 复制代码

18.事件:特殊变量 $event

原生事件
解决场景:有时候,我们绑定事件后,想传入除了原生事件对象之外的其他参数
在监听原生 DOM 事件时,方法以原生事件对象为唯一的参数(默认值)。很多时候,我们想要在内联处理器中访问原始的 DOM 事件(而且同时想传其他参数),可以使用 $event 把它传入。

  1. <!-- 注意这里调用的方法有两个参数 -->
  2. <input v-model="value1" @change="inputChange('hello', $event)">
  3. 复制代码
  1. methods: {
  2. inputChange(msg, e) {
  3. console.log(msg, e);
  4. }
  5. }
  6. 复制代码

中级前端vue使用技巧 - 图4
自定义事件
在自定义事件中,$event 是从其子组件中捕获的值
场景:你想监听 el-input 的传递过来的值的同时,传递其他的参数。

  1. <el-input
  2. v-model="value2"
  3. @change="change($event, 'hello')"
  4. placeholder="Input something here"
  5. />
  6. 复制代码
  1. methods: {
  2. change(e, val) {
  3. console.log("event is " + e); // el-input 输入的值
  4. console.log(val); // hello
  5. }
  6. }
  7. 复制代码

中级前端vue使用技巧 - 图5
详情可看这个 demo

19.调试 template

很多时候,我们会遇到 template 模板中变量报错的问题,这个时候,我们很想通过 console.log 打印到控制台,看它的值是什么

  1. // 这里最好是判断一下,只有在测试环境中才使用
  2. // main.js
  3. Vue.prototype.$log = window.console.log;
  4. // 组件内部
  5. <div>{{$log(info)}}</div>
  6. 复制代码

可见 demo
中级前端vue使用技巧 - 图6

20.开发调试 Vue 必备的工具——vue-devtools

vue-dev-toolVue 官方开源的调试神器,利用它可以很清楚的查看组件层级,组件数据变化,Vuex 数据以及事件等等。特别是对于一些复杂应用,决定能够提升你的工作效率
可以科学上网的见地址1
不能的见地址2 里面有手动安装教程
中级前端vue使用技巧 - 图7
另外,vscode 的插件 Vetur 也一起推荐一下,支持语法高亮,代码块等等功能,个人觉得使用 vscodeVue 开发者必备

总结

Vue 的学习门槛相对比较低,我们掌握一些常见的用法就能解决我们日常大部分的问题。但掌握上面全部的 Vue 技巧,你肯定会有一种全新的体验
“原来 Vue 还可以这么玩”,如果你有这样的感觉,恭喜你,尝试使用这些技巧去解决你的一些问题吧,肯定可以达到事半功倍的效果

往期优秀文章推荐