​博客地址:https://ainyi.com/95

本人玩了 Vue 两年多,在此总结一下开发时的一些技巧和方法

自定义组件 v-model

v-model 是 Vue 提供的一个语法糖,它本质上是由 value 属性 + input 事件组成的(都是原生的默认属性)

自定义组件中,可以通过传递 value 属性并监听 input 事件来实现数据的双向绑定

自定义组件

<template>
<div>
<input :value="value" @input="$_handleInput" />
</div>
</template> <script>
export default {
props: {
value: {
type: String,
default: ''
}
},
data() {
return {}
},
methods: {
$_handleInput(e) {
this.$emit('input', e.target.value)
}
}
}
</script>

父组件调用

<template>
<div class="home">
<krry-input v-model="say"></krry-input>
</div>
</template> <script>
export default {
name: 'Home',
components: {
KrryInput: () => import('@/components/KrryInput')
},
data() {
return {
say: 'haha'
}
}
}
</script>

函数式组件

简单说一下函数式组件

函数式组件就是函数是组件。使用过 React 的同学,应该不会对函数式组件感到陌生

函数式组件,我们可以理解为没有内部状态,没有生命周期钩子函数,没有 this(不需要实例化的组件)

由于它像函数一样轻巧,没有实例引用,所以渲染性能提高了不少

在日常开发中,经常会开发一些纯展示性的业务组件,比如一些详情页面,列表界面等,它们有一个共同的特点是只需要将外部传入的数据进行展现,不需要有内部状态,不需要在生命周期钩子函数里面做处理,这时候你就可以考虑使用函数式组件

export default {
// 通过配置 functional 属性指定组件为函数式组件
functional: true,
// 组件接收的外部属性,也可无需显式声明 props
props: {
avatar: {
type: String
}
},
/**
* 渲染函数
* @param {*} h
* @param {*} context 函数式组件没有 this, props, slots 等,都在 context 上面挂着
*/
render(h, context) {
const { props } = context
if (props.avatar) {
return <img src={props.avatar}></img>
}
return <img src="default-avatar.png"></img>
}
}

使用函数式组件的原因:

  1. 最主要最关键的原因是函数式组件不需要实例化,无状态,没有生命周期,所以渲染性能要好于普通组件
  2. 函数式组件结构比较简单,代码结构更清晰

函数式组件与普通组件的区别

  1. 函数式组件需要在组件上声明functional
  2. 函数式组件不需要实例化,所以没有 this,this通过render函数的第二个参数来代替
  3. 函数式组件没有生命周期钩子函数,不能使用计算属性、watch 等等
  4. 函数式组件不能通过 $emit 对外暴露事件,调用事件只能通过context.listeners.click的方式调用外部传入的事件
  5. 因为函数式组件是没有实例化的,所以在外部通过ref去引用组件时,实际引用的是 HTMLElement
  6. 函数式组件的props可以不用显式声明,所以没有在props里面声明的属性都会被自动隐式解析为 prop,而普通组件所有未声明的属性都被解析到 $attrs 里面,并自动挂载到组件根元素上面(可以通过 inheritAttrs 属性禁止)

模板语法声明函数式组件

在 Vue2.5 之前,使用函数式组件只能通过 JSX 的方式,在之后可以通过模板语法来声明函数式组件

<!-- 在 template 上面添加 functional 属性 -->
<template functional>
<img :src="props.avatar" />
</template>
<!-- 上面第 6 点,可不用显示声明 props -->

事件参数 $event

$event 是事件对象的一个特殊变量。它在某些场景下为复杂的功能提供了更多的可选参数

<template>
<img src="text.jpg" @click="handleClick($event)" />
</template> <script>
export default {
methods: {
handleClick (e) {
console.log(e)
}
}
}
</script>

EventBus

声明一个全局 Vue 实例变量 EventBus,把所有的通信数据、事件监听都存储到这个变量上

类似于 Vuex,但这种方式一般适用于小的项目

原理就是利用 on、emit 并实例化一个全局 vue 实现数据共享

可以实现平级、嵌套组件传值;但是对应的事件名 eventTarget 必须是全局唯一的

// 在 main.js
Vue.prototype.$eventBus = new Vue() // 传值组件
this.$eventBus.$emit('eventTarget','这是eventTarget传过来的值') // 接收组件
this.$eventBus.$on('eventTarget', v => {
console.log('eventTarget', v)
})

也可以新建一个 bus.js 文件

import Vue from 'vue'
export default new Vue()

在要通信的组件导入此文件,进行监听或发送

import Bus from '@/bus'

// 组件1
Bus.$emit('operateMusic', id) // 组件2
Bus.$on('operateMusic', id => {})

Mixin 混入

一般在 src 定义一个 mixins 文件夹,里面存放每个 mixin,用 index.js 文件汇总导出

index.js

