vue开发者必须知道的实用技术点!

更新日期: 2022-06-12阅读: 948标签: vue

前言

vue 作为目前前端三大框架之一,对于前端开发者可以说是必备技能。掌握这些实用小技巧,可以让你事半功倍。

1、路由懒加载,能让你首次加载更快

路由懒加载可以让我们的包不需要一次把所有的页面的加载进来,只加载当前页面的路由组件就行。

举个栗子,如果这样写,加载的时候会全部都加载进来。

const router = new VueRouter({
routes:[
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: About
}
]
})

所以,应该避免上面的写法,尽量使用懒加载。

路由的懒加载可以分为以下三种写法。

  • Vue异步组件
  • es6的import
  • webpack提供的require.ensure()
// 1、Vue异步组件
VueRouter({
routes:[
{
path: '/about',
name: 'About',
component: resolve => reqire(['path路径'], resolve)
}
]
})

// 2、es6的import
VueRouter({
routes:[
{
path: '/about',
name: 'About',
component: () => import('path路径')
}
]
})

// 3、webpack提供的require.ensure()
VueRouter({
routes:[
{
path: '/about',
name: 'About',
component: r => require.ensure([],() => r(require('path路径')), 'demo')
}
]
})


2、异步组件

异步组件可以让我们在需要一些组件时才将它加载进来,而不是一初始化就加载进来,这跟路由懒加载是一个概念。

以前是这么引入组件的

import BureauDetail from './components/ChildFirst'
import addBureau from './components/ChildSecond'

//在vue的comoinents中
components: {
ChildFirst,
ChildSecond
}

如果不是一开始就要加载的组件,我们可以使用组件懒加载

//在vue的comoinents中
components: {
BureauDetail: () => import('./components/ChildFirst'),
addBureau: () => import('./components/ChildSecond')
},

异步组件还有一种比较完善的写法

export default {
components:{
ChildFirst:()=>({
component:import(/* webpackChunkName: "ChildFirst" */ './Async'),
delay:200, // 延迟几毫秒,默认200
timeout:3000, // 加载几毫米之后就超时,触发error组件
loading:LoadingComponent, // 组件未加载回来前显示
error:ErrorComponent // 组件超时时显示
})
}
}


3、require.context()引入多个组件

常常用来在组件内引入多个组件, require.context(directory, useSubdirectories, regExp)

原始写法:

// 原始写法
import titleCom from '@/components/home/titleCom'
import bannerCom from '@/components/home/bannerCom'
import cellCom from '@/components/home/cellCom'
components: {
titleCom, bannerCom, cellCom
}

这样就写了大量重复的代码,利用 require.context 可以写成

const path = require('path')
const files = require.context('@/components/home', false, /\.vue$/)
const modules = {}
files.keys().forEach(key => {
const name = path.basename(key, '.vue')
modules[name] = files(key).default || files(key)
})
components: modules

在main.js中引入大量公共组件,利用 require.context 可以写成

import Vue from 'vue'
// 自定义组件
const requireComponents = require.context('../views/components', true, /\.vue/)
// 打印结果
// 遍历出每个组件的路径
requireComponents.keys().forEach(fileName => {
// 组件实例
const reqCom = requireComponents(fileName)
// 截取路径作为组件名
const reqComName =reqCom.name|| fileName.replace(/\.\/(.*)\.vue/,'$1')
// 组件挂载
Vue.component(reqComName, reqCom.default || reqCom)
})


4、在父组件里监听子组件的生命周期

比如有父组件 Parent 和子组件 Child,如果父组件监听到子组件挂载 mounted 就做一些逻辑处理,常规的写法可能如下:

// Parent.vue
<Child @mounted="doSomething"/>

// Child.vue
mounted() {
this.$emit("mounted");
}

此外,还有一种特别简单的方式,子组件不需要任何处理,只需要在父组件引用的时候通过@hook 来监听即可,@hook也可以监听其它的生命周期事件,代码如下:

<Child @hook:mounted="doSomething" /> 
<Child @hook:updated="doSomething" />


5、computed中使用this?

在computed属性中通过this.xxx去拿data里面的数据,和methods里面的方法吧,或许还会通过this.$store去拿vuex的state,和commit等,甚至,还会通过this.$route去获取路由里面的数据吧。

其实,我们可以避免这些丑陋的this,它甚至会给我们带来看不见的性能问题。

实现上,我们通过this能访问到的数据,在computed的第一个参数上都能结构出来。

export default {
watch: {
haha({$attrs,$route,$store,$listeners,$ref}){
// 还能结构很多属性,可自行打印看看
return
}
}
}


6、初始化的时候,让watch立即执行

watch每当监听的数据变化时都会执行回调进行后续操作。

但是当 watch 一个变量的时候,在页面或者组件初始化时并不会执行,如下面的例子,你需要在 created 的时候手动调用一次。

created() {
this.getList();
},
watch: {
keyWord: 'getList',
}

上面这样的做法可以使用,但很麻烦,我们可以添加 immediate 属性,这样初始化的时候就会自动触发

