当前位置: 首页 > news >正文

学做早餐网站企业管理培训课程费用

学做早餐网站,企业管理培训课程费用,公司装修合同范本,永康市建设银行网站查询Vue 组件间通信有哪几种方式#xff1f; ​ Vue 组件间通信是面试常考的知识点之一#xff0c;这题有点类似于开放题#xff0c;你回答出越多方法当然越加分#xff0c;表明你对 Vue 掌握的越熟练。Vue 组件间通信只要指以下 3 类通信#xff1a;父子组件通信、隔代组件通…Vue 组件间通信有哪几种方式 ​ Vue 组件间通信是面试常考的知识点之一这题有点类似于开放题你回答出越多方法当然越加分表明你对 Vue 掌握的越熟练。Vue 组件间通信只要指以下 3 类通信父子组件通信、隔代组件通信、兄弟组件通信下面我们分别介绍每种通信方式且会说明此种方法可适用于哪类组件间通信。 1props / $emit 适用 父子组件通信 这种方法是 Vue 组件的基础相信大部分同学耳闻能详所以此处就不举例展开介绍。 2ref 与 $parent / $children 适用 父子组件通信 ref如果在普通的 DOM 元素上使用引用指向的就是 DOM 元素如果用在子组件上引用就指向组件实例$parent / $children访问父 / 子实例 3EventBus $emit / $on 适用于 父子、隔代、兄弟组件通信 这种方法通过一个空的 Vue 实例作为中央事件总线事件中心用它来触发事件和监听事件从而实现任何组件间的通信包括父子、隔代、兄弟组件。 4$attrs/$listeners 适用于 隔代组件通信 $attrs包含了父作用域中不被 prop 所识别 (且获取) 的特性绑定 ( class 和 style 除外 )。当一个组件没有声明任何 prop 时这里会包含所有父作用域的绑定 ( class 和 style 除外 )并且可以通过 v-bind$attrs 传入内部组件。通常配合 inheritAttrs 选项一起使用。$listeners包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on$listeners 传入内部组件 5provide / inject 适用于 隔代组件通信 祖先组件中通过 provider 来提供变量然后在子孙组件中通过 inject 来注入变量。 provide / inject API 主要解决了跨级组件间的通信问题不过它的使用场景主要是子组件获取上级组件的状态跨级组件间建立了一种主动提供与依赖注入的关系。 6Vuex 适用于 父子、隔代、兄弟组件通信 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。每一个 Vuex 应用的核心就是 store仓库。“store” 基本上就是一个容器它包含着你的应用中大部分的状态 ( state )。 Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候若 store 中的状态发生变化那么相应的组件也会相应地得到高效更新。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化。 Vue template 到 render 的过程 vue的模版编译过程主要如下template - ast - render函数 vue 在模版编译版本的码中会执行 compileToFunctions 将template转化为render函数 // 将模板编译为render函数const { render, staticRenderFns } compileToFunctions(template,options//省略}, this) CompileToFunctions中的主要逻辑如下∶ 1调用parse方法将template转化为ast抽象语法树 constast parse(template.trim(), options) parse的目标把tamplate转换为AST树它是一种用 JavaScript对象的形式来描述整个模板。解析过程利用正则表达式顺序解析模板当解析到开始标签、闭合标签、文本的时候都会分别执行对应的 回调函数来达到构造AST树的目的。 AST元素节点总共三种类型type为1表示普通元素、2为表达式、3为纯文本 2对静态节点做优化 optimize(ast,options) 这个过程主要分析出哪些是静态节点给其打一个标记为后续更新渲染可以直接跳过静态节点做优化 深度遍历AST查看每个子树的节点元素是否为静态节点或者静态节点根。如果为静态节点他们生成的DOM永远不会改变这对运行时模板更新起到了极大的优化作用。 3生成代码 const code generate(ast, options) generate将ast抽象语法树编译成 render字符串并将静态部分放到 staticRenderFns 中最后通过 new Function( render) 生成render函数。 动态给vue的data添加一个新的属性时会发生什么怎样解决 Vue 不允许在已经创建的实例上动态添加新的响应式属性 若想实现数据与视图同步更新可采取下面三种解决方案 Vue.set()Object.assign()$forcecUpdated() Vue.set() Vue.set( target, propertyName/index, value )参数 {Object | Array} target{string | number} propertyName/index{any} value 返回值设置的值 通过Vue.set向响应式对象中添加一个property并确保这个新 property同样是响应式的且触发视图更新 关于Vue.set源码省略了很多与本节不相关的代码 源码位置src\core\observer\index.js function set (target: Arrayany | Object, key: any, val: any): any {...defineReactive(ob.value, key, val)ob.dep.notify()return val }这里无非再次调用defineReactive方法实现新增属性的响应式 关于defineReactive方法内部还是通过Object.defineProperty实现属性拦截 大致代码如下 function defineReactive(obj, key, val) {Object.defineProperty(obj, key, {get() {console.log(get ${key}:${val});return val},set(newVal) {if (newVal ! val) {console.log(set ${key}:${newVal});val newVal}}}) }Object.assign() 直接使用Object.assign()添加到对象的新属性不会触发更新 应创建一个新的对象合并原对象和混入对象的属性 this.someObject Object.assign({},this.someObject,{newProperty1:1,newProperty2:2 ...})$forceUpdate 如果你发现你自己需要在 Vue中做一次强制更新99.9% 的情况是你在某个地方做错了事 $forceUpdate迫使Vue 实例重新渲染 PS仅仅影响实例本身和插入插槽内容的子组件而不是所有子组件。 小结 如果为对象添加少量的新属性可以直接采用Vue.set()如果需要为新对象添加大量的新属性则通过Object.assign()创建新对象如果你实在不知道怎么操作时可采取$forceUpdate()进行强制刷新 (不建议) PSvue3是用过proxy实现数据响应式的直接动态添加新属性仍可以实现数据响应式 对SSR的理解 SSR也就是服务端渲染也就是将Vue在客户端把标签渲染成HTML的工作放在服务端完成然后再把html直接返回给客户端 SSR的优势 更好的SEO首屏加载速度更快 SSR的缺点 开发条件会受到限制服务器端渲染只支持beforeCreate和created两个钩子当需要一些外部扩展库时需要特殊处理服务端渲染应用程序也需要处于Node.js的运行环境更多的服务端负载。 Vue模版编译原理知道吗能简单说一下吗 简单说Vue的编译过程就是将template转化为render函数的过程。会经历以下阶段 生成AST树优化codegen 首先解析模版生成AST语法树(一种用JavaScript对象的形式来描述整个模板)。 使用大量的正则表达式对模板进行解析遇到标签、文本的时候都会执行对应的钩子进行相关处理。 Vue的数据是响应式的但其实模板中并不是所有的数据都是响应式的。有一些数据首次渲染后就不会再变化对应的DOM也不会变化。那么优化过程就是深度遍历AST树按照相关条件对树节点进行标记。这些被标记的节点(静态节点)我们就可以跳过对它们的比对对运行时的模板起到很大的优化作用。 编译的最后一步是将优化后的AST树转换为可执行的代码。 assets和static的区别 相同点 assets 和 static 两个都是存放静态资源文件。项目中所需要的资源文件图片字体图标样式文件等都可以放在这两个文件下这是相同点 不相同点assets 中存放的静态资源文件在项目打包时也就是运行 npm run build 时会将 assets 中放置的静态资源文件进行打包上传所谓打包简单点可以理解为压缩体积代码格式化。而压缩后的静态资源文件最终也都会放置在 static 文件中跟着 index.html 一同上传至服务器。static 中放置的静态资源文件就不会要走打包压缩格式化等流程而是直接进入打包好的目录直接上传至服务器。因为避免了压缩直接进行上传在打包时会提高一定的效率但是 static 中的资源文件由于没有进行压缩等操作所以文件的体积也就相对于 assets 中打包后的文件提交较大点。在服务器中就会占据更大的空间。 建议 将项目中 template需要的样式文件js文件等都可以放置在 assets 中走打包这一流程。减少体积。而项目中引入的第三方的资源文件如iconfoont.css 等文件可以放置在 static 中因为这些引入的第三方文件已经经过处理不再需要处理直接上传。 参考 前端进阶面试题详细解答 Vue的性能优化有哪些 1编码阶段 尽量减少data中的数据data中的数据都会增加getter和setter会收集对应的watcherv-if和v-for不能连用如果需要使用v-for给每项元素绑定事件时使用事件代理SPA 页面采用keep-alive缓存组件在更多的情况下使用v-if替代v-showkey保证唯一使用路由懒加载、异步组件防抖、节流第三方模块按需导入长列表滚动到可视区域动态加载图片懒加载 2SEO优化 预渲染服务端渲染SSR 3打包优化 压缩代码Tree Shaking/Scope Hoisting使用cdn加载第三方模块多线程打包happypacksplitChunks抽离公共文件sourceMap优化 4用户体验 骨架屏PWA还可以使用缓存(客户端缓存、服务端缓存)优化、服务端开启gzip压缩等。 对keep-alive的理解它是如何实现的具体缓存的是什么 如果需要在组件切换的时候保存一些组件的状态防止多次渲染就可以使用 keep-alive 组件包裹需要保存的组件。 1keep-alive keep-alive有以下三个属性 include 字符串或正则表达式只有名称匹配的组件会被匹配exclude 字符串或正则表达式任何名称匹配的组件都不会被缓存max 数字最多可以缓存多少组件实例。 注意keep-alive 包裹动态组件时会缓存不活动的组件实例。 主要流程 判断组件 name 不在 include 或者在 exclude 中直接返回 vnode说明该组件不被缓存。获取组件实例 key 如果有获取实例的 key否则重新生成。key生成规则cid “∶∶” tag 仅靠cid是不够的因为相同的构造函数可以注册为不同的本地组件。如果缓存对象内存在则直接从缓存对象中获取组件实例给 vnode 不存在则添加到缓存对象中。 5.最大缓存数量当缓存组件数量超过 max 值时清除 keys 数组内第一个组件。 2keep-alive 的实现 const patternTypes: ArrayFunction [String, RegExp, Array] // 接收字符串正则数组export default {name: keep-alive,abstract: true, // 抽象组件是一个抽象组件它自身不会渲染一个 DOM 元素也不会出现在父组件链中。props: {include: patternTypes, // 匹配的组件缓存exclude: patternTypes, // 不去匹配的组件不缓存max: [String, Number], // 缓存组件的最大实例数量, 由于缓存的是组件实例vnode数量过多的时候会占用过多的内存可以用max指定上限},created() {// 用于初始化缓存虚拟DOM数组和vnode的keythis.cache Object.create(null)this.keys []},destroyed() {// 销毁缓存cache的组件实例for (const key in this.cache) {pruneCacheEntry(this.cache, key, this.keys)}},mounted() {// prune 削减精简[v.]// 去监控include和exclude的改变根据最新的include和exclude的内容来实时削减缓存的组件的内容this.$watch(include, (val) {pruneCache(this, (name) matches(val, name))})this.$watch(exclude, (val) {pruneCache(this, (name) !matches(val, name))})}, } render函数 会在 keep-alive 组件内部去写自己的内容所以可以去获取默认 slot 的内容然后根据这个去获取组件keep-alive 只对第一个组件有效所以获取第一个子组件。和 keep-alive 搭配使用的一般有动态组件 和router-view render () {//function getFirstComponentChild (children: ?ArrayVNode): ?VNode {if (Array.isArray(children)) {for (let i 0; i children.length; i) {const c children[i]if (isDef(c) (isDef(c.componentOptions) || isAsyncPlaceholder(c))) {return c}}}}const slot this.$slots.default // 获取默认插槽const vnode: VNode getFirstComponentChild(slot)// 获取第一个子组件const componentOptions: ?VNodeComponentOptions vnode vnode.componentOptions // 组件参数if (componentOptions) { // 是否有组件参数// check patternconst name: ?string getComponentName(componentOptions) // 获取组件名const { include, exclude } thisif (// not included(include (!name || !matches(include, name))) ||// excluded(exclude name matches(exclude, name))) {// 如果不匹配当前组件的名字和include以及exclude// 那么直接返回组件的实例return vnode}const { cache, keys } this// 获取这个组件的keyconst key: ?string vnode.key null// same constructor may get registered as different local components// so cid alone is not enough (#3269)? componentOptions.Ctor.cid (componentOptions.tag ? ::${componentOptions.tag} : ): vnode.keyif (cache[key]) {// LRU缓存策略执行vnode.componentInstance cache[key].componentInstance // 组件初次渲染的时候componentInstance为undefined// make current key freshestremove(keys, key)keys.push(key)// 根据LRU缓存策略执行将key从原来的位置移除然后将这个key值放到最后面} else {// 在缓存列表里面没有的话则加入同时判断当前加入之后是否超过了max所设定的范围如果是则去除// 使用时间间隔最长的一个cache[key] vnodekeys.push(key)// prune oldest entryif (this.max keys.length parseInt(this.max)) {pruneCacheEntry(cache, keys[0], keys, this._vnode)}}// 将组件的keepAlive属性设置为truevnode.data.keepAlive true // 作用判断是否要执行组件的created、mounted生命周期函数}return vnode || (slot slot[0]) } keep-alive 具体是通过 cache 数组缓存所有组件的 vnode 实例。当 cache 内原有组件被使用时会将该组件 key 从 keys 数组中删除然后 push 到 keys数组最后以便清除最不常用组件。 实现步骤 获取 keep-alive 下第一个子组件的实例对象通过他去获取这个组件的组件名 通过当前组件名去匹配原来 include 和 exclude判断当前组件是否需要缓存不需要缓存直接返回当前组件的实例vNode 需要缓存判断他当前是否在缓存数组里面 存在则将他原来位置上的 key 给移除同时将这个组件的 key 放到数组最后面LRU 不存在将组件 key 放入数组然后判断当前 key数组是否超过 max 所设置的范围超过那么削减未使用时间最长的一个组件的 key 最后将这个组件的 keepAlive 设置为 true 3keep-alive 本身的创建过程和 patch 过程 缓存渲染的时候会根据 vnode.componentInstance首次渲染 vnode.componentInstance 为 undefined 和 keepAlive 属性判断不会执行组件的 created、mounted 等钩子函数而是对缓存的组件执行 patch 过程∶ 直接把缓存的 DOM 对象直接插入到目标元素中完成了数据更新的情况下的渲染过程。 首次渲染 组件的首次渲染∶判断组件的 abstract 属性才往父组件里面挂载 DOM // core/instance/lifecycle function initLifecycle (vm: Component) {const options vm.$options// locate first non-abstract parentlet parent options.parentif (parent !options.abstract) { // 判断组件的abstract属性才往父组件里面挂载DOMwhile (parent.$options.abstract parent.$parent) {parent parent.$parent}parent.$children.push(vm)}vm.$parent parentvm.$root parent ? parent.$root : vmvm.$children []vm.$refs {}vm._watcher nullvm._inactive nullvm._directInactive falsevm._isMounted falsevm._isDestroyed falsevm._isBeingDestroyed false } 判断当前 keepAlive 和 componentInstance 是否存在来判断是否要执行组件 prepatch 还是执行创建 componentlnstance // core/vdom/create-component init (vnode: VNodeWithData, hydrating: boolean): ?boolean {if (vnode.componentInstance !vnode.componentInstance._isDestroyed vnode.data.keepAlive) { // componentInstance在初次是undefined!!!// kept-alive components, treat as a patchconst mountedNode: any vnode // work around flowcomponentVNodeHooks.prepatch(mountedNode, mountedNode) // prepatch函数执行的是组件更新的过程} else {const child vnode.componentInstance createComponentInstanceForVnode(vnode,activeInstance)child.$mount(hydrating ? vnode.elm : undefined, hydrating)}}, prepatch 操作就不会在执行组件的 mounted 和 created 生命周期函数而是直接将 DOM 插入 4LRU least recently used缓存策略 LRU 缓存策略∶ 从内存中找出最久未使用的数据并置换新的数据。 LRULeast rencently used算法根据数据的历史访问记录来进行淘汰数据其核心思想是 “如果数据最近被访问过那么将来被访问的几率也更高”。 最常见的实现是使用一个链表保存缓存数据详细算法实现如下∶ 新数据插入到链表头部每当缓存命中即缓存数据被访问则将数据移到链表头部链表满的时候将链表尾部的数据丢弃。 diff算法 答案 时间复杂度 个树的完全 diff 算法是一个时间复杂度为 O(n*3 vue进行优化转化成 O(n) 。 理解 最小量更新 key 很重要。这个可以是这个节点的唯一标识告诉 diff 算法在更改前后它们是同一个DOM节点 扩展 v-for 为什么要有 key 没有 key 会暴力复用举例子的话随便说一个比如移动节点或者增加节点修改DOM加 key 只会移动减少操作DOM。 只有是同一个虚拟节点才会进行精细化比较否则就是暴力删除旧的插入新的。 只进行同层比较不会进行跨层比较。 diff算法的优化策略四种命中查找四个指针 旧前与新前先比开头后插入和删除节点的这种情况 旧后与新后比结尾前插入或删除的情况 旧前与新后头与尾比此种发生了涉及移动节点那么新前指向的节点移动到旧后之后 旧后与新前尾与头比此种发生了涉及移动节点那么新前指向的节点移动到旧前之前 — 问完上面这些如果都能很清楚的话基本O了 — 以下的这些简单的概念你肯定也是没有问题的啦 Vue的优点 轻量级框架只关注视图层是一个构建数据的视图集合大小只有几十 kb 简单易学国人开发中文文档不存在语言障碍 易于理解和学习双向数据绑定保留了 angular 的特点在数据操作方面更为简单组件化保留了 react 的优点实现了 html 的封装和重用在构建单页面应用方面有着独特的优势视图数据结构分离使数据的更改更为简单不需要进行逻辑代码的修改只需要操作数据就能完成相关操作虚拟DOMdom 操作是非常耗费性能的不再使用原生的 dom 操作节点极大解放 dom 操作但具体操作的还是 dom 不过是换了另一种方式运行速度更快相比较于 react 而言同样是操作虚拟 dom就性能而言 vue 存在很大的优势。 template和jsx的有什么分别 对于 runtime 来说只需要保证组件存在 render 函数即可而有了预编译之后只需要保证构建过程中生成 render 函数就可以。在 webpack 中使用vue-loader编译.vue文件内部依赖的vue-template-compiler模块在 webpack 构建过程中将template预编译成 render 函数。与 react 类似在添加了jsx的语法糖解析器babel-plugin-transform-vue-jsx之后就可以直接手写render函数。 所以template和jsx的都是render的一种表现形式不同的是JSX相对于template而言具有更高的灵活性在复杂的组件中更具有优势而 template 虽然显得有些呆滞。但是 template 在代码结构上更符合视图与逻辑分离的习惯更简单、更直观、更好维护。 常见的事件修饰符及其作用 .stop等同于 JavaScript 中的 event.stopPropagation() 防止事件冒泡.prevent 等同于 JavaScript 中的 event.preventDefault() 防止执行预设的行为如果事件可取消则取消该事件而不停止事件的进一步传播.capture 与事件冒泡的方向相反事件捕获由外到内.self 只会触发自己范围内的事件不包含子元素.once 只会触发一次。 为什么vue组件中data必须是一个函数 对象为引用类型当复用组件时由于数据对象都指向同一个data对象当在一个组件中修改data时其他重用的组件中的data会同时被修改而使用返回对象的函数由于每次返回的都是一个新对象Object的实例引用地址不同则不会出现这个问题。 Vue.mixin的使用场景和原理 在日常的开发中我们经常会遇到在不同的组件中经常会需要用到一些相同或者相似的代码这些代码的功能相对独立可以通过 Vue 的 mixin 功能抽离公共的业务逻辑原理类似“对象的继承”当组件初始化时会调用 mergeOptions 方法进行合并采用策略模式针对不同的属性进行合并。当组件和混入对象含有同名选项时这些选项将以恰当的方式进行“合并”如果混入的数据和本身组件的数据冲突会以组件的数据为准mixin有很多缺陷如命名冲突、依赖问题、数据来源问题 基本使用 script// Vue.optionsVue.mixin({ // 如果他是对象 每个组件都用mixin里的对象进行合并data(){return {a: 1,b: 2}}});// Vue.extendVue.component(my,{ // 组件必须是函数 Vue.extend render(xxx)data(){return {x:1}}}) // 没有 new 没有实例 _init()// const vm thisnew Vue({el:#app,data(){ // 根可以不是函数 return {c:3}}}) /script相关源码 export default function initMixin(Vue){Vue.mixin function (mixin) {// 合并对象this.optionsmergeOptions(this.options,mixin)}; } };// src/util/index.js // 定义生命周期 export const LIFECYCLE_HOOKS [beforeCreate,created,beforeMount,mounted,beforeUpdate,updated,beforeDestroy,destroyed, ];// 合并策略 const strats {}; // mixin核心方法 export function mergeOptions(parent, child) {const options {};// 遍历父亲for (let k in parent) {mergeFiled(k);}// 父亲没有 儿子有for (let k in child) {if (!parent.hasOwnProperty(k)) {mergeFiled(k);}}//真正合并字段方法function mergeFiled(k) {// strats合并策略if (strats[k]) {options[k] strats[k](parent[k], child[k]);} else {// 默认策略options[k] child[k] ? child[k] : parent[k];}}return options; }Vue组件如何通信 Vue组件通信的方法如下: props/$emitv-on: 通过props将数据自上而下传递而通过$emit和v-on来向上传递信息。EventBus: 通过EventBus进行信息的发布与订阅vuex: 是全局数据管理库可以通过vuex管理全局的数据流$attrs/$listeners: Vue2.4中加入的$attrs/$listeners可以进行跨级的组件通信provide/inject以允许一个祖先组件向其所有子孙后代注入一个依赖不论组件层次有多深并在起上下游关系成立的时间里始终生效这成为了跨组件通信的基础 还有一些用solt插槽或者ref实例进行通信的使用场景过于有限就不赘述了。 用VNode来描述一个DOM结构 虚拟节点就是用一个对象来描述一个真实的DOM元素。首先将 template 真实DOM先转成 ast ast 树通过 codegen 生成 render 函数 render 函数里的 _c 方法将它转为虚拟dom 对 React 和 Vue 的理解它们的异同 相似之处 都将注意力集中保持在核心库而将其他功能如路由和全局状态管理交给相关的库都有自己的构建工具能让你得到一个根据最佳实践设置的项目模板都使用了Virtual DOM虚拟DOM提高重绘性能都有props的概念允许组件间的数据传递都鼓励组件化应用将应用分拆成一个个功能明确的模块提高复用性。 不同之处 1数据流 Vue默认支持数据双向绑定而React一直提倡单向数据流 2虚拟DOM Vue2.x开始引入Virtual DOM消除了和React在这方面的差异但是在具体的细节还是有各自的特点。 Vue宣称可以更快地计算出Virtual DOM的差异这是由于它在渲染过程中会跟踪每一个组件的依赖关系不需要重新渲染整个组件树。对于React而言每当应用的状态被改变时全部子组件都会重新渲染。当然这可以通过 PureComponent/shouldComponentUpdate这个生命周期方法来进行控制但Vue将此视为默认的优化。 3组件化 React与Vue最大的不同是模板的编写。 Vue鼓励写近似常规HTML的模板。写起来很接近标准 HTML元素只是多了一些属性。React推荐你所有的模板通用JavaScript的语法扩展——JSX书写。 具体来讲React中render函数是支持闭包特性的所以import的组件在render中可以直接调用。但是在Vue中由于模板中使用的数据都必须挂在 this 上进行一次中转所以 import 一个组件完了之后还需要在 components 中再声明下。 4监听数据变化的实现原理不同 Vue 通过 getter/setter 以及一些函数的劫持能精确知道数据变化不需要特别的优化就能达到很好的性能React 默认是通过比较引用的方式进行的如果不优化PureComponent/shouldComponentUpdate可能导致大量不必要的vDOM的重新渲染。这是因为 Vue 使用的是可变数据而React更强调数据的不可变。 5高阶组件 react可以通过高阶组件HOC来扩展而Vue需要通过mixins来扩展。 高阶组件就是高阶函数而React的组件本身就是纯粹的函数所以高阶函数对React来说易如反掌。相反Vue.js使用HTML模板创建视图组件这时模板无法有效的编译因此Vue不能采用HOC来实现。 6构建工具 两者都有自己的构建工具 React Create React APPVue vue-cli 7跨平台 React React NativeVue Weex data为什么是一个函数而不是对象 JavaScript中的对象是引用类型的数据当多个实例引用同一个对象时只要一个实例对这个对象进行操作其他实例中的数据也会发生变化。 而在Vue中更多的是想要复用组件那就需要每个组件都有自己的数据这样组件之间才不会相互干扰。 所以组件的数据不能写成对象的形式而是要写成函数的形式。数据以函数返回值的形式定义这样当每次复用组件的时候就会返回一个新的data也就是说每个组件都有自己的私有数据空间它们各自维护自己的数据不会干扰其他组件的正常运行。 vue3中 watch、watchEffect区别 watch是惰性执行也就是只有监听的值发生变化的时候才会执行但是watchEffect不同每次代码加载watchEffect都会执行忽略watch第三个参数的配置如果修改配置项也可以实现立即执行watch需要传递监听的对象watchEffect不需要watch只能监听响应式数据ref定义的属性和reactive定义的对象如果直接监听reactive定义对象中的属性是不允许的会报警告除非使用函数转换一下。其实就是官网上说的监听一个getterwatchEffect如果监听reactive定义的对象是不起作用的只能监听对象中的属性 看一下watchEffect的代码 template div请输入firstNameinput typetext v-modelfirstName /div div请输入lastNameinput typetext v-modellastName /div div请输入obj.textinput typetext v-modelobj.text /divdiv【obj.text】 {{obj.text}}/div /templatescript import {ref, reactive, watch, watchEffect} from vue export default {name: HelloWorld,props: {msg: String,},setup(props,content){let firstName ref()let lastName ref()let obj reactive({text:hello})watchEffect((){console.log(触发了watchEffect);console.log(组合后的名称为${firstName.value}${lastName.value})})return{obj,firstName,lastName}} }; /script改造一下代码 watchEffect((){console.log(触发了watchEffect);// 这里我们不使用firstName.value/lastName.value 相当于是监控整个ref,对应第四点上面的结论console.log(组合后的名称为${firstName}${lastName}) })watchEffect((){console.log(触发了watchEffect);console.log(obj); })稍微改造一下 let obj reactive({text:hello }) watchEffect((){console.log(触发了watchEffect);console.log(obj.text); })再看一下watch的代码验证一下 let obj reactive({text:hello }) // watch是惰性执行 默认初始化之后不会执行只有值有变化才会触发可通过配置参数实现默认执行 watch(obj, (newValue, oldValue) {// 回调函数console.log(触发监控更新了new, newValue);console.log(触发监控更新了old, oldValue); },{// 配置immediate参数立即执行以及深层次监听immediate: true,deep: true })监控整个reactive对象从上面的图可以看到 deep 实际默认是开启的就算我们设置为false也还是无效。而且旧值获取不到。要获取旧值则需要监控对象的属性也就是监听一个getter看下图 总结 如果定义了reactive的数据想去使用watch监听数据改变则无法正确获取旧值并且deep属性配置无效自动强制开启了深层次监听。如果使用 ref 初始化一个对象或者数组类型的数据会被自动转成reactive的实现方式生成proxy代理对象。也会变得无法正确取旧值。用任何方式生成的数据如果接收的变量是一个proxy代理对象就都会导致watch这个对象时,watch回调里无法正确获取旧值。所以当大家使用watch监听对象时如果在不需要使用旧值的情况可以正常监听对象没关系但是如果当监听改变函数里面需要用到旧值时只能监听 对象.xxx属性 的方式才行 watch和watchEffect异同总结 体验 watchEffect立即运行一个函数然后被动地追踪它的依赖当这些依赖改变时重新执行该函数 const count ref(0) ​ watchEffect(() console.log(count.value)) // - logs 0 ​ count.value // - logs 1watch侦测一个或多个响应式数据源并在数据源变化时调用一个回调函数 const state reactive({ count: 0 }) watch(() state.count,(count, prevCount) {/* ... */} )回答范例 watchEffect立即运行一个函数然后被动地追踪它的依赖当这些依赖改变时重新执行该函数。watch侦测一个或多个响应式数据源并在数据源变化时调用一个回调函数watchEffect(effect)是一种特殊watch传入的函数既是依赖收集的数据源也是回调函数。如果我们不关心响应式数据变化前后的值只是想拿这些数据做些事情那么watchEffect就是我们需要的。watch更底层可以接收多种数据源包括用于依赖收集的getter函数因此它完全可以实现watchEffect的功能同时由于可以指定getter函数依赖可以控制的更精确还能获取数据变化前后的值因此如果需要这些时我们会使用watchwatchEffect在使用时传入的函数会立刻执行一次。watch默认情况下并不会执行回调函数除非我们手动设置immediate选项从实现上来说watchEffect(fn)相当于watch(fn,fn,{immediate:true}) watchEffect定义如下 export function watchEffect(effect: WatchEffect,options?: WatchOptionsBase ): WatchStopHandle {return doWatch(effect, null, options) }watch定义如下 export function watchT any, Immediate extends Readonlyboolean false(source: T | WatchSourceT,cb: any,options?: WatchOptionsImmediate ): WatchStopHandle {return doWatch(source as any, cb, options) }很明显watchEffect就是一种特殊的watch实现。 Vue实例挂载的过程中发生了什么 简单 TIP 分析 挂载过程完成了最重要的两件事 初始化建立更新机制 把这两件事说清楚即可 回答范例 挂载过程指的是app.mount()过程这个过程中整体上做了两件事初始化和建立更新机制初始化会创建组件实例、初始化组件状态创建各种响应式数据建立更新机制这一步会立即执行一次组件更新函数这会首次执行组件渲染函数并执行patch将前面获得vnode转换为dom同时首次执行渲染函数会创建它内部响应式数据之间和组件更新函数之间的依赖关系这使得以后数据变化时会执行对应的更新函数 来看一下源码在src/core/instance/index.js 中 function Vue (options) {if (process.env.NODE_ENV ! production !(this instanceof Vue)) {warn(Vue is a constructor and should be called with the new keyword)}this._init(options) }可以看到 Vue 只能通过 new 关键字初始化然后会调用 this._init 方法 该方法在 src/core/instance/init.js 中定义 Vue.prototype._init function (options?: Object) {const vm: Component this// a uidvm._uid uidlet startTag, endTag/* istanbul ignore if */if (process.env.NODE_ENV ! production config.performance mark) {startTag vue-perf-start:${vm._uid}endTag vue-perf-end:${vm._uid}mark(startTag)}// a flag to avoid this being observedvm._isVue true// merge optionsif (options options._isComponent) {// optimize internal component instantiation// since dynamic options merging is pretty slow, and none of the// internal component options needs special treatment.initInternalComponent(vm, options)} else {vm.$options mergeOptions(resolveConstructorOptions(vm.constructor),options || {},vm)}/* istanbul ignore else */if (process.env.NODE_ENV ! production) {initProxy(vm)} else {vm._renderProxy vm}// expose real selfvm._self vminitLifecycle(vm)initEvents(vm)initRender(vm)callHook(vm, beforeCreate)initInjections(vm) // resolve injections before data/propsinitState(vm)initProvide(vm) // resolve provide after data/propscallHook(vm, created)/* istanbul ignore if */if (process.env.NODE_ENV ! production config.performance mark) {vm._name formatComponentName(vm, false)mark(endTag)measure(vue ${vm._name} init, startTag, endTag)}if (vm.$options.el) {vm.$mount(vm.$options.el)} }Vue 初始化主要就干了几件事情合并配置初始化生命周期初始化事件中心初始化渲染初始化 data、props、computed、watcher 等
http://www.w-s-a.com/news/883663/