import serviceMixinsModule from './service-mixins'
import tableListMixinsModule from './tableList-mixins' export const serviceMixins = serviceMixinsModule
export const tableListMixins = tableListMixinsModule // 组件中使用
// import { serviceMixins, tableListMixins } from '@/mixins'
// export default {
// mixins: [serviceMixins, tableListMixins],
// }

主要说说冲突问题

当组件和混入对象含有同名选项时,这些选项将以恰当的方式进行“合并”

比如,数据对象在内部会进行递归合并,并在发生冲突时以组件数据优先

let mixin = {
data: function () {
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" }
}
})

同名钩子函数将合并为一个数组,因此都将被调用。另外,混入对象的钩子将在组件自身钩子之前调用

let mixin = {
created: function () {
console.log('混入对象的钩子被调用')
}
} new Vue({
mixins: [mixin],
created: function () {
console.log('组件钩子被调用')
}
}) // => "混入对象的钩子被调用"
// => "组件钩子被调用"

值为对象的选项,例如 methods、components 和 directives,将被合并为同一个对象。两个对象键名冲突时,取组件对象的键值对

let mixin = {
methods: {
foo: function () {
console.log('foo')
},
conflicting: function () {
console.log('from mixin')
}
}
} let vm = new Vue({
mixins: [mixin],
methods: {
bar: function () {
console.log('bar')
},
conflicting: function () {
console.log('from self')
}
}
}) vm.foo() // => "foo"
vm.bar() // => "bar"
vm.conflicting() // => "from self"

注意:Vue.extend() 也使用同样的策略进行合并

路由参数解耦

相信这是大多数人处理组件中路由参数的方式:

export default {
computed: {
paramsId() {
return this.$route.params.id
}
}
}

在组件内部使用 $route 会对某个URL产生强耦合,这限制了组件的灵活性

正确的解决方案是向路由器添加 props

const router = new VueRouter({
routes: [{
path: '/:id',
component: Component,
props: true
}]
})

这样,组件可以直接从 props 获取 params

export default {
props: ['id'],
computed: {
paramsId() {
return this.id
}
}
}

此外,你还可以传入函数以返回自定义 props

const router = new VueRouter({
routes: [{
path: '/:id',
component: Component,
props: router => ({ id: route.query.id })
}]
})

hook 妙用

如果在页面挂载时增加一个定时器,但销毁时需要清除定时器

一般想法是在 beforeDestroy 中使用 clearInterval(this.timer) 来清除

export default {
data () {
return {
timer: null
}
},
mounted () {
this.timer = setInterval(() => {
console.log(Date.now())
}, 1000)
},
beforeDestroy () {
clearInterval(this.timer)
}
}

还有种更方便的方法,使用 $once 监听 hook 函数

export default {
mounted () {
let timer = null
timer = setInterval(() => {
console.log(Date.now())
}, 1000)
this.$once('hook:beforeDestroy', () => {
clearInterval(timer)
})
}
}

监听子组件生命周期 Hook

通常,可以像这样监听子组件的生命周期(例如 mounted)

<!-- Child -->
<script>
export default {
mounted () {
this.$emit('onMounted')
}
}
</script> <!-- Parent -->
<template>
<Child @onMounted="handleOnMounted" />
</template>

还有另一种简单的解决方案,可以改用 @hook:mounted 在父组件直接监听

<!-- Parent -->
<template>
<Child @hook:mounted="handleOnMounted" />
</template>

挂载全局变量

Vue.prototype.$lang = Lang

// 可以在任何一个组件使用 this.$lang

Watcher 技巧

watch 的深度监听deep: true 和 立即触发immediate: true 就不多说了

需要注意的是深度监听deep: true 只能监听原有属性的变化,不能监听新增、删除的属性

还有一个有趣的特性,随时监听,随时取消,$watch

const unwatch = this.$watch('say', curVal => {
console.log('数据发生了变化', curVal)
}, {
deep: true,
immediate: true // 是否第一次触发
})
setTimeout(() => {
unwatch()
}, 3000)

this.$watch 的返回值 unwatch 是个方法,执行后就可以取消监听

传送门

Vue 自定义指令

Vue3 为何使用 Proxy 实现数据监听

Vue JSX、自定义 v-model

Vue.nextTick 的应用解析

Vue 路由模块化配置

关于 Vue 不能 watch 数组 和 对象变化的解决方案

Vue.mixin

Vuex 相关理解

Vue 知识总结

​博客地址:https://ainyi.com/95

