Vue面试

Vue生命周期:

https://www.jianshu.com/p/a921cd6aeaa7?from=timeline
创建期:before create, created, before mount, mounted
运行期:beforUpdate, updated
销毁期:beforeDestroy, destroyed

keep-alive
包裹动态组件时,会缓存不活动的组件实例,主要用于保留组件状态或避免重新渲染。
解析: 比如有一个列表和一个详情,那么用户就会经常执行打开详情=>返回列表=>打开详情…这样的话列表和详情都是一个频率很高的页面,那么就可以对列表组件使用进行缓存,这样用户每次返回列表的时候,都能从缓存中快速渲染,而不是重新渲染

destroy:
组件销毁时使用(如v-if),beforeDestroy 中操作,常用来销毁一些监听事件及定时函数。貌似刷新不会执行destroy。


父子组件执行生命周期:

父组件先创建,然后子组件创建;子组件先挂载,然后父组件挂载,即“父beforeCreate-> 父created -> 子beforeCreate-> 子created -> 子mounted -> 父mounted”
**注意:**在父组件传递接口的数据给子组件时,最好在子组件标签上加上v-if=“传递的接口数据”
在父组件调用接口传递数据给子组件时,接口响应显然是异步的。当子组件的mounted都执行完之后,此时可能父组件的请求才返回数据。会导致,从父组件传递给子组件的数据是undefined。

解决方法1:
在渲染子组件的时候加上一个条件,data1是父组件调用接口返回的数据。当有数据的时候在去渲染子组件。

<div class="test">
    <children v-if="data1" :data="data1" ></children>
</div>

解决方法2:
在子组件中 watch 监听,父组件获取到值,这个值就会变化,自然是可以监听到的

props:['data1'],
watch:{
    data1:{
      deep:true,
      handler:function(newVal,oldVal) {
        this.$nextTick(() => {
          this.data1 = newVal
          this.showData1(this.data1)
        })
      }
    },
}

vue和jQuery区别

jquery:轻量级的js库,jQuery是使用选择器( ) 选 取 D O M 对 象 , 对 其 进 行 赋 值 、 取 值 、 事 件 绑 定 等 操 作 , 其 实 和 原 生 的 H T M L 的 区 别 只 在 于 可 以 更 方 便 的 选 取 和 操 作 D O M 对 象 , 而 数 据 和 界 面 是 在 一 起 的 。 比 如 需 要 获 取 l a b e l 标 签 的 内 容 : )选取DOM对象,对其进行赋值、取值、事件绑定等操作,其实和原生的HTML的区别只在于可以更方便的选取和操作DOM对象,而数据和界面是在一起的。比如需要获取label标签的内容: DOMHTML便DOMlabel(“lable”).val();,它还是依赖DOM元素的值。
vue:前端js框架,它专注于MVVM模型的viewModel层,通过Vue对象把数据和View完全分离开来,对数据进行操作不再需要引用相应的DOM对象,可以说数据和View是分离的。通过数据绑定把view和model层连接起来,通过对数据的操作就可以完成对页面视图的渲染。

扩展:

  1. vue适用的场景:复杂数据操作的后台页面,表单填写页面
  2. jquery适用的场景:比如说一些html5的动画页面,一些需要js来操作页面样式的页面
    二者也是可以结合起来一起使用的,vue侧重数据绑定,jquery侧重样式操作,动画效果等,则会更加高效率的完成业务需求

vue单页面和传统的多页面区别?

单页面应用(SPA)
通俗一点说就是指只有一个主页面的应用,浏览器一开始要加载所有必须的 html, js, css。所有的页面内容都包含在这个所谓的主页面中。但在写的时候,还是会分开写(页面片段),然后在交互的时候由路由程序动态载入,单页面的页面跳转,仅刷新局部资源。多应用于pc端。

多页面(MPA)
指一个应用中有多个页面,页面跳转时是整页刷新

单页面的优点:
用户体验好,快,内容的改变不需要重新加载整个页面,基于这一点spa对服务器压力较小;前后端分离;页面效果会比较炫酷(比如切换页面内容时的专场动画)。

单页面缺点:
不利于seo;导航不可用,如果一定要导航需要自行实现前进、后退。(由于是单页面不能用浏览器的前进后退功能,所以需要自己建立堆栈管理);初次加载时耗时多;页面复杂度提高很多。

