Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >vue组件对象字面量传值的注意啦!

vue组件对象字面量传值的注意啦!

作者头像
奋飛
发布于 2021-08-30 02:14:29
发布于 2021-08-30 02:14:29
1.4K00
代码可运行
举报
文章被收录于专栏:Super 前端Super 前端
运行总次数:0
代码可运行

前面汇总过 「vue组件引用传值的最佳实践」,对于 vue2 版本存在一个严重的性能问题,需要格外注意:对象字面量的传递

vue-props-传入一个对象 <blog-post v-bind:author="{ name: 'Veronica', company: 'Veridian Dynamics' }" >blog-post> <blog-post v-bind:author="post.author">blog-post>

问题描述

前提:

  • 字面量形式传参
  • 触发虚拟DOM重绘或patch(模板使用的响应数据修改;向模板中动态调整响应数据set/ delete)

官方允许对象字面量的方式进行属性传递,如上述。会产生这样一个问题:组件外部响应式变量(组件内并没有使用)发生变化,也会引起组件的 updated(vue 生命周期一环),如果我们在组件内部 watch/computed 了相关传递的属性值(如上述的 author,虽然 author 使用的值没有发生变化),也会导致 watch/computed 逻辑被执行

示例:

演示地址:https://8x6mx.csb.app/

代码地址:https://codesandbox.io/s/code-8x6mx?file=/src/components/HelloWorld2.js:0-108

每次 test 变量修改,都会引起 HelloWorld 组件的 updated,从而导致 watch 的执行。

App.vue

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<template>
  <div id="app">
    <hello-world :person="{name: 'ligang'}"></hello-world>
    <hello-world2 :person="p"></hello-world2>
    <input type="text" v-model="test" placeholder="请输入">
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld.vue"
import HelloWorld2 from "./components/HelloWorld2.js"

export default {
  name: "App",
  components: {
    HelloWorld,
    HelloWorld2
  },
  data() {
    return {
      p: { name: "ligang" },
      test: ""
    }
  }
}
</script>

HelloWorld.vue

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<template>
  <div>
    <div>{{$options._componentTag}}div>
    <div>Hello {{person.name}}div>
    <div>Updated次数:{{count}}div>
  div>
template>
<script>
export default {
  name: "HelloWorld",
  props: {
    person: Object
  },
  data() {
    return {
      count: 0
    };
  },
  watch: {
    person: {
      handler(val, oldVal) {
        this.count++;
      },
      immediate: true
    }
  },
  updated() {
    console.log("HelloWorld updated")
  }
}
script>

HelloWorld2.js

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import HelloWorld from "./HelloWorld.vue"
export default {
  name: "HelloWorld2",
  extends: HelloWorld
}

原因分析

模板 ==> AST ==> render函数 ==> vnode对象(virtual dom) ==> 真实Dom

模板解析为 AST,预编译为渲染函数。通过 vue-template-compiler,可以查看生成 render 函数的不同。

模板中使用了响应式数据 test,修改该数据,vue 追踪到变化,修改 vnode,通过对比算法确定需要更新的节点,进行 patch 操作,渲染视图。

每次执行 render,虽然 person 对象属性未发生变化,但 hello-world 组件中其为字面量,所以导致每次的引用值不同,因此触发组件内的 watch;hello-world2 为同一引用,因此不会触发组件内的 watch。

render 函数

vue-template-compiler:该模块可用于将 Vue 2.0 模板预编译为渲染函数(template => ast => render),以避免运行时编译开销和 CSP 限制。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import {compile} from 'vue-template-compiler'
compile(``)
compile(``)
虚拟DOM
  • Vue1.0,当状态发生变化时,在一定程度上知道哪些节点使用了这个状态,从而对这些节点进行更新操作,无需对比。但这种细粒度的处理方式,每一个绑定都会有一个对应的 watcher 来观察状态的变化,这样就会有一些内存开销以及一些追踪依赖的开销,当状态值被越多的节点使用时,开销就越大。对于一个中大型项目,这个开销是巨大的。
  • vue2.0,选择了一种”中粒度“解决方案,引入虚拟DOM,组件级别 watcher,一个组件内有 10 个节点使用了某一状态值,其也只会有一个 watcher 在观察这个状态的变化。组件得到变化通知后,通过虚拟 DOM 进行对比,最后渲染。
  • vue3.0,该问题不复存在。现阶段可以通过 vite 尝试。
