13个技巧让你的 vue.js 代码更优雅

可莉
• 阅读 753

前言🍊


作为深度代码洁癖,我们都希望能写出简单高效的代码,让我们的代码看起来更加优雅,让我们抛弃繁杂的代码,一起开启简单的旅程~~

$on(‘hook:’) 可以帮助你简化代码

mounted () {  window.addEventListener('resize', this.resizeHandler);  this.$on("hook:beforeDestroy", () => {    window.removeEventListener('resize', this.resizeHandler);  })}

$on 还可以侦听子组件的生命周期钩子

生命周期钩子发出自定义事件这一事实意味着父组件可以监听其子级的生命周期钩子。它将使用正常模式来监听事件(@event),并且可以像其他自定义事件一样进行处理。

<child-comp @hook:mounted="someFunction" />

使用 immediate: true 在初始化时触发watcher

如果你需要 wather 在实例初始化后立即运行,那么你所要做的就是将 wather 转换为具有 handler(newVal, oldVal) 函数以及即时 immediate: true 的对象。

watch: {    title: {      immediate: true,      handler(newTitle, oldTitle) {        console.log("Title changed from " + oldTitle + " to " + newTitle)      }    }}

slots 新语法向 3.0 看齐

使用带有“#”的新命名插槽缩写语法,在Vue 2.6.0+中可用👍

构建插槽与构建组件没有什么不同。本质上,插槽是具有超强功能的组件,让我们细分一下上面的布局,组件的外观如下:

<!-- TidbitPage.vue --><template>  <article-layout>    <template #articleHeader>      <h1>I am the header</h1>    </template>    <template #articleContent>      <p>I am the content</p>    </template>    <template #articleFooter>      <footer>I am the footer</footer>    </template>    <template #side>      <aside>I am the side stuff</aside>    </template>    <template #banner>      <div>I am the banner</div>    </template>  </article-layout><template>

动态指令参数