衍生如何解决单页及多页面各自优点的问题:服务端渲染

一、Vue使用

1. 基本使用,组件使用——常用,必须会

1.1 指令、插值

插值表达式
指令、动态属性
x-html :会有XSS风险,会覆盖子组件

表单

v-model
常见表单项textarea checkbox radio select
修饰符lazy number trim

组件使用

组件间通讯

父子,兄弟
props和$emit
组件间通讯-自定义事件

组件生命周期 (important)

挂载阶段 before create, created, before mount, mounted
更新阶段 beforUpdate, updated
销毁阶段 beforeDestroy, destroyed

created 和 mounted 什么区别?
created 之后 检查 el 和 template,created 只是把Vue的实例初始化了,只是存在于js内存中的一个变量,并没有开始渲染。
mounted 是真正在网页上渲染完成了,大部分在mounted里进行操作 。

beforeDestroy 做哪些事?
解除绑定、销毁子组件以及事件监听器

带有父子组件的生命周期:
谁先被mounted,数据被修改后父组件先update还是子组件先updated,销毁顺序
创建和渲染:
index created -> list created -> list mounted -> index mounted。 创建是从外到内,渲染是从内到外。
update:
index before update -> list before update -> list updated -> index updated

data 为什么返回函数

组件中的data写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。
vue文件被vue-loader处理,template被编译成render函数。通常在使用vue的时候是在vue文件中export出一个对象,这个时候如果将data定义为一个对象。使用的时候通过import导入,经过babel编译,将导出的对象直接替换成了一个对象变量,然后将这个变量传入到对应的组件构造函数中。

2. 高级特性——不常用 ,但体现深度

自定义v-model

栗子:颜色选择器

$nextTick

Vue是异步渲染,data改变之后, DOM不会立刻渲染,$nextTick会在DOM渲染之后被触发,以获取最新DOM节点。
1.异步渲染,$nextTick 待DOM渲染完再回调
3.页面渲染时会将data 的修改做整合,多次data 修改只会渲染一次(同步渲染就会改一次渲染一次)

汇总data的修改, 一次性更新视图
目的是减少DOM操作次数,提高性能

实现思路:
第一,同步修改 data 时,把修改操作汇总到一个队列中
第二,再异步时取得这个队列,将其中的修改数据汇总,就像 Object.assign
第三,用汇总的结果统一修改 data ,触发试图更新

补充:vue中可用$ref.name 来获取到dom

slot

父组件向子组件传递 标签中的内容,在使用时候会用子元素或子节点替换slot标签。
匿名插槽
具名插槽
作用域插槽:
父组件复用子组件的slot(及其中数据),又可以使slot内容不一致。父组件不仅要向子组件中传递插槽,还要使用子组件定义的数据。
父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。
slot-scope

子组件 Link.vue:
<template>
    <a :href="url">
        <slot :slotData="website">  把子组件变量暴露到插槽作用域。slotData名称可以自定义
            {{website.subTitle}}
        </slot>
    </a>
</template>

父组件调用:
<ScopedSlotDemo :url="website.url">
    <template v-slot="slotProps">
        {{slotProps.slotData.title}}
    </template>
</ScopedSlotDemo>

动态、异步组件

动态组件:
:is= "component-name” 用法
需要根据数据,动态渲染的场景。即组件类型不确定。

异步组件:
有些组件体积非常大,代码编辑器,echarts这些用到
什么时候用什么时候加载
() => import(’…/…’)

keep-alive

缓存组件,频繁切换,不需要重复渲染。用包裹。通常用于tab切换。

mixin

多个组件有相同的逻辑,抽离出来。mixin并不是完美的解决方案,会有一些问题。Vue3提出的Composition API旨在解决这些问题
mixins: [myMixin]

问题:
变量来源不明确,不利于阅读
多mixin可能会造成命名冲突
mixin和组件可能出现多对多的关系,复杂度较高

vuex

基本概念:state, getters, action, mutation
用于vue组件:dispatch, commit, mapState, mapGetters, mapActions, mapMutations

scoped

实现组件的私有化,不对全局造成样式污染,表示当前style属性只属于当前模块。

实现原理:

  1. 在DOM结构加上data-v 的自定义属性,利用css样式属性选择器,保证唯一。
  2. 如果组件内部还有组件,只会给最外层的组件里的标签加上唯一属性字段,不影响组件内部引用的组件( 注意 )