Vue 开发技巧总结的更多相关文章

  1. Vue 开发技巧或者说Vue知识点梳理(转,自个学习)

    Vue 组件通讯 ——常见使用场景可以分为三类: 父子通信: 父向子传递数据是通过 props,子向父是通过 events($emit):通过父链 / 子链也可以通信($parent / $child ...

  2. 10个Vue开发技巧助力成为更好的工程师·二

    优雅更新props 更新 prop 在业务中是很常见的需求,但在子组件中不允许直接修改 prop,因为这种做法不符合单向数据流的原则,在开发模式下还会报出警告.因此大多数人会通过 $emit 触发自定 ...

  3. vue -- 7 个 有用的 Vue 开发技巧

    1 状态共享 随着组件的细化,就会遇到多组件状态共享的情况, Vuex当然可以解决这类问题,不过就像 Vuex官方文档所说的,如果应用不够大,为避免代码繁琐冗余,最好不要使用它,今天我们介绍的是 vu ...

  4. vue开发必须知道的小技巧

    近年来,vue越来越火,使用它的人也越来越多.vue基本用法很容易上手,但是还有很多优化的写法你就不一定知道了.本文列举了一些vue常用的开发技巧.require.context() 在实际开发中,绝 ...

  5. 微信小程序入门与实战 常用组件API开发技巧项目实战*全

    第1章 什么是微信小程序? 第2章 小程序环境搭建与开发工具介绍 第3章 从一个简单的“欢迎“页面开始小程序之旅 第4章 第二个页面:新闻阅读列表 第5章 小程序的模板化与模块化 第6章 构建新闻详情 ...

  6. SQL开发技巧(二)

    本系列文章旨在收集在开发过程中遇到的一些常用的SQL语句,然后整理归档,本系列文章基于SQLServer系列,且版本为SQLServer2005及以上-- 文章系列目录 SQL开发技巧(一) SQL开 ...

  7. DelphiXE2 DataSnap开发技巧收集

    DelphiXE2 DataSnap开发技巧收集 作者:  2012-08-07 09:12:52     分类:Delphi     标签: 作为DelphiXE2 DataSnap开发的私家锦囊, ...

  8. delphi XE5下安卓开发技巧

    delphi XE5下安卓开发技巧 一.手机快捷方式显示中文名称 project->options->Version Info-label(改成需要显示的中文名即可),但是需要安装到安卓手 ...

  9. 经典收藏 50个jQuery Mobile开发技巧集萃

    http://www.cnblogs.com/chu888chu888/archive/2011/11/10/2244181.html 1.Backbone移动实例 这是在Safari中运行的一款Ba ...

随机推荐

  1. Python File write() 方法

    概述 write() 方法用于向文件中写入指定字符串.高佣联盟 www.cgewang.com 在文件关闭前或缓冲区刷新前,字符串内容存储在缓冲区中,这时你在文件中是看不到写入的内容的. 如果文件打开 ...

  2. 教你在 Linux 下时光穿梭

    时光穿梭?电影里的桥段吧?良许你又在唬人? 非也非也,良许在这里要给大家介绍 touch 命令,有了它你就可以改变时间戳,达到时光穿梭的目的. touch 命令在我们的工作中使用也相当频繁,我们就由浅 ...

  3. samba服务及配置

    samba 目录 samba 1. samba简介 2. samba访问 配置示例 3.搭建用户认证共享服务器 4.搭建匿名用户共享服务器 1. samba简介 Samba是在Linux和UNIX系统 ...

  4. 对Word2Vec的理解

    1. word embedding 在NLP领域,首先要把文字或者语言转化为计算机能处理的形式.一般来说计算机只能处理数值型的数据,所以,在NLP的开始,有一个很重要的工作,就是将文字转化为数字,把这 ...

  5. three.js 着色器材质之glsl内置函数

    郭先生发现在开始学习three.js着色器材质时,我们经常会无从下手,辛苦写下的着色器,也会因莫名的报错而手足无措.原因是着色器材质它涉及到另一种语言–GLSL,只有懂了这个语言,我们才能更好的写出着 ...

  6. Azure DevOps+Docker+Asp.NET Core 实现CI/CD(一 .简介与创建自己的代理池)

    前言 本文主要是讲解如何使用Azure DevOps+Docker 来实现持续集成Asp.NET Core项目(当然 也可以是任意项目). 打算用三个篇幅来记录完整的全过程 觉得有帮助的朋友~可以左上 ...

  7. Python 中 3 个不可思议的返回

    第一个:神奇的字典键 some_dict = {} some_dict[5.5] = "Ruby" some_dict[5.0] = "JavaScript" ...

  8. Python数据类型-dic,set常见操作

    字典常见方法   语法:字典名[新key]=value 功能:给字典增加键值 语法:字典名[字典里存在的key]=新的value 功能:修改字典里的值   功能:删除字典的元素,通过key来进行删除, ...

  9. Paper English

    论文中的英语 单词 a arange 整理 ambiguity 含糊的 aggregate 总量 auxiliary 辅助的 alleviate 缓解 aberrant 异常的 akin 类似的 Ac ...

  10. 8、Builder 建造者模式 组装复杂的实例 创造型模式

    1.什么是Builder模式 定义: 将一个复杂对象的构建与表示相分离,使得同样的构建过程可以创建不同的表示.大白话就是,你不需要知道这个类的内部是什么样的,只用把想使用的参数传进去就可以了,达到了解 ...