相关文章:

  • 外贸网站外包WordPress仿牌
  • 如何设计网站logohtml5开发
  • 金坛建设银行总行网站网站开发费用如何记账
  • 贵阳企业网站设计制作湛江知名网站建设电话
  • 网站建设安全性高清效果图网站
  • 上海网站排名推广黄山公司做网站
  • 全国网站建设公司实力排名单页面网站建设
  • 网站建设方案 规划wordpress 要备案吗
  • 一个完整的网站 技术网站建设中 敬请期待.
  • 如何建一个公司的网站网上怎么推广公司产品
  • 十大旅游电子商务网站影楼网站制作
  • 深圳网站建设代理商网业打开慢的原因
  • 旅游网站经营模式在屈臣氏做网站运营
  • 做管理信息的网站com域名查询
  • 免费推广网站推荐外贸推广平台哪个好
  • 腾宁科技做网站399元全包企业校园网站建设
  • 海外医疗兼职网站建设公司取名字大全免费
  • 龙口市规划建设局网站vi设计和品牌设计的区别
  • 企业网站的总体设计网站建设评审验收会议主持词
  • 网站建设完成推广响应式网站设计开发
  • 电商网站用php做的吗网站开发流程可规划为那三个阶段
  • flash网站怎么做音乐停止深圳网站建设金瓷网络
  • 哪个网站可以做房产信息群发怎么做国内网站吗
  • 微商城网站建设公司的价格卖磁铁的网站怎么做的
  • 免费做做网站手机平台软件开发
  • 网站单页做301徐州百度网站快速优化
  • 织梦怎么制作手机网站漳州专业网站建设公司
  • 邓州做网站网络优化概念
  • 查看网站开发phonegap wordpress
  • 网站建设和维护待遇怎样c 做的网站又哪些