问题:

  1. 父组件无scoped属性,子组件带有scoped,父组件是无法操作子组件的样式的
  2. 父组件有scoped属性,子组件无,父组件也无法设置子组件样式
  3. 父子组件都有,同理也无法设置样式,更改起来增加代码量

二、Vue原理

v-show和v-if的区别
为何v-for中要用key
描述Vue组件生命周期(有父子组件的情况)
Vue组件如何通讯
描述组件渲染和更新的过程
双向数据绑定v-model的实现原理

1. 组件化基础

如何理解MVVM模型

"很久以前”就有组件化:
asp jsp php已经有组件化了,nodejs中也有类似的组件化(后端)
但是,传统组件,只是静态渲染,更新还要依赖于操作DOM
数据驱动视图- Vue MVVM
数据驱动视图- React setState (暂时按下不表) , 通过数据操作(重新渲染)视图。
更加关注数据(业务逻辑)

数据驱动视图( MVVM , setState )
在这里插入图片描述

2. 响应式

组件data的数据一旦变化,立刻触发视图的更新。
实现数据驱动视图的第一步,考察Vue原理的第一题。

核心API - Object.defineProperty
如何实现响应式,代码演示
Object.defineProperty的一些缺点( Vue3.0启用Proxy,Proxy有兼容性问题 )

核心机制是 观察者模式。数据是被观察的一方,发生改变时,通知所有的观察者,这样观察者可以做出响应,比如,重新渲染然后更新视图。通过 Object.defineProperty() 替换配置对象属性的 set、get 方法,实现“拦截”;watcher 在执行 getter 函数时触发数据的 get 方法,从而建立依赖关系;更改数据时触发 set 方法,从而借助 dep 发布通知,进而 watcher 进行更新。

2.1 Object.defineProperty基本用法:

在这里插入图片描述

2.2 监听对象,监听数组

见代码

2.3 复杂对象,深度监听

// 触发更新视图
function updateView() {
    console.log('视图更新')
}

// 重新定义数组原型
const oldArrayProperty = Array.prototype
// 创建新对象,原型(__proto__)指向 oldArrayProperty ,再扩展新的方法不会影响原型
const arrProto = Object.create(oldArrayProperty);
['push', 'pop', 'shift', 'unshift', 'splice'].forEach(methodName => {
    arrProto[methodName] = function () {
        updateView() // 触发视图更新
        oldArrayProperty[methodName].call(this, ...arguments)
        // Array.prototype.push.call(this, ...arguments)
    }
})

// 重新定义属性,监听起来
function defineReactive(target, key, value) {
    // 深度监听,判断是否是对象,不是的直接返回
    observer(value)

    // 核心 API
    Object.defineProperty(target, key, {
        get() {
            return value
        },
        set(newValue) {
            if (newValue !== value) {
                // 深度监听,如果被设置的新值也是对象
                observer(newValue)

                // 设置新值
                // 注意,value 一直在闭包中,此处设置完之后,再 get 时也是会获取最新的值
                value = newValue

                // 触发更新视图
                updateView()
            }
        }
    })
}

// 监听对象属性
function observer(target) {
    if (typeof target !== 'object' || target === null) {
        // 不是对象或数组
        return target
    }

    // 污染全局的 Array 原型
    // Array.prototype.push = function () {
    //     updateView()
    //     ...
    // }

    if (Array.isArray(target)) {
    	// 当值为数组,让它的原型指向 新对象,这个对象重写了Array中的原型方法,即添加了视图渲染,再更新值
        target.__proto__ = arrProto
    }

    // 重新定义各个属性(for in 也可以遍历数组)
    for (let key in target) {
        defineReactive(target, key, target[key])
    }
}

// 准备数据
const data = {
    name: 'zhangsan',
    age: 20,
    info: {
        address: '北京' // 需要深度监听
    },
    nums: [10, 20, 30]
}

// 监听数据
observer(data)

// 测试
// data.name = 'lisi'
// data.age = 21
// // console.log('age', data.age)
// data.x = '100' // 新增属性,监听不到 —— 所以有 Vue.set
// delete data.name // 删除属性,监听不到 —— 所有已 Vue.delete
// data.info.address = '上海' // 深度监听
data.nums.push(4) // 监听数组