指令参数现在可以接受动态JavaScript表达式 动态参数值应该是字符串,但允许null作为一个明确指示应该删除绑定的特殊值,那将会很方便。任何其他非字符串值都可能出错,并会触发警告。(仅适用于v-bind和v-on

<div v-bind:[attr]="attributeName"></div>//简写<div :[attr]="attributeName"></div>

这里的 attributeName 会被作为一个JavaScript表达式进行动态求值,求得的值将会作为最终的参数来使用。例如,如果你的 Vue 实例有一个 data 属性 attributeName,其值为 href,那么这个绑定将等价于 v-bind:href

同样地,你可以使用动态参数为一个动态的事件名绑定处理函数:

<button v-on:[eventName]="handler"></button>//简写<button @[eventName]="handler"></button>

当 eventName 的值为 focus 时,v-on:[eventName] 将等价于v-on:focus

同样可以适用于插槽绑定:

<my-component><template v-slot:[slotName]>Dynamic slot name</template></my-component>//简写<foo><template #[name]>Default slot</template></foo>

动态参数预期会求出一个字符串,异常情况下值为 null。这个特殊的 null 值可以被显性地用于移除绑定。任何其它非字符串类型的值都将会触发一个警告。

<!-- 这会触发一个编译警告 且 无效 --><a v-bind:['foo' + bar]="value"> ... </a>

变通的办法是使用没有空格或引号的表达式,或用计算属性替代这种复杂表达式。

@hook那些事

处理组件内定时器的步骤。通常我们一般都是这样操作的:

<script>  export default {    mounted() {      this.timer = setInterval(() => { ... }, 1000);    },    beforeDestroy() {      clearInterval(this.timer);    }  };</script>

但是其实更好的做法是:

<script>  export default {    mounted() {      const timer = setInterval(() => { ... }, 1000);      this.$once('hook:beforeDestroy', () => clearInterval(timer);)    }  };</script>

设想一个场景 如果我们需要在数据渲染到页面的之前让页面 loadingmounted 之后停止 loadingbeforeUpdata 时开始 loadingupdatad 之后停止 loading

最简单的方法就是改写组件的生命周期函数,使其在 mounted/beforeUpdata /updatad 时通知父组件显示或者隐藏 loading。

这样做显示不好,因为侵入了自组件的逻辑,增加的逻辑也和组件本身的功能好不关联。最好的办法就是使用 v-on="hook:xxx" 的方式:

<v-chart    @hook:mounted="loading = false"    @hook:beforeUpdated="loading = true"    @hook:updated="loading = false"    :data="data"/>

这样,就实现了对子组件生命周期的监听。对任意的组件都有效果,包括引入的第三方组件。

vue中的$props$attrs$listeners(可用来二次封装组件)

$props:当前组件接收到的 props 对象。Vue 实例代理了对其 props 对象属性的访问。

假如有个input输入框。我们有很多的原生属性,比如:name、placeholder、disabled等等。我们如果都定义在props显示接收,未免太过繁琐。所以官网出现了:v-bind="$props"这样的操作。如果父组件传递很多的原生属性,那么我们在子组件中直接可以:

//good<input v-bind="$props"> //bad//而不是下面这样,如果很多的属性就特别繁琐<input :name="name" :placeholder="placeholder" :disabled="disabled">

我们可以利用以下方式$attrs 将原生属性直接传递给子组件,这是Vue在2.4.0新增的属性,包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件——在创建高级别的组件时非常有用。

<input   v-bind="$attrs"   :value="value"   @focus=$emit('focus', $event)"   @input="$emit('input', $event.target.value)">

$listeners:包含了父作用域中的 (不含 .native修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。

如果子组件不在父组件的根目录下,则可以将所有事件侦听器从父组件传递到子组件,如下所示:

<template><div>  ...<childComponent v-on="$listeners" />...</div></template>

响应式数据(2.6.0新增)

我们习惯于用Vuex去解决状态的共享问题,但是在小项目中使用就会有增大代码体积和将代码复杂化的烦恼,所以在后来的版本中Vue新增

Vue.observable( object )让一个对象可响应,Vue 内部会用它来处理 data 函数返回的对象。

返回的对象可以直接用于渲染函数和 计算属性 内,并且会在发生改变时触发相应的更新。也可以作为最小化的跨组件状态存储器,用于简单的场景:

官方示例:

const state = Vue.observable({ count: 0 })const Demo = {  render(h) {    return h('button', {      on: { click: () => { state.count++ }}    }, `count is: ${state.count}`)  }}

jsx模板组件

以下面的一组状态判断按钮为例,我们很容易就下意识地在模板内写下这种代码

<button v-if="status === 1" class="btn1" :class="status === 1" @click="">未开始</button><button v-if="status === 2" class="btn2" :class="status === 2" @click="">进行中</button><button v-if="status === 3" class="btn3" :class="status === 3" @click="">可领取</button><button v-if="status === 4" class="btn4" :class="status === 4" @click="">已领取</button>

但是如果我们利用渲染函数可以将上面的代码抽取成优雅的使用组件

<!DOCTYPE html><html lang="en"><body>    <div id="app">        <child :status="status"></child>    </div>    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>    <script>        Vue.component('child', {            props: {                status: {                    type: Number,                    required: true                }            },            render(createElement) {                const innerHTML = ['未开始', '进行中', '可领取', '已领取'][this.status]                return createElement('button', {                    class: {                        active: this.status                    },                    attrs: {                        id: 'btn'                    },                    domProps: {                        innerHTML                    },                    on: {                        click: () => console.log(this.status)                    }                })            }        })        var app = new Vue({            el: '#app',            data: {                status: 0            }        })    </script></body></html>

我们将所有的逻辑封装进渲染函数内,外部只需要传递一个状态参数即可改变

<child :status="status"></child>

动态组件

通过 Vue 的  元素加一个特殊的 is attribute 可以实现动态组件的效果

如图,这是一个v-for渲染的列表(只是目前这个版块才刚开始做,目前只有一个),圆圈内的就是一个组件,也就是要v-for动态组件

实际使用

一开始就是基本的组件引入了

import ColorIn from '@/components/Magic/ColorIn.vue'import LineIn from "@/components/Magic/LineIn.vue";import Header from "@/components/Magic/Header.vue";import Footer from "@/components/Magic/Footer.vue";export default{      components:{        ColorIn,        LineIn,        Header,        Footer    }}

接下来就是动态v-for动态组件的使用,componentList:['ColorIn','LineIn','Header','Footer']使用下面的代码即可将代码依次循环

<component v-for="(item,index) in componentList" :key="index" :is="item"></component>

编译以后的效果就是

<ColorIn></ColorIn><LineIn></LineIn><Header></Header><Footer></Footer>

Vue.filter

简单介绍一下过滤器,顾名思义,过滤就是一个数据经过了这个过滤之后出来另一样东西,可以是从中取得你想要的,或者给那个数据添加点什么装饰,那么过滤器则是过滤的工具。例如,从['abc','abd','ade']数组中取得包含‘ab’的值,那么可通过过滤器筛选出来‘abc’和‘abd’;把‘Hello’变成‘Hello World’,那么可用过滤器给值‘Hello’后面添加上‘ World’;或者把时间节点改为时间戳等等都可以使用过滤器。

场景:时间戳转化成年月日这是一个公共方法,所以可以抽离成过滤器使用

// 使用// 在双花括号中{{ message | capitalize }}// 在 `v-bind` 中<div v-bind:id="rawId | formatId"></div>// 全局注册Vue.filter('stampToYYMMDD', (value) =>{  // 处理逻辑})// 局部注册filters: {  stampToYYMMDD: (value)=> {    // 处理逻辑  }}// 多个过滤器全局注册// /src/common/filters.jslet dateServer = value => value.replace(/(\d{4})(\d{2})(\d{2})/g, '$1-$2-$3')export { dateServer }// /src/main.jsimport * as custom from './common/filters/custom'Object.keys(custom).forEach(key => Vue.filter(key, custom[key]))

.sync 语法糖

sync 就是为了实现prop 进行“双向绑定”仅此而已(父对子,子对父,来回传)

当你有需要在子组件修改父组件值的时候这个方法很好用,它的实现机制和v-model是一样的。

<comp :foo.sync="bar"></comp><!--等同于↓--><child :bar="foo" @update:bar="e=>foo=e"/><!--更新方式-->

this.$emit("update:bar",newValue)

利用 object.freeze 提升性能

Object.freeze() 方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。freeze() 返回和传入的参数相同的对象。

比方我们需要渲染一个非常大的数组对象,例如用户列表,对象列表,文章列表等等。

export default {  data: () => ({    users: {}  }),  async created() {    const users = await axios.get("/api/users");    this.users = users;  }};

vue 会将 data 对象中的所有的属性加入到 vue 的响应式系统中,当这些属性的值发生改变时,视图将会产生 响应,若对象的体积比较大,会消耗很多浏览器解析时间。

所以我们可以通过减少数据的响应式转换来提供前端的性能。

export default {  data: () => ({    users: {}  }),  async created() {    const users = await axios.get("/api/users");    this.users = Object.freeze(users);  }};

文章整理:

>juejin.cn/post/6854573215969181703

>segmentfault.com/a/1190000022341733

1.如果看到这里,说明你喜欢这篇文章,请 转发点赞、`在看`

2.关注公众号前端人,回复资料包领取我整理的前端进阶资料包

3.回复加群,加入前端进阶群,和小伙伴一起学习讨论!

13个技巧让你的 vue.js 代码更优雅

本文分享自微信公众号 - 前端人(FrontendPeople)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这