watch 有三个参数

  • handler:其值是一个回调函数。即监听到变化时应该执行的函数
  • deep:其值是 true 或 false;确认是否深入监听。当要监听数组或对象等引用类型数据时,可以使用deep属性
  • immediate:其值是 true 或 false,确认是否以当前的初始值执行 handler 的函数
watch: {
keyWord: {
handler(val) {},
immediate: true
}
}


7、递归组件自己调用自己

递归组件: 组件在它的模板内可以递归的调用自己,只要给组件设置 name 组件就可以了。

注意:必须给一个条件来限制数量,否则会抛出错误: max stack size exceeded

<template>
<div v-for="(item,index) in treeArr"> {{index}} <br/>
<tree :item="item.arr" v-if="item.flag"></tree>
</div>
</template>
<script>
export default {
// 必须定义name,组件内部才能递归调用
name: 'tree',
data(){
return {}
},
// 接收外部传入的值
props: {
item: {
type:Array,
default: ()=>[]
}
}
}
</script>

看Element ui源码时,封装的tree控件、级联选择其,也是这么使用的。



8、object.freeze性能优化

vue 2.0版本会通过 object.defineProperty 对数据进行劫持,遇到数组和对象必须循环遍历所有的域值才能劫持每一个属性。

vue 3.0版本会通过Proxy构造函数来进行数据劫持,来实现视图响应数据的变化

然而有些时候我们的组件就是纯粹的数据展示,不会有任何改变,我们就不需要 vue 来劫持我们的数据,在大量数据展示的情况下,这能够很明显的减少组件初始化的时间。

所以,我们可以通过 object.freeze 方法来冻结一个对象,这个对象一旦被冻结,vue就不会对数据进行劫持了。

Object.freeze() 可以冻结一个对象,冻结之后不能向这个对象添加新的属性,不能修改其已有属性的值,不能删除已有属性,以及不能修改该对象已有属性的可枚举性、可配置性、可写性。该方法返回被冻结的对象。

<p v-for="item in list">{{ item.value }}</p>

export default {
data: {
// vue不会对list里的object做getter、setter绑定
list: Object.freeze([
{ value: 1 },
{ value: 2 }
])
},
created () {
// 界面不会有响应
this.list[0].value = 100;

// 下面两种做法,界面都会响应
this.list = [
{ value: 100 },
{ value: 200 }
];
this.list = Object.freeze([
{ value: 100 },
{ value: 200 }
]);
}}


9、修改引用类型的数据,视图不更新?

当vue的data里边声明或者已经赋值过的对象或者数组(数组里边的值是对象)时,向对象中添加新的属性,如果更新此属性的值,是不会更新视图的。

调用方法: this.$set( target , key , value)

  • target: 要更改的数据源(可以是一个对象或者数组)
  • key 要更改的具体数据 (索引)
  • value 重新赋的值
export default {
name: 'App',
data () {
return {
items: [
{ message: "one", id: "1" },
{ message: "two", id: "2" },
{ message: "three", id: "3" }
]
}
},
mounted () {
//此时对象的值更改了,但是视图没有更新
this.items[0] = { message:'first',id:'4'}

//$set 可以触发更新视图
this.$set(this.items,0,art)
},
methods: {
handClick(){
let change = this.items[0]
change.message="shen"
//$set 可以触发更新视图
this.$set(this.items,0,change)
}
}
}
</script>


10、.sync修饰符

.sync提供了一种与父组件沟通的思路!你如果只是单纯的在子组件当中修改父组件的某个数据时,建议使用sync,简单,快捷,不需要在传一个自定义方法来接收了

vue中我们经常会用v-bind(缩写为:)给子组件传入参数。或者我们会给子组件传入一个函数,子组件通过调用传入的函数来改变父组件的状态。举个例子

//父组件 给子组件传入一个函数
<MyFooter :age="age" @setAge="(res)=> age = res">
</MyFooter>


//子组件 通过调用这个函数来实现修改父组件的状态。
mounted () {
console.log(this.$emit('setAge',1234567));
}

现在只需要使用.sync就可以轻松更新赋组件的值

//父组件 将age传给子组件并使用.sync修饰符。
<MyFooter :age.sync="age">
</MyFooter>


//子组件 触发事件
mounted () {
console.log(this.$emit('update:age',1234567));
}


11、Vue.mixin混入,复用代码

混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。

通俗的说,mixin可以定义公用的data,created,methods,computed,watch等。然后混入到你当前的vue文件中。

minxin还有一个强大之处就是合并选项,相同的变量/方法名会合并在一起,如果有相同名字,当前文件的变量或者方法会覆盖mixin文件的名字或者方法。

  • data对象在内部会进行递归合并,并在发生冲突时以组件数据优先。
  • 同名钩子函数将合并为一个数组,因此都将被调用。混入对象的钩子将在组件自身钩子之前调用。
  • 值为对象的选项,例如 methods、components 和 directives,将被合并为同一个对象。两个对象键名冲突时,取组件对象的键值对。

1、定义一个 mixin.js