2.5 简易demo

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>双向绑定最最最初级demo</title>
        <meta charset="UTF-8">
    </head>
    <body>
        <div id="app">
            <input type="text" id="txt">
            <p id="show-txt"></p>
        </div>
    </body>
    <script>
        var obj={}
        Object.defineProperty(obj,'txt',{
            get:function(){
                return obj
            },
            set:function(newValue){
                document.getElementById('txt').value = newValue
                document.getElementById('show-txt').innerHTML = newValue
            }
        })
        document.addEventListener('keyup',function(e){
            obj.txt = e.target.value
        })
    </script>
</html>

2.4 几个缺点

深度监听时,需要递归到底, 一次性计算量大
无法监听新增属性/删除属性( 需要用Vue.set Vue.delete )
无法原生监听数组,需要特殊处理

3. 虚拟DOM(virtual dom)和diff

3.1 vdom

vdom是实现vue和React的重要基石
diff算法是vdom中最核心、最关键的部分
以前用jQuery ,可以自行控制DOM操作的时机,手动调整
Vue和React是数据驱动视图,如何有效控制DOM操作? - vdom
有了一定复杂度,想减少计算次数比较难
能不能把计算,更多的转移为JS计算?因为JS执行速度很快
vdom-用JS模拟DOM结构,计算出最小的变更, 操作DOM
下图最好能记住(面试题:用vnode 模拟 html 片段)

DOM操作非常耗费性能,JS执行速度比DOM更新速度快很多,vdom就是尽量用JS模拟DOM结构,进行对比计算后找出最需要更新的 dom 去更新。这个js对象通常包含tag,props,children这些结构。对比的过程就是diff算法
在这里插入图片描述
vdom 优化 dom 操作:尽量将所有计算都放在 js 中,进行对比计算后找出最需要更新的 dom 去更新。

snabbdom: h函数(传入标签,属性,子元素,生成vnode),vnode数据结构,patch 函数(可以做首次渲染,即将虚拟节点渲染到真正的节点上,或者DOM更新)。(vue参考它实现的)
在patch过程中会遍历整个树结构,并且挨个执行patchVnode函数,传入两个参数,分别是旧的vNode和新的vNode,如果旧节点有子节点但新节点没有,那么直接删除旧节点的子节点;如果旧节点没有子节点但新节点有,那么直接添加子节点;如果两个都有子节点,就会执行updateChildren函数。
updateChildren函数会分别给两个子节点列表设置两个头尾指针,用于标记对比。头和头,尾和尾,头和尾,尾和头,根据tag和key是否相等判断是否是相同节点,命中了就移动指针,继续执行pathNode;如果都未命中,就根据新的子节点列表中的头指针指向的key遍历旧子节点列表看是否有key一样的,如果都没对应上,就直接插入,对应上了就继续执行pathNode,移动指针。
h函数参数:(标签名,属性(类,id等),子元素)

3.2 diff算法

传统树的diff算法时间复杂度是O(n^3)
时间复杂度优化到O(n):
只比较同一层级,不跨级比较
tag不相同,则直接删掉重建,不再深度比较
tag和key , 两者都相同,则认为是相同节点,不再深度比较

4. computed 和 watch 的区别

computed:
计算结果并返回,只有当被计算的属性发生改变时才会触发(即:计算属性的结果会被缓存,除非依赖的相应属性变化才会重新计算)

watch如何深度监听? (handle , deep:true)
watch监听引用类型,拿不到oldVal
监听某一个值,当被监听的值发生变化时,执行相关操作。

(其实是两个不同功能)

场景:购物车

computed: {
    sum: function(){
        let res = 0;
        for(let i = 0; i < this.arr.length; i++){
            res += this.arr[i].num*this.arr[i].price;
        }
        return res;
    }
}
watch: {
    arr: {
        handler: functin(v, oldVal){
            let res = 0;
            for(let i = 0; i < this.arr.length; i++){
                res += this.arr[i].num*this.arr[i].price;
            }
            this.sum = res;
        }
        immediate: true,
        deep: true
    }
}
  • 方法:页面数据每次重新渲染都会重新执行。性能消耗大。
  • computed: 是计算属性,依赖其他属性计算值,并且computed的值有缓存,只有当计算值变化时才会返回内容,否则返回缓存值。页面里有个Input,输入时候并没有改数组值,触发重新渲染,但还是会重新计算。有点类似于React里的SCU,通过比较缓存值是否改变来判断子组件是否需要重新渲染。
  • watch:只能监听具体的值(或对象),监听到值的变化就会执行回调(监听的是数组),支持异步操作,可以监听computed里属性。