响应属性

vue 内置响应式的属性:props、data、computed、watch。

  • 由于 javascript 并没有提供元编程的能力,无法侦测 object 什么时间添加或减少属性。所以 vue 新增了 vm.set 和 vm. delete ,通过此来转换成响应式的
  • 关于数组,是通过拦截原型方法 if (Array.isArray(value)) { value.__proto__ = arrayMethods },来实现的。其中包括 push、pop、shift、unshift、splice、sort、reverse

关于视图更新的其他说明

方式

结论

【horrible】重新加载整个页面

无语…

【terrible】使用 v-if

频繁重排,组件生命周期都会触发一遍

【better】使用Vue的内置forceUpdate方法

官方 Api,即使响应数据没有更新,也会重新渲染

【best】改变组件的 key 属性

  1. v-if 示例 key 值也可以使用时间戳(每次变更时间戳)
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 <my-component v-if="renderComponent" />
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
export default {
  data() {
    return {
      renderComponent: true,
    };
  },
  methods: {
    forceRerender() {
      // 移除 my-component DOM
      this.renderComponent = false

      this.$nextTick(() => {
        // 追加 DOM
        this.renderComponent = true
      });
    }
  }
}
  1. forceUpdate()
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 全局
import Vue from 'vue';
Vue.forceUpdate();

// Using the component instance
export default {
  methods: {
    methodThatForcesUpdate() {
      // 组件
      this.$forceUpdate()
      // ...
    }
  }
}

注意$forceUpdate 只会重新渲染视图,不会重新计算属性 – forceUpdate does not update computed fields

  1. key

错误示例: 在过滤或者删除某一person时,列表会被重新渲染(key值发生了变化)。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<li v-for="(person, index) in people" :key="index">
  {{ person.name }} - {{ index }}
li>

正确示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<li v-for="(person, index) in people" :key="person.id">
  {{ person.name }} - {{ index }}
li>