export default mixin {
data() {
return {
name: 'mixin'
}
},
created() {
console.log('mixin...', this.name);
},
mounted() {},
methods: { //日期转换
formatDate (dateTime, fmt = 'YYYY年MM月DD日 HH:mm:ss') {
if (!dateTime) {
return ''
}
moment.locale('zh-CN')
dateTime = moment(dateTime).format(fmt)
return dateTime
}
}
}

2、在vue文件中使用mixin

import '@/mixin'; // 引入mixin文件
export default {
mixins: [mixin], //用法
data() {
return {
userName: "adimin",
time: this.formatDate(new Date()) //这个vue文件的数据源data里面的time就是引用混入进来的方法
}
}
}


12、provide/inject

常用的父子组件通信方式都是父组件绑定要传递给子组件的数据,子组件通过props属性接收,一旦组件层级变多时,采用这种方式一级一级传递值非常麻烦,而且代码可读性不高,不便后期维护。

vue提供了provide和inject帮助我们解决多层次嵌套嵌套通信问题。在provide中指定要传递给子孙组件的数据,子孙组件通过inject注入祖父组件传递过来的数据。

其实,provide 和 inject 主要为高阶插件/组件库提供用例。

读Element UI源码时,发现很多高阶组件使用了provide和inject,减少了很多父组件向子组件以及孙子组件一层层通信的工作量。

elementUI组件库中,在el-form组件中将组件实例暴露给子孙组件


在el-form-item组件中注入el-form组件实例,然后就可以使用el-form组件实例的方法、变量等等


1、在父组件中provide提供变量

<template>
<div>
<p>{{ title }}</p>
<son></son>
</div>
</template>
<script>
import Son from "./son"
export default {
name: 'Father',
components: { Son },
// provide选项提供变量
provide: {
message: 'provided by father'
},
data () {
return {
title: '父组件'
}
},
methods: { ... }
}
</script>

2、在子孙组件中,都可以使用inject来注入

<template>
<div>
<p>message:{{ message }}</p>
</div>
</template>
<script>
export default {
name: "GrandSon",
inject: [ "message" ],
data () {
return {
title: '孙组件'
}
},
methods: { ... }
};
</script>
以上文章来源于公众号:javascript艺术 ,作者:zhangjing


链接: https://fly63.com/article/detial/11711

VueJS 实际开发中会遇到的问题

VueJS 实际开发中会遇到的问题,主要写一些 官方手册 上没有写,但是实际开发中会遇到的问题,需要一定知识基础。

vue与后台交互ajax数据

Vue.js是一套构建用户界面的渐进式的前端框架。 vueJS与后台交互数据的方法我所了解的有以下几种

Vuejs讲解之:响应式、过渡效果、过渡状态

Vue是一套构建用户界面的JS渐进式框架。 Vue 只关注视图层, 采用自底向上增量开发的设计。讲解js高级之响应式、过渡效果、过渡状态。

Vue响应式开发,深入理解Vue.js响应式原理

深入理解Vue.js响应式原理。Vue教程有关的视频都讲到,我习惯响应式开发,在更早的Angular1时代,我们叫它:数据绑定(Data Binding)。你只需要在Vue实例的 data() 块中定义一些数据,并绑定到HTML

vue中慎用style的scoped属性

在vue组件中,为了使样式私有化(模块化),不对全局造成污染,可以在style标签上添加scoped属性以表示它的只属于当下的模块,这是一个非常好的举措,但是为什么要慎用呢?因为scoped往往会造成我们在修改公共组件(三方库或者项目定制的组件)的样式困难,需要增加额外的工作量

基于vue移动端UI框架有哪些?vue移动端UI框架总汇

vue现在使用的人越来越多了,这篇文章主要整理一些比较优秀的移动端ui框架,推荐给大家,例如:mint UI、vux、vonic、vant、cube-ui、Muse-ui、Vue-Carbon、YDUI等

使用webpack提升vue应用的4种方式

webpack是开发Vue单页应用必不可少的工具,它能管理复杂的构建步骤,并且优化你的应用大小和性能, 使你的开发工作流更加简单。在这篇文章中,我将解释使用webpack提升你的Vue应用的4种方式,包括:单文件组件、优化Vue构建过程、浏览器缓存管理、代码分离

Vue2.0用户权限控制解决方案

Vue-Access-Control是一套基于Vue/Vue-Router/axios 实现的前端用户权限控制解决方案,通过对路由、视图、请求三个层面的控制,使开发者可以实现任意颗粒度的用户权限控制。

组件化的概念/特性/优点,Vue组件的使用

Web 中的组件其实就是页面组成的一部分,具有高内聚性,低耦合度,互冲突等特点,有利于提高开发效率,方便重复使用,简化调试步骤等。vue 中的组件是一个自定义标签形式,扩展原生的html元素,封装可重用的代码。

Vue2实例详解与生命周期

Vue的实例是Vue框架的入口,其实也就是前端的ViewModel,它包含了页面中的业务逻辑处理、数据模型等,当然它也有自己的一系列的生命周期的事件钩子,辅助我们进行对整个Vue实例生成、编译、挂着、销毁等过程进行js控制。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!