5. v-if v-show区别

v-show和v-if都是用来显示隐藏元素,v-if还有一个v-else配合使用,两者达到的效果都一样,但是v-if更消耗性能的,因为v-if在显示隐藏过程中有DOM的添加和删除,v-show就简单多了,只是操作css。

v-show
v-show不管条件是真还是假,第一次渲染的时候都会编译出来,也就是标签都会添加到DOM中。之后切换的时候,通过display: none;样式来显示隐藏元素。可以说只是改变css的样式,几乎不会影响什么性能。

v-if
在首次渲染的时候,如果条件为假,什么也不操作,页面当作没有这些元素。当条件为真的时候,开始局部编译,动态的向DOM元素里面添加元素。当条件从真变为假的时候,开始局部编译,卸载这些元素,也就是删除。

更新不频繁用v-if,频繁更新用v-show。

5. v-key

key的重要性。key 不能乱写(如random或者index)
vue中列表循环需加:key=“唯一标识” 唯一标识且最好是静态的,因为vue组件高度复用增加Key可以标识组件的唯一性,为了更好地区别各个组件 key的作用主要是为了高效的更新虚拟DOM

涉及到 diff 算法
https://zhuanlan.zhihu.com/p/124019708

4. 模板编译

5. 渲染过程

6. 前端路由

在这里插入图片描述
origin: 协议 域名 端口号

知道基本配置
路由间通讯:
1、路由参数,通过 $route.params. 获取
2、路由规则中 props 设置为true, 通过props获取
3、将 props 设置为对象
4、如果想要获取传递的参数值还想要获取传递的对象数据,那么props应该设置为函数形式

路由模式( hash、H5 history )

hash模式(默认) ,如http://abc.com/#/user/10
H5 history模式,如http://abc.com/user/20
后者需要server端支持,因此无特殊需求可选择前者

vue-router 中hash模式和history模式区别:
在vue的路由配置中有mode选项,最直观的区别就是在url中hash 带了一个很丑的 # ,而history是没有#的。vue默认使用hash。
mode:“hash”;
mode:“history”;
hash—— 即地址栏 URL 中的 # 符号(此 hash 不是密码学里的散列运算)。
比如这个 URL:http://www.aaa.com/#/hello,hash 的值为 #/hello。它的特点在于:hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。通过window.onhashchange 实现。

history—— 利用了 HTML5 History Interface 中新增的 history.pushState() 和 window.onpopstate()方法。(需要特定浏览器支持)这两个方法应用于浏览器的历史记录栈,在当前已有的 back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的 URL,但浏览器不会立即向后端发送请求。

因此可以说,hash 模式和 history 模式都属于浏览器自身的特性,Vue-Router 只是利用了这两个特性(通过调用浏览器提供的接口)来实现前端路由。

history模式的问题

  • 通过history api,我们丢掉了丑陋的#,但是它也有个问题:不怕前进,不怕后退,就怕刷新,f5,(如果后端没有准备的话),因为刷新是实实在在地去请求服务器的。
  • 在hash模式下,前端路由修改的是#中的信息,而浏览器请求时不会将 # 后面的数据发送到后台,所以没有问题。但是在history下,你可以自由的修改path,当刷新时,如果服务器中没有相应的响应或者资源,则会刷新出来404页面。

js 实现 hash

hash 变化会触发网页跳转,即浏览器的前进、后退。hash变化不会刷新页面,也永远不会提交到server端。
window.onhashchange

window.location.hash = newHash

popstate

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>hash test</title>
</head>
<body>
    <p>hash test</p>
    <button id="btn1">修改 hash</button>

    <script>
        // hash 变化,包括:
        // a. JS 修改 url
        // b. 手动修改 url 的 hash
        // c. 浏览器前进、后退
        window.onhashchange = (event) => {
            console.log('old url', event.oldURL)
            console.log('new url', event.newURL)

            console.log('hash:', location.hash)
        }

        // 页面初次加载,获取 hash
        document.addEventListener('DOMContentLoaded', () => {
            console.log('hash:', location.hash)
        })

        // JS 修改 url
        document.getElementById('btn1').addEventListener('click', () => {
            location.href = '#/user'
        })
    </script>