参考地址

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/05/19 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
『 Vue 小 Case 』- 别被字面量 Prop 坑了
用过 Vue 的各位,对于 Prop 一定不会陌生,相信大家都能够信手拈来。但就是这么一个大家都熟悉的 Prop,有时候也会把我们坑了。在介绍这个坑之前,我们先再来温习一下 Prop 的基础用法。
歪马
2020/04/07
1.1K0
『 Vue 小 Case 』- 别被字面量 Prop 坑了
一个合格的中级前端工程师应该掌握的 20 个 Vue 技巧
之前写过一篇文章,关于 Vue 属性透传的,文章中我列举了很多种方法去实现属性透传。其中包括直接设置 props,v-bind="$attrs",render function 等方式。感兴趣,详情看 【Vue 进阶】——如何实现组件属性透传?
GopalFeng
2020/09/24
6.2K0
一个合格的中级前端工程师应该掌握的 20 个 Vue 技巧
Vue 中 强制组件重新渲染的正确方法
有时候,依赖 Vue 响应方式来更新数据是不够的,相反,我们需要手动重新渲染组件来更新数据。或者,我们可能只想抛开当前的DOM,重新开始。那么,如何让Vue以正确的方式重新呈现组件呢?
前端小智@大迁世界
2022/06/15
8.3K1
Vue 中 强制组件重新渲染的正确方法
vue3笔记1 组件配置API
vue2中的数据,计算属性,方法,生命周期钩子等都可以在setup函数中构造 setup函数返回:
路过君
2022/04/13
4120
2022前端经典vue面试题(持续更新中)
一个SPA应用的路由需要解决的问题是 页面跳转内容改变同时不刷新 ,同时路由还需要以插件形式存在,所以:
bb_xiaxia1998
2022/09/16
1K0
学会这几个API,vue3直接上手
vue2开发过项目的,想直接上手vue3很快,几个API熟悉了就够了,其它的特性在使用vue3的过程慢慢去了解。任何在熟悉了使用之后再去研究一些API的原理,慢慢就能把vue3掌握。
wade
2022/03/28
7140
vue课程大全
var app=new Vue({el:"#app",data:{msg:"hello vue!"}})
李才哥
2021/02/20
1.7K0
vue课程大全
【Vue原理解析】之异步与优化
Vue是一款流行的JavaScript框架,它提供了一些强大的特性来提升应用程序的性能和用户体验。在本文中,我们将深入探讨Vue的异步更新机制和一些优化技巧,帮助您更好地理解和应用这些特性。
can4hou6joeng4
2023/11/15
2840
4. 「vue@2.6.11 源码分析」new Vue() 整体流程和组件渲染之前的准备工作
将组件渲染渲染分为两大步骤:组件信息(事件、方法等等)的初始化,以及组件的渲染。 虽然源码中 $mount方法调用放在了_init方法上,但是感觉拿出来好些,毕竟是两个大的步骤。
tinyant
2023/02/24
7240
4.  「vue@2.6.11 源码分析」new Vue() 整体流程和组件渲染之前的准备工作
超全的Vue3文档【Vue2迁移Vue3】
链接:https://juejin.cn/post/6858558735695937544#heading-153
小丑同学
2021/03/25
2.9K0
为什么说 Vue 的响应式更新精确到组件级别?(原理深度解析)
我们都知道 Vue 对于响应式属性的更新,只会精确更新依赖收集的当前组件,而不会递归的去更新子组件,这也是它性能强大的原因之一。
ssh_晨曦时梦见兮
2024/01/26
3710
腾讯前端一面常考vue面试题汇总2
vue构建函数调用_init方法,但我们发现本文件中并没有此方法,但仔细可以看到文件下方定定义了很多初始化方法
bb_xiaxia1998
2023/01/04
6890
前端vue面试题
通过webpack的tree-shaking功能,可以将无用模块“剪辑”,仅打包需要的
bb_xiaxia1998
2022/11/15
2.2K0
京东前端高频vue面试题
通俗点理解就是,vuex 弱化 dispatch,通过commit进行 store状态的一次更变;取消了action概念,不必传入特定的 action形式进行指定变更;弱化reducer,基于commit参数直接对数据进行转变,使得框架更加简易;
bb_xiaxia1998
2022/12/19
1.3K0
【Vue】(3)生命周期钩子函数 | 组件定义的方式 | 组件切换方式 | 父子组件之间传值 | watch/methods/computed
beforeDestory:实例销毁之前调用。在这一步,实例(包括:过滤器、指令、Data、methods等)仍然完全可用。
前端修罗场
2023/10/07
4840
【Vue 源码解析】Vue实例挂载过程
源码位置:node_modules/vue/src/core/instance/index.js(ps:找不到可以在node_modules目录下搜索,因为懒惰后边就不写node_modules/vue这两级目录了)
CODER-V
2023/03/19
8480
【Vue 源码解析】Vue实例挂载过程
Vue的Key属性,v-for和v-if,v-if/v-show,v-pre不渲染,v-once只渲染一次
key的特殊属性主要用在vue的虚拟dom算法,如果不适用key,vue会使用一种最大限度减少动态元素并且尽可能的尝试修复/再利用相同类型元素的算法。使用Key,它会基于Key的变化重新排列元素顺序,并且会移除Key不存在的元素。
达达前端
2019/11/05
2.9K0
Vue的Key属性,v-for和v-if,v-if/v-show,v-pre不渲染,v-once只渲染一次
Vue学习笔记---暂保存
当我们创建这样一个Vue实例后,它就挂在到了一个id为app的dom对象上,我们就不再需要和HTML直接交互了,我们仅仅需要利用Vue实例操作即可
名字是乱打的
2021/12/23
3.1K0
Vue学习笔记---暂保存
vue之vue组件component整理
组件是可复用的 Vue 实例,且带有一个名字:在这个例子中是。我们可以在一个通过 new Vue 创建的 Vue 根实例中,把这个组件作为自定义元素来使用:
山行AI
2019/07/30
6.9K0
vue之vue组件component整理
最全系列的vue3入门教程『图文并茂』
Vue 3 是一个流行的开源JavaScript框架,用于构建用户界面和单页面应用。它带来了许多新特性和改进,包括更好的性能、更小的打包大小、更好的TypeScript支持、全新的组合式 API,以及一些新的内置组件。
linwu
2023/07/27
5.3K0
最全系列的vue3入门教程『图文并茂』
推荐阅读
相关推荐
『 Vue 小 Case 』- 别被字面量 Prop 坑了
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验