</body>
</html>

js 实现history

window.history.pushState、 window.history.replaceState 和 window.history.go

需要后端支持
history.pushState
window.onpopstate

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>history API test</title>
</head>
<body>
    <p>history API test</p>
    <button id="btn1">修改 url</button>

    <script>
        // 页面初次加载,获取 path
        document.addEventListener('DOMContentLoaded', () => {
            console.log('load', location.pathname)
        })

        // 打开一个新的路由
        // 【注意】用 pushState 方式,浏览器不会刷新页面
        document.getElementById('btn1').addEventListener('click', () => {
            const state = { name: 'page1' }
            console.log('切换路由到', 'page1')
            history.pushState(state, '', 'page1') // 重要!!
        })

        // 监听浏览器前进、后退
        window.onpopstate = (event) => { // 重要!!
            console.log('onpopstate', event.state, location.pathname)
        }

        // 需要 server 端配合,可参考
        // https://router.vuejs.org/zh/guide/essentials/history-mode.html#%E5%90%8E%E7%AB%AF%E9%85%8D%E7%BD%AE%E4%BE%8B%E5%AD%90
    </script>
</body>
</html>

代码如下(示例):

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
import  ssl
ssl._create_default_https_context = ssl._create_unverified_context

7. vue组件渲染

模板编译

1.前置知识:JS的with语法
使用with能改变{}块内自由变量的查找方式
将{}内自由变量,当做obj的属性来查找,如果找不到匹配的属性会报错

with(obj){
    log(a);
}

2.vue template complier将模板编译为render函数
html模板转成js代码
_c createElement
_v createTextVNode
3.执行render函数生成vnode

初次渲染:

  1. 解析模板为render函数的形式(一般在编译或者打包时候已完成,vue-loader),返回的是vnode。
    _c createElement
    参数:(标签名,属性(类,id等),子元素)
  2. 触发响应式,监听data属性getter setter(如果模板没有用到则不会触发)
  3. 执行render函数,生成vnode,基于vnode执行patch(elem, vnode)和diff

更新:

  1. 修改data , 触发setter (此前在getter中已被监听)
  2. 重新执行render函数,生成newVnode
  3. patch(vnode, newVnode)。期间利用diff算法更新,减少消耗
异步渲染

实现思路:
第一,同步修改 data 时,把修改操作汇总到一个队列中
第二,再异步时取得这个队列,将其中的修改数据汇总,就像 Object.assign
第三,用汇总的结果统一修改 data ,触发试图更新
可以用render函数代替template

vue性能优化

合理使用v-show 和 v-if
合理使用computed
v-for 时 加 key,以及避免和v-if同时使用
自定义事件、DOM事件及时销毁
合理使用异步组件(import())
合理使用keep-alive。(缓存组件,频繁切换,不需要重复渲染。)
data层级不要太深
使用vue-loader在开发环境做模板编译(预编译)
比如后端返回1000条数据,如果需要一次性渲染到页面上,就可以用异步渲染来做。通过一个异步操作,比如settimeout或者requestAnimationFrame把dom操作推倒异步队列,进行分批渲染,提高页面性能,减少卡顿。https://coding.imooc.com/learn/questiondetail/GDyQ0Y9JlE7XJARr.html

组件封装的思路

一段代码在项目中出现两次就开始考虑是否应该进行封装,出现三次就肯定要封装,大到一个页面,一个组件,小到一个function和一个css样式。
封装出来的组件必须具有高性能,低耦合的特性,主要从以下几点入手:

组件具有单一职责

数据从父组件传入

子组件本身不应该生成数据,如果需要生成数据,只能在组件内部进行使用,不要传递出去。
对于通过props传入的参数,不建议对其进行操作,因为会同时修改父组件里面的数据(如果修改的话,控制台中也会报错的),如果需要修改数据,可以传递给父组件,让父组件去修改(在父组件中处理事件)。

记得留一个slot

一个通用的组件,往往不能完美的适应所有的应用场景,所以在封装组件的时候,只需要完成组件的80%的功能,剩下的20%让父组件通过slot解决。

不要依赖vuex

如果要抽离组件尽量不要使用vuex来实现参数的传递,因为vuex是用来管理组件状态的,虽然可以用来传参,但是不推荐,可以选择放到localstorage中,或者通过props传递等方式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值