关于vue.js:Vue-3-技术揭秘

随着 Vue 3 正式版本的公布,将来 Vue 3 将会成为前端的支流框架,这个毋庸置疑。Vue 3 在应用方面会兼容局部 Vue 2.x 的个性,比方 options API。所以,到底是要先学习 Vue 2 打好根底,还是间接学习 Vue 3 呢?当 Vue 作者尤大面对这样的发问时,间接给出了十分动摇的答复:间接学 Vue 3 就行了,根底概念是截然不同的。不过,在学习应用 Vue 3 的过程中,很多小伙伴会遇到一些痛点问题,比方: Vue 3 渲染器做了哪些事件?Vue 3 的响应式和 Vue 2 相比有什么不同?Vue 3 编译器的过程是什么样的?Vue 3 传说中的编译时优化,到底做了哪些工作?Vue 3 一些内置内容到底是如何运作的?……只有解答了上述这些问题,能力更好地应用高性能的 Vue.js,也能够帮忙你在做我的项目的时候,在理解 Vue 运行机制的前提下,写出性能更优的代码。另外,很值得一提的是,在浏览 Vue 3 源码的时候,你会发现大量优良的设计模式和算法,让人赞不绝口。 然而,间接去啃 Vue 3 源码会十分艰涩难懂,比方一个 baseCreateRenderer 函数就有靠近 2000 行代码,可能会让你大功告成(妥妥地 “从入门到放弃”),这个预计很多小伙伴们都深有体会。所以,《Vue 3 技术揭秘》一方面会对 Vue 3 外围源码做适量的精简,让你能够只用关注外围逻辑实现;另一方面,也配了大量的插图,一图胜千言,能够更加活泼地向你展现源码的运行机制。《Vue 3 技术揭秘》次要划分为了 5 大模块 来顺次为你揭开 Vue 3 的 “神秘面纱”。 ...

December 23, 2022 · 1 min · jiezi

关于vue.js:校招前端二面高频vue面试题边面边更

Vue中封装的数组办法有哪些,其如何实现页面更新在Vue中,对响应式解决利用的是Object.defineProperty对数据进行拦挡,而这个办法并不能监听到数组外部变动,数组长度变动,数组的截取变动等,所以须要对这些操作进行hack,让Vue能监听到其中的变动。 那Vue是如何实现让这些数组办法实现元素的实时更新的呢,上面是Vue中对这些办法的封装: // 缓存数组原型const arrayProto = Array.prototype;// 实现 arrayMethods.__proto__ === Array.prototypeexport const arrayMethods = Object.create(arrayProto);// 须要进行性能拓展的办法const methodsToPatch = [ "push", "pop", "shift", "unshift", "splice", "sort", "reverse"];/** * Intercept mutating methods and emit events */methodsToPatch.forEach(function(method) { // 缓存原生数组办法 const original = arrayProto[method]; def(arrayMethods, method, function mutator(...args) { // 执行并缓存原生数组性能 const result = original.apply(this, args); // 响应式解决 const ob = this.__ob__; let inserted; switch (method) { // push、unshift会新增索引,所以要手动observer case "push": case "unshift": inserted = args; break; // splice办法,如果传入了第三个参数,也会有索引退出,也要手动observer。 case "splice": inserted = args.slice(2); break; } // if (inserted) ob.observeArray(inserted);// 获取插入的值,并设置响应式监听 // notify change ob.dep.notify();// 告诉依赖更新 // 返回原生数组办法的执行后果 return result; });});简略来说就是,重写了数组中的那些原生办法,首先获取到这个数组的__ob__,也就是它的Observer对象,如果有新的值,就调用observeArray持续对新的值察看变动(也就是通过target__proto__ == arrayMethods来扭转了数组实例的型),而后手动调用notify,告诉渲染watcher,执行update。 ...

December 20, 2022 · 11 min · jiezi

关于vue.js:Vue的computed和watch的区别是什么

一、computed介绍computed 用来监控本人定义的变量,该变量在 data 内没有申明,间接在 computed 外面定义,页面上可间接应用。 //根底应用{{msg}}<input v-model="name" /> //计算属性 computed:{ msg:function(){ return this.name }}在输入框中,扭转 name 值得时候,msg 也会跟着扭转。这是因为 computed 监听本人的属性 msg,发现 name 一旦变动,msg 立马会更新。 留神:msg 不可在 data 中定义,否则会报错。 1.1、get 和 set 用法 <input v-model="full" ><br><input v-model="first" > <br><input v-model="second" > data(){ return{ first:'美女', second:'姐姐' }},computed:{ full:{ get(){ //回调函数 当须要读取以后属性值是执行,依据相干数据计算并返回以后属性的值 return this.first + ' ' + this.second }, set(val){ //监督以后属性值的变动,当属性值发生变化时执行,更新相干的属性数据 let names = val.split(' ') this.first = names[0] this.second = names[1] } }}get 办法:first 和 second 扭转时,会调用 get 办法,更新 full 的值。 ...

December 20, 2022 · 2 min · jiezi

关于vue.js:前端一面必会vue面试题边面边更

为什么要应用异步组件节俭打包出的后果,异步组件离开打包,采纳jsonp的形式进行加载,无效解决文件过大的问题。外围就是包组件定义变成一个函数,依赖import() 语法,能够实现文件的宰割加载。components:{ AddCustomerSchedule:(resolve)=>import("../components/AddCustomer") // require([]) }原理 export function ( Ctor: Class<Component> | Function | Object | void, data: ?VNodeData, context: Component, children: ?Array<VNode>, tag?: string ): VNode | Array<VNode> | void { // async component let asyncFactory if (isUndef(Ctor.cid)) { asyncFactory = Ctor Ctor = resolveAsyncComponent(asyncFactory, baseCtor) // 默认调用此函数时返回 undefiend // 第二次渲染时Ctor不为undefined if (Ctor === undefined) { return createAsyncPlaceholder( // 渲染占位符 空虚构节点 asyncFactory, data, context, children, tag ) } } }function resolveAsyncComponent ( factory: Function, baseCtor: Class<Component> ): Class<Component> | void { if (isDef(factory.resolved)) { // 3.在次渲染时能够拿到获取的最新组件 return factory.resolved } const resolve = once((res: Object | Class<Component>) => { factory.resolved = ensureCtor(res, baseCtor) if (!sync) { forceRender(true) //2. 强制更新视图从新渲染 } else { owners.length = 0 } }) const reject = once(reason => { if (isDef(factory.errorComp)) { factory.error = true forceRender(true) } }) const res = factory(resolve, reject)// 1.将resolve办法和reject办法传入,用户调用 resolve办法后 sync = false return factory.resolved }谈谈你对MVVM的了解为什么要有这些模式,目标:职责划分、分层(将Model层、View层进行分类)借鉴后端思维,对于前端而已,就是如何将数据同步到页面上 ...

December 19, 2022 · 9 min · jiezi

关于vue.js:面试官vue2和vue3的区别有哪些

一、Vue3 与 Vue2 区别详述1. 生命周期对于生命周期来说,整体上变动不大,只是大部分生命周期钩子名称上 + “on”,性能上是相似的。不过有一点须要留神,Vue3 在组合式API(Composition API,上面开展)中应用生命周期钩子时须要先引入,而 Vue2 在选项API(Options API)中能够间接调用生命周期钩子,如下所示。 // vue3<script setup> import { onMounted } from 'vue'; // 应用前需引入生命周期钩子onMounted(() => { // ...});// 可将不同的逻辑拆开成多个onMounted,仍然按程序执行,不会被笼罩onMounted(() => { // ...});</script>// vue2<script> export default { mounted() { // 间接调用生命周期钩子 // ... }, }</script> 罕用生命周期比照如下表所示。 vue2vue3beforeCreate created beforeMountonBeforeMountmountedonMountedbeforeUpdateonBeforeUpdateupdatedonUpdatedbeforeDestroyonBeforeUnmountdestroyedonUnmountedTips: setup 是围绕 beforeCreate 和 created 生命周期钩子运行的,所以不须要显式地去定义。2. 多根节点相熟 Vue2 的敌人应该分明,在模板中如果应用多个根节点时会报错,如下所示。 // vue2中在template里存在多个根节点会报错<template> <header></header> <main></main> <footer></footer></template>// 只能存在一个根节点,须要用一个<div>来包裹着<template> <div> <header></header> <main></main> <footer></footer> </div></template>然而,Vue3 反对多个根节点,也就是 fragment。即以下多根节点的写法是被容许的。 ...

December 19, 2022 · 6 min · jiezi

关于vue.js:必会vue面试题附答案

vue初始化页面闪动问题应用vue开发时,在vue初始化之前,因为div是不归vue管的,所以咱们写的代码在还没有解析的状况下会容易呈现花屏景象,看到相似于{{message}}的字样,尽管个别状况下这个工夫很短暂,然而还是有必要让解决这个问题的。 首先:在css里加上以下代码: [v-cloak] { display: none;}如果没有彻底解决问题,则在根元素加上style="display: none;" :style="{display: 'block'}" v-show 与 v-if 有什么区别?v-if 是真正的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建;也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。 v-show 就简略得多——不论初始条件是什么,元素总是会被渲染,并且只是简略地基于 CSS 的 “display” 属性进行切换。 所以,v-if 实用于在运行时很少扭转条件,不须要频繁切换条件的场景;v-show 则实用于须要十分频繁切换条件的场景。 你有对 Vue 我的项目进行哪些优化?(1)代码层面的优化 v-if 和 v-show 辨别应用场景computed 和 watch 辨别应用场景v-for 遍历必须为 item 增加 key,且防止同时应用 v-if长列表性能优化事件的销毁图片资源懒加载路由懒加载第三方插件的按需引入优化有限列表性能服务端渲染 SSR or 预渲染(2)Webpack 层面的优化 Webpack 对图片进行压缩缩小 ES6 转为 ES5 的冗余代码提取公共代码模板预编译提取组件的 CSS优化 SourceMap构建后果输入剖析Vue 我的项目的编译优化(3)根底的 Web 技术的优化 开启 gzip 压缩浏览器缓存CDN 的应用应用 Chrome Performance 查找性能瓶颈为什么Vue采纳异步渲染呢?Vue 是组件级更新,如果不采纳异步更新,那么每次更新数据都会对以后组件进行从新渲染,所以为了性能, Vue 会在本轮数据更新后,在异步更新视图。核心思想 nextTick 。 dep.notify() 告诉 watcher进行更新, subs[i].update 顺次调用 watcher 的 update , queueWatcher 将watcher 去重放入队列, nextTick( flushSchedulerQueue )在下一tick中刷新watcher队列(异步)。 ...

December 19, 2022 · 4 min · jiezi

关于vue.js:VuenextTick的原理是什么vue面试进阶

原理性的货色就会文字较多,请耐下心来,细细品味 Vue中DOM更新机制当你威风凛凛地应用Vue大展宏图的时候,忽然发现,咦,我明明对这个数据进行更改了,然而当我获取它的时候怎么是上一次的值(自己比拟懒,就不具体举例了) 此时,Vue就会说:“小样,这你就不懂了吧,我的DOM是异步更新的呀!!!” 简略的说,Vue的响应式并不是只数据发生变化之后,DOM就立即发生变化,而是依照肯定的策略进行DOM的更新。这样的益处是能够防止一些对DOM不必要的操作,进步渲染性能。 在Vue官网文档中是这样阐明的: 可能你还没有留神到,Vue异步执行DOM更新。只有察看到数据变动,Vue将开启一个队列,并缓冲在同一事件循环中产生的所有数据扭转。如果同一个watcher被屡次触发,只会被推入到队列中一次。这种在缓冲时去除反复数据对于防止不必要的计算和DOM操作上十分重要。而后,在下一个的事件循环“tick”中,Vue刷新队列并执行理论 (已去重的) 工作。文言一点就是说,其实这是和JS当中的事件循环是非亲非故的,就是Vue不可能对每一个数据变动都做一次渲染,它会把这些变动先放在一个异步的队列当中,同时它还会对这个队列外面的操作进行去重,比方你批改了这个数据三次,它只会保留最初一次。这些变动是都能够通过队列的模式保存起来,那当初的问题就来到了,那vue是在事件循环的哪个机会来对DOM进行批改呢? Vue有两种抉择,一个是在本次事件循环的最初进行一次DOM更新,另一种是把DOM更新放在下一轮的事件循环当中。z这时,尤雨溪拍了拍胸脯说:“这两种办法,我都有!” 然而因为本轮事件循环最初执行会比放在下一轮事件循环要快很多,所以Vue优先选择第一种,只有当环境不反对的时候才触发第二种机制。(结尾的链接让你懂事件循环) 尽管性能上进步了很多,但这个时候问题就呈现了,咱们都晓得在一轮事件循环中,同步执行栈中代码执行实现之后,才会执行异步队列当中的内容,那咱们获取DOM的操作是一个同步的呀!!那岂不是尽管我曾经把数据改掉了,然而它的更新异步的,而我在获取的时候,它还没有来得及改,所以会呈现文章结尾的那个问题。 这。。。我的确须要进行这样操作,那这么办呢?? 没关系啦,尤大很贴心的为咱们提供了Vue.$nextTick() Vue.$nextTick()其实一句话就能够把$nextTick这个货色讲明确:就是你放在$nextTick 当中的操作不会立刻执行,而是等数据更新、DOM更新实现之后再执行,这样咱们拿到的必定就是最新的了。 再精确一点来讲就是$nextTick办法将回调提早到下次DOM更新循环之后执行。(看不懂这句人话的,能够看下面[狗头]) 意思咱们都懂了,那$nextTick是怎么实现这个神奇的性能的呢? 外围如下: Vue在外部对异步队列尝试应用原生的Promise.then、MutationObserver和setImmediate,如果执行环境不反对,则会采纳 setTimeout(fn, 0)代替。认真地看这句话,你就能够发现这不就是利用 JavaScript 的这些异步回调工作队列,来实现 Vue 框架中本人的异步回调队列。这其实就是一个典型的将底层 JavaScript 执行原理利用到具体案例中的示例。 我在这里略微总结一下:就是$nextTick将回调函数放到微工作或者宏工作当中以提早它地执行程序;(总结的也比拟懒) 重要的是了解源码中它的三个参数的意思: callback:咱们要执行的操作,能够放在这个函数当中,咱们没执行一次$nextTick就会把回调函数放到一个异步队列当中;pending:标识,用以判断在某个事件循环中是否为第一次退出,第一次退出的时候才触发异步执行的队列挂载timerFunc:用来触发执行回调函数,也就是Promise.then或MutationObserver或setImmediate 或setTimeout的过程了解之后,在看整个$nextTick外面的执行过程,其实就是把一个个$nextTick中的回调函数压入到callback队列当中,而后依据事件的性质期待执行,轮到它执行的时候,就执行一下,而后去掉callback队列中相应的事件。 应用说了这么多,怎么用它呢? 很简略很简略 mounted: function () { this.$nextTick(function () { // Code that will run only after the // entire view has been rendered })}应用场景created中获取DOM的操作须要应用它就是咱们下面的例子,你如果想要获取最新值,就用它还有一些第三方插件应用过程中,应用到的状况,具体问题具体分析参考 前端进阶面试题具体解答 补充之前我始终搞不懂一个的问题,$nextTick既然把它传入的办法变成微工作了,那它和其它微工作的执行程序是怎么的呢? 这简略来说就是谁先挂载Promise对象的问题,在调用$nextTick办法时就会将其闭包外部保护的执行队列挂载到Promise对象,在数据更新时Vue外部首先就会执行$nextTick办法,之后便将执行队列挂载到了Promise对象上,其实在明确Js的Event Loop模型后,将数据更新也看做一个$nextTick办法的调用,并且明确$nextTick办法会一次性执行所有推入的回调,就能够明确执行程序的问题了 还有$nextTick和nextTick区别就是nextTick多了一个context参数,用来指定上下文。但两个的实质是一样的,$nextTick是实例办法,nextTick是类的静态方法而已;实例办法的一个益处就是,主动给你绑定为调用实例的this罢了。

December 19, 2022 · 1 min · jiezi

关于vue.js:说说Vue响应式系统中的Watcher和Dep的关系面试进阶

引言在这里我先提出两个问题(文章开端会进行解答): 在Vue的数据响应零碎中,Dep和Watcher各自分担什么工作?Vue的数据响应零碎的外围是Object.defineproperty肯定是最好的吗?有什么弊病和破绽吗?一、什么是响应零碎中的Watcher,它的作用是什么?响应零碎中的Watcher即这个零碎的观察者,它是响应零碎中观察者模式的载体,当响应零碎中的数据产生扭转的时候,它可能晓得并且执行相应的函数以达到某种业务逻辑的目标。打个比方,如果你是一个商家,要寄一批货别离给不同的客户,那么watcher就是一个个快递员,收回的动作就是数据产生扭转。你只须要负责寄出去这个动作就行了,如何找到、送到客户则是watcher的事件。 每个watcher和数据之间的关系要么是1对1,要么是多对多关系(这与watcher的类型无关),要不是没有分割。watcher和业务逻辑只有1对1关系。 二、Watcher的类型在Vue源码中是没有体现出Watcher的类型的,我在这里给Watcher增加类型是为了更好地了解Watcher这个对象。Watcher在一般的业务逻辑上能够分为以下三类: 一般的Watcher:与数据1对1关系。lazy型Watcher:与数据1对1关系,然而它是一个惰性求值的观察者,怎么体现呢?对它进行赋值是不会扭转它的值,只有当获取它的值的时候,才会更新最新版的数据(在Vue中体现为computed办法,个别求值是通过办法来求值的)。render型Watcher:与数据是1对多(不思考传参进子组件)的关系,在一个组件中,渲染函数观察者肯定是最初生成的,所以执行观察者队列的时候,渲染函数观察者在一个组件中是最初执行的。在这里多嘴一下lazy型的观察者是怎么回事吧。lazy型观察者在Vue中体现为computed属性,个别这个属性是一个函数,以下是一个例子: computed: { // getCount最初解决成一个属性,而后这个办法被存储在Watcher的某个属性中 getCount() { return this.a + this.b; }}lazy观察者外面有一个dirty属性,也就是一个开关作用,只有它为true的时候应用getCount的getter办法的时候,才会进行调用这个函数。 如果lazy观察者所援用的数据(a或者b属性)产生扭转后,会将这个放到观察者执行队列中,而后执行这个观察者的时候把dirty赋值为true(代表下次访问getter办法的时候会执行一遍lazy的求值办法(求值后会将dirty赋值为false))。等到下一次须要获取这个数据的时候才进行求值,所以它叫做惰性求值。这种形式可能节俭不必要执行函数的开销。 三、Watcher和Dep的关系看过Vue源码的defineReactive这个办法,就会发现一个被察看的对象外面每个属性会有一个Dep依赖筐来寄存所有察看它的Watcher。而defineReactive办法只有初始化每个属性的dep却并没有创立观察者(要分清初始化和创立观察者是离开这个事实)。那么这个Dep如何增加观察者呢?Vue应用了全局变量,这个变量叫做Dep.target,它是一个Watcher类型的变量,来将Watcher和Dep进行相互绑定。数据的绑定用图来示意的话如下: 咱们能够明确以下区别: $watch办法创立的观察者的时候,如果不设定immediate属性,那么是不会进行调用的,而computed和render是会进行调用办法的。数据的Dep的subs数组寄存这个数据所绑定的观察者对象,观察者对象的deps数组中寄存着与这个观察者无关的数据Dep。所以数据的Dep与Watcher其实是多对多关系$watch和computed观察者是在created生命钩子函数前就创立结束并且绑定的,而render观察者是在mounted之前创立并绑定的,所以同一个组件中,render观察者的id会大于其余观察者(id是在前面执行队列外面升序排序的时候的根据)。 换句话说,在同一个组件的观察者中,当数据产生扭转的时候,渲染函数观察者肯定是最初执行的。 这个很好了解,其余观察者中难免会对数据进行批改,如果渲染函数观察者先执行了,而后其余观察者对数据进行扭转的话,那么没方法将数据精确出现在页面上,导致数据不一致性。四、讲一下观察者执行队列机制Vue是如何实现性能优化的呢?最显著的两个点: 观察者设定执行队列,批量执行。diff算法缩小渲染开销。第二个不在这外面解说,咱们看一下第一个是怎么回事? 这个队列的长度是怎么定量的呢? 最大长度是100,源码摆在那里。 以一个事件循环时间段为收集工夫。(什么是事件循环?能够看一下本博客零碎的其余优良文章)参考 前端进阶面试题具体解答 它的流程是如下的: 未执行时候:如果有更改过数据,那么就将对应的观察者间接推动队列中(执行的时候会进行依据id升序排序后执行)在执行中的时候,如果有新的观察者进来了(观察者中更改数据,而后这个数据又绑定观察者),依照id升序来进行插入(这相当于在有序数组外面进行插入,能够看做插入排序的其中一步,所以某种意义上来说它就是排序)。五、解答后面的问题Dep是负责存放数据所绑定所有的观察者的对象的容器,只有数据产生扭转,就会通过这个Dep来告诉所有观察者进行批改数据。(每个数据都有举世无双的Dep)。而Watcher更偏差于一个动作,也就是规定的业务逻辑或者渲染函数,是一个执行者。在ES5是很轻便的,很好的。然而在ES6呈现后,它就肯定不是最好的,因为ES6有一个Proxy代理来对立进行解决。(ES6应用代理实现Vue数据响应零碎(TypeScript)) 弊病:如果一个数据有1000个属性,那么就要给这1000个属性应用Object.defineProperty,这样在初始化页面的时候会造成卡顿。如果用代理的话,那么只须要执行一次就能够了。破绽:如果咱们拿到了vm实例,那么用户是能够在运行的时候通过批改对象属性的描述符(descriptor)来进行批改它,会造成零碎的不确定性。这是因为响应零碎的模式导致必须将数据的描述符的configuration设为true,所以在运行的时候可能对它进行批改。

December 19, 2022 · 1 min · jiezi

关于vue.js:京东前端高频vue面试题边面边更

Redux 和 Vuex 有什么区别,它们的独特思维(1)Redux 和 Vuex区别 Vuex改良了Redux中的Action和Reducer函数,以mutations变动函数取代Reducer,无需switch,只需在对应的mutation函数里扭转state值即可Vuex因为Vue主动从新渲染的个性,无需订阅从新渲染函数,只有生成新的State即可Vuex数据流的程序是∶View调用store.commit提交对应的申请到Store中对应的mutation函数->store扭转(vue检测到数据变动主动渲染)艰深点了解就是,vuex 弱化 dispatch,通过commit进行 store状态的一次更变;勾销了action概念,不用传入特定的 action模式进行指定变更;弱化reducer,基于commit参数间接对数据进行转变,使得框架更加繁难; (2)独特思维 单—的数据源变动能够预测实质上:redux与vuex都是对mvvm思维的服务,将数据从视图中抽离的一种计划;模式上:vuex借鉴了redux,将store作为全局的数据中心,进行mode治理; v-model 能够被用在自定义组件上吗?如果能够,如何应用?能够。v-model 实际上是一个语法糖,如: <input v-model="searchText">实际上相当于: <input v-bind:value="searchText" v-on:input="searchText = $event.target.value">用在自定义组件上也是同理: <custom-input v-model="searchText">相当于: <custom-input v-bind:value="searchText" v-on:input="searchText = $event"></custom-input>显然,custom-input 与父组件的交互如下: 父组件将searchText变量传入custom-input 组件,应用的 prop 名为value;custom-input 组件向父组件传出名为input的事件,父组件将接管到的值赋值给searchText;所以,custom-input 组件的实现应该相似于这样: Vue.component('custom-input', { props: ['value'], template: ` <input v-bind:value="value" v-on:input="$emit('input', $event.target.value)" > `})MVC 和 MVVM 区别MVC MVC 全名是 Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计榜样 Model(模型):是应用程序中用于解决应用程序数据逻辑的局部。通常模型对象负责在数据库中存取数据View(视图):是应用程序中解决数据显示的局部。通常视图是根据模型数据创立的Controller(控制器):是应用程序中解决用户交互的局部。通常控制器负责从视图读取数据,管制用户输出,并向模型发送数据MVC 的思维:一句话形容就是 Controller 负责将 Model 的数据用 View 显示进去,换句话说就是在 Controller 外面把 Model 的数据赋值给 View。 ...

December 19, 2022 · 8 min · jiezi

关于vue.js:说说你对Vue的keepalive的理解

什么是 keep-alive在平时开发中,有局部组件没有必要屡次初始化,这时,咱们须要将组件进行长久化,使组件的状态维持不变,在下一次展现时,也不会进行从新初始化组件。 也就是说,keepalive 是 Vue 内置的一个组件,能够使被蕴含的组件保留状态,或防止从新渲染 。也就是所谓的组件缓存 <keep-alive>是Vue的内置组件,能在组件切换过程中将状态保留在内存中,避免反复渲染DOM。 <keep-alive> 包裹动静组件时,会缓存不流动的组件实例,而不是销毁它们。和 <transition> 类似,<keep-alive> 是一个形象组件:它本身不会渲染一个 DOM 元素,也不会呈现在父组件链中。prop: include: 字符串或正则表达式。只有匹配的组件会被缓存。exclude: 字符串或正则表达式。任何匹配的组件都不会被缓存。keep-alive的申明周期执行页面第一次进入,钩子的触发程序 created-> mounted-> activated, 退出时触发 deactivated 当再次进入(后退或者后退)时,只触发 activated事件挂载的办法等,只执行一次的放在 mounted 中;组件每次进去执行的办法放在 activated 中;根本用法<!--被keepalive蕴含的组件会被缓存--><keep-alive> <component><component /></keep-alive>被keepalive蕴含的组件不会被再次初始化,也就意味着不会重走生命周期函数 然而有时候是心愿咱们缓存的组件能够可能再次进行渲染,这时 Vue 为咱们解决了这个问题被蕴含在 keep-alive 中创立的组件,会多出两个生命周期的钩子: activated 与 deactivated: activated 当 keepalive 蕴含的组件再次渲染的时候触发deactivated 当 keepalive 蕴含的组件销毁的时候触发keepalive是一个形象的组件,缓存的组件不会被 mounted,为此提供activated和deactivated钩子函数 参数了解keepalive 能够接管3个属性做为参数进行匹配对应的组件进行缓存: include 蕴含的组件(能够为字符串,数组,以及正则表达式,只有匹配的组件会被缓存)exclude 排除的组件(认为字符串,数组,以及正则表达式,任何匹配的组件都不会被缓存)max 缓存组件的最大值(类型为字符或者数字,能够管制缓存组件的个数)注:当应用正则表达式或者数组时,肯定要应用 v-bind <!-- 将(只)缓存组件name为a或者b的组件, 联合动静组件应用 --><keep-alive include="a,b"> <component></component></keep-alive><!-- 组件name为c的组件不缓存(能够保留它的状态或防止从新渲染) --><keep-alive exclude="c"> <component></component></keep-alive><!-- 应用正则表达式,需应用v-bind --><keep-alive :include="/a|b/"> <component :is="view"></component></keep-alive><!-- 动静判断 --><keep-alive :include="includedComponents"> <router-view></router-view></keep-alive><!-- 如果同时应用include,exclude,那么exclude优先于include, 上面的例子只缓存a组件 --><keep-alive include="a,b" exclude="b"> <component></component></keep-alive><!-- 如果缓存的组件超过了max设定的值5,那么将删除第一个缓存的组件 --><keep-alive exclude="c" max="5"> <component></component></keep-alive>遇见 vue-router 联合router应用,缓存局部页面所有门路下的视图组件都会被缓存<keep-alive> <router-view> <!-- 所有门路匹配到的视图组件都会被缓存! --> </router-view></keep-alive>如果只想要router-view外面的某个组件被缓存,怎么办?应用 include/exclude应用 meta 属性1、用 include (exclude例子相似) ...

December 19, 2022 · 2 min · jiezi

关于vue.js:手把手教你vue组件库共享组件不直接打包进代码

1、“共享组件不间接打包进代码”什么意思?比方你写了一个组件库,外面有Button、Dialog、MessageBox3个组件,其中Dialog、MessageBox组件都援用了Button组件,那么Button组件就是共享组件。当对这3个组件挨个打包实现后去查看Dialog、MessageBox组件打包实现后的产物代码,会发现Dialog、MessageBox组件外面都蕴含了Button组件产物代码,这样一来产物体积就变大了。 那有没有什么方法使得打包实现后的Dialog、MessageBox组件产物里不蕴含Button组件产物代码呢?答案必定是有的,比方ant-design-vue、element-ui它们打包后的产物代码中就不蕴含共享组件代码,它们是通过import或require去加载共享组件。 如ant-design-vue打包产物代码: 2 、怎么实现呢?这个问题也困扰了我很久,直到我用esbuild去打包我的【vue3 bootstrap图标组件库】时我才解决这个问题。原理很简略:把共享组件当成内部扩大(Externals) 在打包时通常会把vue设置为内部扩大,那共享组件为甚么不能设置为内部扩大呢?将共享组件设置为内部扩大后webpack或其余打包工具就不会将其打包进产物中,而是以import或require的模式去加载。 看到这里你应该恍然大悟了吧!接下来的代码你就会写了。 3、代码实现(vue3)我这里以esbuild打包为例,webpack或vite代码差不多。 首先须要装置2个要害依赖:npm i esbuild esbuild-plugin-vue -D接下来装置esbuild打包进去依赖:npm i esbuild-plugin-progress -D装置css解决依赖:npm i postcss esbuild-sass-plugin autoprefixer postcss-preset-env postcss-import -D 目录构造: -my-project +node_modules -src -components yn-button.scss YnButton.vue YnDialog.vue YnMessageBox.vue App.vue main.js build-lib.js package.jsonyn-button.scss .yn-button{ transition: all .3s;}YnButton.vue <template><button class="yn-button" :type="nativeType" :disabled="disabled"> <slot></slot></button></template><script>export default { name: 'YnButton', props: { nativeType: { type: String, default: 'button' }, disabled: { type: Boolean, default: false } }};</script><style lang="scss">@import "yn-button";</style>YnDialog.vue <template><dialog v-show="visible" class="yn-dialog" :class="{ 'dialog-opened': visible }" :data-opened-count="openCount"> <h1> <slot name="title">{{ title }}</slot> </h1> <div class="dialog-content"> <slot></slot> </div> <div class="dialog-footer"> <yn-button class="dialog-cancel-btn" @click="close">勾销</yn-button> <yn-button class="dialog-ok-btn" @click="close">确定</yn-button> </div></dialog></template><script>import { ref, watch} from 'vue';// 因为esbuild打包时是以脚本执行目录为根目录,因而这里不以我的项目门路去引入button组件import YnButton from 'src/components/YnButton.vue';let count = 0;export default { name: 'YnDialog', props: { visible: { type: Boolean, default: false }, title: { type: String, default: '' } }, components: { YnButton }, emits: ['update:visible', 'close'], setup (props, ctx) { let openCount = ref(count); watch(() => props.visible, function (isVisible) { count++; openCount.value = count; }); return { openCount, close () { ctx.emit('update:visible', false); ctx.emit('close'); } }; }};</script>YnMessageBox.vue ...

December 18, 2022 · 3 min · jiezi

关于vue.js:P24-vue3-组合式api语法糖

App.vue<script setup>import Content from "./components/Content.vue";</script><template> <div> <Content /> </div></template> 定义相应式变量还是须要vue引入<script setup>import Content from "./components/Content.vue";import { ref } from "vue";const b=ref(100000)const a=20;console.log(a);</script><template> <div> <h2>{{a}}</h2> <h2>{{b}}</h2> <Content /> </div></template>

December 17, 2022 · 1 min · jiezi

关于vue.js:Vue-第二章-Pinia

本文来源于 Home | Pinia 中文文档 (web3doc.top)1、概述Pinia 是 Vue 的存储库,它容许您跨组件/页面共享状态。1)比照 Vuex更小,只有1kb;更简略,actions 能够同时解决同步工作和异步工作;不再有命名空间模块,然而各个 store 之间互相独立并且能够相互援用。组合式 API 格调和良好的 TS 反对。2)装置Vue3 创立一个 pinia(根存储)并将其传递给应用程序 import { createPinia } from 'pinia'app.use(createPinia())Vue 2,您还须要装置一个插件并将创立的 pinia 注入应用程序的根目录须要装置组合 API:@vue/composition-apiimport { createPinia, PiniaVuePlugin } from 'pinia'Vue.use(PiniaVuePlugin)const pinia = createPinia()new Vue({ el: '#app', // ... pinia,})2、store1)定义Store 是应用 defineStore() 定义的,并且它须要一个惟一名称,作为第一个参数传递 这个 name,也称为 id,是必要的,Pinia 应用它来将 store 连贯到 devtools。import { defineStore } from 'pinia'// useStore 能够是 useUser、useCart 之类的任何货色// 第一个参数是应用程序中 store 的惟一 idexport const useStore = defineStore('main', { // other options...})2)模块化能够依据须要定义任意数量的 store ,并且您应该在不同的文件中定义每个 store 以充分利用 pinia。3、state在 Pinia 中,状态被定义为返回初始状态的函数。 ...

December 17, 2022 · 4 min · jiezi

关于vue.js:Vue-第一章-Vuex

本文基于 Vue2 解说 Vuex教程视频: 107_尚硅谷Vue技术_Vuex工作原理图_哔哩哔哩_bilibili1、简介Vuex 是一种状态管理模式,集中式存储和治理利用的所有组件的状态。比照 Pinia Vuex 应用繁多状态树,每个利用仅蕴含一个store实例;而 pinia 能够存在多个 store实例;严格模式下,Vuex 不能间接扭转 store中的状态,惟一路径是显式地提交mutation;而 pinia 能够间接批改;2、外围1)StateVuex 采纳繁多状态树,这棵状态树就是 state,这也意味着,每个利用将仅仅蕴含一个 store 实例。(1)获取状态因为 Vuex 的状态存储是响应式的,从 store 实例中读取状态最简略的办法就是在计算属性中返回某个状态。 // 创立一个 Counter 组件// 每当 `store.state.count` 变动的时候, 都会从新求取计算属性,并且触发更新相关联的 DOM。const Counter = { template: `<div>{{ count }}</div>`, computed: { count () { return store.state.count } }}(2)mapState 辅助函数mapState:把state属性映射到computed身上。当一个组件须要获取多个状态的时候,将这些状态都申明为计算属性会有些反复和冗余,咱们能够应用 mapState 辅助函数帮忙咱们生成计算属性。 import { mapState } from 'vuex';export default{ computed:{ ...mapState("loginModule",["userinfo"]) }}2)Getter就像计算属性一样,getter 的返回值会依据它的依赖被缓存起来,且只有当它的依赖值产生了扭转才会被从新计算。Getter 承受 state 作为其第一个参数,也能够承受其余 getter 作为第二个参数。 const store = new Vuex.Store({ state: { todos: [ { id: 1, text: '...', done: true }, { id: 2, text: '...', done: false } ] }, getters: { doneTodos: state => { return state.todos.filter(todo => todo.done) } doneTodosCount: (state, getters) => { return getters.doneTodos.length } }})(1)通过属性拜访Getter 会裸露为 store.getters 对象,你能够以属性的模式拜访这些值。留神,getter 在通过属性拜访时是作为 Vue 的响应式零碎的一部分缓存其中的。 ...

December 17, 2022 · 4 min · jiezi

关于vue.js:必会vue面试题总结

Composition API 与 Options API 有什么不同剖析 Vue3最重要更新之一就是Composition API,它具备一些列长处,其中不少是针对Options API裸露的一些问题量身打造。是Vue3举荐的写法,因而把握好Composition API利用对把握好Vue3至关重要 What is Composition API?(opens new window) Composition API呈现就是为了解决Options API导致雷同性能代码扩散的景象 体验 Composition API能更好的组织代码,上面用composition api能够提取为useCount(),用于组合、复用 compositon api提供了以下几个函数: setuprefreactivewatchEffectwatchcomputedtoRefs生命周期的hooks答复范例 Composition API是一组API,包含:Reactivity API、生命周期钩子、依赖注入,使用户能够通过导入函数形式编写vue组件。而Options API则通过申明组件选项的对象模式编写组件Composition API最次要作用是可能简洁、高效复用逻辑。解决了过来Options API中mixins的各种毛病;另外Composition API具备更加麻利的代码组织能力,很多用户喜爱Options API,认为所有货色都有固定地位的选项搁置代码,然而单个组件增长过大之后这反而成为限度,一个逻辑关注点扩散在组件各处,造成代码碎片,保护时须要重复横跳,Composition API则能够将它们无效组织在一起。最初Composition API领有更好的类型推断,对ts反对更敌对,Options API在设计之初并未思考类型推断因素,尽管官网为此做了很多简单的类型体操,确保用户能够在应用Options API时取得类型推断,然而还是没方法用在mixins和provide/inject上Vue3首推Composition API,然而这会让咱们在代码组织上多花点心理,因而在抉择上,如果咱们我的项目属于中低复杂度的场景,Options API仍是一个好抉择。对于那些大型,高扩大,强保护的我的项目上,Composition API会取得更大收益可能的诘问 Composition API是否和Options API一起应用?能够在同一个组件中应用两个script标签,一个应用vue3,一个应用vue2写法,一起应用没有问题 <!-- vue3 --><script setup> // vue3写法</script><!-- 降级vue2 --><script> export default { data() {}, methods: {} }</script>vue和react的区别=> 相同点: 1. 数据驱动页面,提供响应式的试图组件2. 都有virtual DOM,组件化的开发,通过props参数进行父子之间组件传递数据,都实现了webComponents标准3. 数据流动单向,都反对服务器的渲染SSR4. 都有反对native的办法,react有React native, vue有wexx=> 不同点: ...

December 16, 2022 · 5 min · jiezi

关于vue.js:每日一题之请描述Vue组件渲染流程

组件化是 Vue, React 等这些框架的一个核心思想,通过把页面拆成一个个高内聚、低耦合的组件,能够极大水平进步咱们的代码复用度,同时也使得我的项目更加易于保护。所以,本文就来剖析下组件的渲染流程。咱们通过上面这个例子来进行剖析: <div id="demo"> <comp></comp></div><script> Vue.component('comp', { template: '<div>I am comp</div>', }) const app = new Vue({ el: '#demo', })</script>这里咱们分为两步来剖析:组件申明、组件创立及渲染 组件申明首先,咱们看下 Vue.component 是什么货色,它的申明在 core/global-api/assets.js: export function initAssetRegisters(Vue: GlobalAPI) { // ASSET_TYPES是数组:['component','directive','filter'] ASSET_TYPES.forEach((type) => { Vue[type] = function ( id: string, definition: Function | Object ): Function | Object | void { if (!definition) { return this.options[type + 's'][id] } else { /* istanbul ignore if */ if (process.env.NODE_ENV !== 'production' && type === 'component') { validateComponentName(id) } // 组件申明相干代码 if (type === 'component' && isPlainObject(definition)) { definition.name = definition.name || id // _base是Vue // Vue.extend({})返回组件构造函数 definition = this.options._base.extend(definition) } if (type === 'directive' && typeof definition === 'function') { definition = {bind: definition, update: definition} } // 注册到components选项中去 // 在Vue原始选项上增加组件配置,未来其余组件继承,它们都有这些组件注册 this.options[type + 's'][id] = definition return definition } } })}这里 this.options._base.extend(definition) 调用的其实就是 Vue.extend(definition): ...

December 16, 2022 · 6 min · jiezi

关于vue.js:百度前端一面必会vue面试题合集

从0到1本人构架一个vue我的项目,说说有哪些步骤、哪些重要插件、目录构造你会怎么组织综合实际类题目,考查实战能力。没有什么相对的正确答案,把平时工作的重点有条理的形容一下即可 思路 构建我的项目,创立我的项目根本构造引入必要的插件:代码标准:prettier,eslint提交标准:husky,lint-staged`其余罕用:svg-loader,vueuse,nprogress常见目录构造答复范例 从0创立一个我的项目我大抵会做以下事件:我的项目构建、引入必要插件、代码标准、提交标准、罕用库和组件目前vue3我的项目我会用vite或者create-vue创立我的项目接下来引入必要插件:路由插件vue-router、状态治理vuex/pinia、ui库我比拟喜爱element-plus和antd-vue、http工具我会选axios其余比拟罕用的库有vueuse,nprogress,图标能够应用vite-svg-loader上面是代码标准:联合prettier和eslint即可最初是提交标准,能够应用husky,lint-staged,commitlint目录构造我有如下习惯: .vscode:用来放我的项目中的 vscode 配置plugins:用来放 vite 插件的 plugin 配置public:用来放一些诸如 页头icon 之类的公共文件,会被打包到dist根目录下src:用来放我的项目代码文件api:用来放http的一些接口配置assets:用来放一些 CSS 之类的动态资源components:用来放我的项目通用组件layout:用来放我的项目的布局router:用来放我的项目的路由配置store:用来放状态治理Pinia的配置utils:用来放我的项目中的工具办法类views:用来放我的项目的页面文件如何从实在DOM到虚构DOM波及到Vue中的模板编译原理,次要过程: 将模板转换成 ast 树, ast 用对象来形容实在的JS语法(将实在DOM转换成虚构DOM)优化树将 ast 树生成代码Vue 子组件和父组件执行程序加载渲染过程: 父组件 beforeCreate父组件 created父组件 beforeMount子组件 beforeCreate子组件 created子组件 beforeMount子组件 mounted父组件 mounted更新过程: 父组件 beforeUpdate子组件 beforeUpdate子组件 updated父组件 updated销毁过程: 父组件 beforeDestroy子组件 beforeDestroy子组件 destroyed父组件 destoryedvue-router 路由钩子函数是什么 执行程序是什么路由钩子的执行流程, 钩子函数品种有:全局守卫、路由守卫、组件守卫 残缺的导航解析流程: 导航被触发。在失活的组件里调用 beforeRouteLeave 守卫。调用全局的 beforeEach 守卫。在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。在路由配置里调用 beforeEnter。解析异步路由组件。在被激活的组件里调用 beforeRouteEnter。调用全局的 beforeResolve 守卫 (2.5+)。导航被确认。调用全局的 afterEach 钩子。触发 DOM 更新。调用 beforeRouteEnter 守卫中传给 next 的回调函数,创立好的组件实例会作为回调函数的参数传入。用VNode来形容一个DOM构造虚构节点就是用一个对象来形容一个实在的DOM元素。首先将 template (实在DOM)先转成 ast , ast 树通过 codegen 生成 render 函数, render 函数里的 _c 办法将它转为虚构dom ...

December 16, 2022 · 3 min · jiezi

关于vue.js:能不能手写Vue响应式前端面试进阶

Vue 视图更新原理Vue 的视图更新原理次要波及的是响应式相干API Object.defineProperty 的应用,它的作用是为对象的某个属性对外提供 get、set 办法,从而实现内部对该属性的读和写操作时可能被外部监听,实现后续的同步视图更新性能 一、实现响应式的外围API:Object.definePropertyObject.defineProperty的用法介绍:MDN-Object.defineProperty,上面是模仿 Vue data 值的更新对API接口进行初步理解 // 模仿 Vue 中的 dataconst data = {}// 对外不可见的外部变量let _myName = 'Yimwu'// 响应式监听 data 中的 nameObject.defineProperty(data, "name", { // 应用 data.name 时 get 办法被调用,返回外部存储变量值 get: () => { console.log('get') return _myName }, // 应用 data.name = xxx 批改变量时,set 办法被调用,设置外部存储变量值 set: (newVal) => { console.log('set') _myName = newVal }})console.log(data.name) // 输入 Yimwu getdata.name = 'Mr.Wu' // 输入 set (监听胜利)二、视图更新初步实现1、updateView为了不便 模仿视图更新,这里创立了一个函数 updateView ,当数据更新时,调用 updateView ,模仿进行了视图更新(在 Vue 中体现为 template 模板中援用了该变量值的 DOM 元素的变动) ...

December 16, 2022 · 3 min · jiezi

关于vue.js:前端vue面试题汇总

常见的事件修饰符及其作用.stop:等同于 JavaScript 中的 event.stopPropagation() ,避免事件冒泡;.prevent :等同于 JavaScript 中的 event.preventDefault() ,避免执行预设的行为(如果事件可勾销,则勾销该事件,而不进行事件的进一步流传);.capture :与事件冒泡的方向相同,事件捕捉由外到内;.self :只会触发本人范畴内的事件,不蕴含子元素;.once :只会触发一次。如何从实在DOM到虚构DOM波及到Vue中的模板编译原理,次要过程: 将模板转换成 ast 树, ast 用对象来形容实在的JS语法(将实在DOM转换成虚构DOM)优化树将 ast 树生成代码父子组件生命周期调用程序(简略)渲染程序:先父后子,实现程序:先子后父 更新程序:父更新导致子更新,子更新实现后父 销毁程序:先父后子,实现程序:先子后父 v-show 与 v-if 有什么区别?v-if 是真正的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建;也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。 v-show 就简略得多——不论初始条件是什么,元素总是会被渲染,并且只是简略地基于 CSS 的 “display” 属性进行切换。 所以,v-if 实用于在运行时很少扭转条件,不须要频繁切换条件的场景;v-show 则实用于须要十分频繁切换条件的场景。 MVC 和 MVVM 区别MVC MVC 全名是 Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计榜样 Model(模型):是应用程序中用于解决应用程序数据逻辑的局部。通常模型对象负责在数据库中存取数据View(视图):是应用程序中解决数据显示的局部。通常视图是根据模型数据创立的Controller(控制器):是应用程序中解决用户交互的局部。通常控制器负责从视图读取数据,管制用户输出,并向模型发送数据MVC 的思维:一句话形容就是 Controller 负责将 Model 的数据用 View 显示进去,换句话说就是在 Controller 外面把 Model 的数据赋值给 View。 MVVM MVVM 新增了 VM 类 ViewModel 层:做了两件事达到了数据的双向绑定 一是将【模型】转化成【视图】,行将后端传递的数据转化成所看到的页面。实现的形式是:数据绑定。二是将【视图】转化成【模型】,行将所看到的页面转化成后端的数据。实现的形式是:DOM 事件监听。MVVM 与 MVC 最大的区别就是:它实现了 View 和 Model 的主动同步,也就是当 Model 的属性扭转时,咱们不必再本人手动操作 Dom 元素,来扭转 View 的显示,而是扭转属性后该属性对应 View 层显示会主动扭转(对应Vue数据驱动的思维) ...

December 15, 2022 · 5 min · jiezi

关于vue.js:每日一题之Vue数据劫持原理是什么

什么是数据劫持?定义: 数据劫持,指的是在拜访或者批改对象的某个属性时,通过一段代码拦挡这个行为,进行额定的操作或者批改返回后果。 简略地说,就是当咱们 触发函数的时候 动一些手脚做点咱们本人想做的事件,也就是所谓的 "劫持"操作 数据劫持的两种计划:Object.definePropertyProxy1).Object.defineProperty语法:Object.defineProperty(obj,prop,descriptor) 参数: obj:指标对象prop:须要定义的属性或办法的名称descriptor:指标属性所领有的个性可供定义的个性列表: value:属性的值writable:如果为false,属性的值就不能被重写。get: 一旦指标属性被拜访就会调回此办法,并将此办法的运算后果返回用户。set:一旦指标属性被赋值,就会调回此办法。configurable:如果为false,则任何尝试删除指标属性或批改属性性以下个性(writable, configurable, enumerable)的行为将被有效化。enumerable:是否能在for...in循环中遍历进去或在Object.keys中列举进去。例子在Vue中其实就是通过Object.defineProperty来劫持对象属性的setter和getter操作,并“种下”一个监听器,当数据发生变化的时候发出通知,如下: var data = {name:'test'}Object.keys(data).forEach(function(key){ Object.defineProperty(data,key,{ enumerable:true, configurable:true, get:function(){ console.log('get'); }, set:function(){ console.log('监听到数据产生了变动'); } })});data.name //控制台会打印出 “get”data.name = 'hxx' //控制台会打印出 "监听到数据产生了变动"下面的这个例子能够看出,咱们齐全能够管制对象属性的设置和读取。在Vue中,在很多中央都十分奇妙的使用了Object.defineProperty这个办法,具体用在哪里并且它又解决了哪些问题,上面就简略的说一下: 监听对象属性的变动它通过observe每个对象的属性,增加到订阅器dep中,当数据发生变化的时候收回一个notice。 相干源代码如下:(作者采纳的是ES6+flow写的,代码在src/core/observer/index.js模块外面) export function defineReactive ( obj: Object, key: string, val: any, customSetter?: Function) { const dep = new Dep()//创立订阅对象 const property = Object.getOwnPropertyDe述 //属性的形容个性外面如果configurable为false则属性的任何批改将有效 if (property && property.configurable === false) { return }scriptor(obj, key)//获取obj对象的key属性的描 // cater for pre-defined getter/setters const getter = property && property.get const setter = property && property.set let childOb = observe(val)//创立一个观察者对象 Object.defineProperty(obj, key, { enumerable: true,//可枚举 configurable: true,//可批改 get: function reactiveGetter () { const value = getter ? getter.call(obj) : val//先调用默认的get办法取值 //这里就劫持了get办法,也是作者一个奇妙设计,在创立watcher实例的时候,通过调用对象的get办法往订阅器dep上增加这个创立的watcher实例 if (Dep.target) { dep.depend() if (childOb) { childOb.dep.depend() } if (Array.isArray(value)) { dependArray(value) } } return value//返回属性值 }, set: function reactiveSetter (newVal) { const value = getter ? getter.call(obj) : val//先取旧值 if (newVal === value) { return } //这个是用来判断生产环境的,能够忽视 if (process.env.NODE_ENV !== 'production' && customSetter) { customSetter() } if (setter) { setter.call(obj, newVal) } else { val = newVal } childOb = observe(newVal)//持续监听新的属性值 dep.notify()//这个是真正劫持的目标,要对订阅者发告诉了 } })}以上是Vue监听对象属性的变动,那么问题来了,咱们常常在传递数据的时候往往不是一个对象,很有可能是一个数组,那是不是就没有方法了呢,答案显然是否则的。那么上面就看看作者是如何监听数组的变动: ...

December 15, 2022 · 4 min · jiezi

关于vue.js:腾讯前端常考vue面试题必备

虚构DOM的优劣如何?长处: 保障性能上限: 虚构DOM能够通过diff找出最小差别,而后批量进行patch,这种操作尽管比不上手动优化,然而比起粗犷的DOM操作性能要好很多,因而虚构DOM能够保障性能上限无需手动操作DOM: 虚构DOM的diff和patch都是在一次更新中主动进行的,咱们无需手动操作DOM,极大进步开发效率跨平台: 虚构DOM实质上是JavaScript对象,而DOM与平台强相干,相比之下虚构DOM能够进行更不便地跨平台操作,例如服务器渲染、挪动端开发等等毛病: 无奈进行极致优化: 在一些性能要求极高的利用中虚构DOM无奈进行针对性的极致优化,比方VScode采纳间接手动操作DOM的形式进行极其的性能优化如果让你从零开始写一个vue路由,说说你的思路思路剖析: 首先思考vue路由要解决的问题:用户点击跳转链接内容切换,页面不刷新。 借助hash或者history api实现url跳转页面不刷新同时监听hashchange事件或者popstate事件处理跳转依据hash值或者state值从routes表中匹配对应component并渲染答复范例: 一个SPA利用的路由须要解决的问题是 页面跳转内容扭转同时不刷新 ,同时路由还须要以插件模式存在,所以: 首先我会定义一个createRouter函数,返回路由器实例,实例外部做几件事保留用户传入的配置项监听hash或者popstate事件回调里依据path匹配对应路由将router定义成一个Vue插件,即实现install办法,外部做两件事实现两个全局组件:router-link和router-view,别离实现页面跳转和内容显示定义两个全局变量:$route和$router,组件内能够拜访以后路由和路由器实例你有对 Vue 我的项目进行哪些优化?(1)代码层面的优化 v-if 和 v-show 辨别应用场景computed 和 watch 辨别应用场景v-for 遍历必须为 item 增加 key,且防止同时应用 v-if长列表性能优化事件的销毁图片资源懒加载路由懒加载第三方插件的按需引入优化有限列表性能服务端渲染 SSR or 预渲染(2)Webpack 层面的优化 Webpack 对图片进行压缩缩小 ES6 转为 ES5 的冗余代码提取公共代码模板预编译提取组件的 CSS优化 SourceMap构建后果输入剖析Vue 我的项目的编译优化(3)根底的 Web 技术的优化 开启 gzip 压缩浏览器缓存CDN 的应用应用 Chrome Performance 查找性能瓶颈写过自定义指令吗 原理是什么指令实质上是装璜器,是 vue 对 HTML 元素的扩大,给 HTML 元素减少自定义性能。vue 编译 DOM 时,会找到指令对象,执行指令的相干办法。 自定义指令有五个生命周期(也叫钩子函数),别离是 bind、inserted、update、componentUpdated、unbind 1. bind:只调用一次,指令第一次绑定到元素时调用。在这里能够进行一次性的初始化设置。2. inserted:被绑定元素插入父节点时调用 (仅保障父节点存在,但不肯定已被插入文档中)。3. update:被绑定于元素所在的模板更新时调用,而无论绑定值是否变动。通过比拟更新前后的绑定值,能够疏忽不必要的模板更新。4. componentUpdated:被绑定元素所在模板实现一次更新周期时调用。5. unbind:只调用一次,指令与元素解绑时调用。原理 ...

December 15, 2022 · 5 min · jiezi

关于vue.js:每日一题之Vue的异步更新实现原理是怎样的

最近面试总是会被问到这么一个问题:在应用vue的时候,将for循环中申明的变量i从1减少到100,而后将i展现到页面上,页面上的i是从1跳到100,还是会怎么?答案当然是只会显示100,并不会有跳转的过程。 怎么能够让页面上有从1到100显示的过程呢,就是用setTimeout或者Promise.then等办法去模仿。 讲道理,如果不在vue里,独自运行这段程序的话,输入肯定是从1到100,然而为什么在vue中就不一样了呢? for(let i=1; i<=100; i++){ console.log(i);}这就波及到Vue底层的异步更新原理,也要说一说nextTick的实现。不过在说nextTick之前,有必要先介绍一下JS的事件运行机制。 JS运行机制家喻户晓,JS是基于事件循环的单线程的语言。执行的步骤大抵是: 当代码执行时,所有同步的工作都在主线程上执行,造成一个执行栈;在主线程之外还有一个工作队列(task queue),只有异步工作有了运行后果就在工作队列中搁置一个事件;一旦执行栈中所有同步工作执行结束(主线程代码执行结束),此时主线程不会闲暇而是去读取工作队列。此时,异步的工作就完结期待的状态被执行。主线程一直反复以上的步骤。 咱们把主线程执行一次的过程叫一个tick,所以nextTick就是下一个tick的意思,也就是说用nextTick的场景就是咱们想在下一个tick做一些事的时候。所有的异步工作后果都是通过工作队列来调度的。而工作分为两类:宏工作(macro task)和微工作(micro task)。它们之间的执行规定就是每个宏工作完结后都要将所有微工作清空。常见的宏工作有setTimeout/MessageChannel/postMessage/setImmediate,微工作有MutationObsever/Promise.then。 nextTick原理派发更新大家都晓得vue的响应式的靠依赖收集和派发更新来实现的。在批改数据之后的派发更新过程,会触发setter的逻辑,执行dep.notify(): // src/core/observer/watcher.jsclass Dep { notify() { //subs是Watcher的实例数组 const subs = this.subs.slice() for(let i=0, l=subs.length; i<l; i++){ subs[i].update() } }}遍历subs里每一个Watcher实例,而后调用实例的update办法,上面咱们来看看update是怎么去更新的: class Watcher { update() { ... //各种状况判断之后 else{ queueWatcher(this) } }}update执行后又走到了queueWatcher,那就持续去看看queueWatcher干啥了(心愿不要持续套娃了: //queueWatcher 定义在 src/core/observer/scheduler.jsconst queue: Array<Watcher> = []let has: { [key: number]: ?true } = {}let waiting = falselet flushing = falselet index = 0export function queueWatcher(watcher: Watcher) { const id = watcher.id //依据id是否反复做优化 if(has[id] == null){ has[id] = true if(!flushing){ queue.push(watcher) }else{ let i=queue.length - 1 while(i > index && queue[i].id > watcher.id){ i-- } queue.splice(i + 1, 0, watcher) } if(!waiting){ waiting = true //flushSchedulerQueue函数: Flush both queues and run the watchers nextTick(flushSchedulerQueue) } }}这里queue在pushwatcher时是依据id和flushing做了一些优化的,并不会每次数据扭转都触发watcher的回调,而是把这些watcher先增加到⼀个队列⾥,而后在nextTick后执⾏flushSchedulerQueue。 ...

December 15, 2022 · 2 min · jiezi

关于vue.js:P22-vue3-setup中监听watch-计算属性computed使用

watch和watchEffect<script>//import Hello from "./components/Hello.vue";import { ref,reactive,toRefs,watch, watchEffect } from "vue";export default { data() { return { message: 'hellokougou' }; }, setup(){//setup 组件被创立之前执行,不须要应用this const counter=ref(0) function changeCounter(){ counter.value++ } const user=reactive({ name:'tom', age:56, }) function changeName(){ user.name='sean' } watch(counter, (newVal,oldVal)=>{ console.log('new',newVal) console.log(oldVal) }) watch(user,(newVal,oldVal)=>{ console.log('new',newVal) console.log(oldVal) }) //只有一个回调函数 watchEffect(()=>{ console.log(user.name,'watcheffect') }) return { counter,user,changeCounter,changeName } }, //选项式api watch:{ messages:function (newVal,oldVal){ console.log(newVal) } }, methods:{ }, components:{ //Hello }}</script><template> <div> <h2>{{counter}}</h2> <button @click="changeCounter">changeCounter</button> <h2>{{user.name}}</h2> <button @click="changeName">changeName</button> </div></template> ...

December 2, 2022 · 1 min · jiezi

关于vue.js:Proxy代理数据拦截方法

proxyProxy 对象用于创立一个对象的代理,从而实现基本操作的拦挡和自定义(如属性查找、赋值、枚举、函数调用等)。 new Proxy(target,handler)// target 是proxy 要包装的对象 (能够是数组、函数,也能够是另一个Proxy)//handler 一个通常以函数作为属性的对象,用来定制拦挡行为根本的语法是: const p = new Proxy(target,handler)次要的办法有: handler.has() 是针对 in 操作符的代理办法 handler.set() 办法是设置属性值操作的捕捉器。 handler.get() 办法用于拦挡对象的读取属性操作。 handler.defineProperty() 用于拦挡对对象的 Object.defineProperty() 操作。 handler.deleteProperty() 办法用于拦挡对对象属性的 delete 操作。 handler.has()办法const obj = { name: '微芒不朽', occupation: '前端开发'}const handler = { has(target, key) { //判断是否存在该属性 return key in target }}const p = new Proxy(obj, handler)console.log(p.name) //微芒不朽console.log(p.like) //undefinedconsole.log(p.occupation) //前端开发handler.get()办法const obj = { name: '微芒不朽', occupation: '前端开发'}const handler = { has(target, key) { //判断是否存在该属性 return key in target }, get(target, key) { if (key in target) { return target[key] } else { return new ReferenceError(key + '属性不存在') } }}const p = new Proxy(obj, handler)console.log(p.name) //微芒不朽console.log(p.like) //ReferenceError: like属性不存在console.log(p.occupation) //前端开发handler.set()办法const obj = { name: '微芒不朽', occupation: '前端开发'}const handler = { set(target, key) { if (key in target) { return Reflect.set(...arguments) } throw new ReferenceError(key+'属性不存在') }}const p = new Proxy(obj, handler)p.like = '编程' //Uncaught ReferenceError: like属性不存在// console.log(p.like)p.occupation = '测试'console.log(p.occupation) //测试handler.defineProperty() 办法用于拦挡对对象的 Object.defineProperty() 操作 ...

November 30, 2022 · 3 min · jiezi

关于vue.js:P21-vue3-组合式-api

什么是组合式 API?组合式 API (Composition API) 是一系列 API 的汇合,使咱们能够应用函数而不是申明选项的形式书写 Vue 组件。它是一个概括性的术语,涵盖了以下方面的 API: 响应式 API:例如 ref() 和 reactive(),使咱们能够间接创立响应式状态、计算属性和侦听器。 生命周期钩子:例如 onMounted() 和 onUnmounted(),使咱们能够在组件各个生命周期阶段增加逻辑。 依赖注入:例如 provide() 和 inject(),使咱们能够在应用响应式 API 时,利用 Vue 的依赖注入零碎。 组合式 API 是 Vue 3 及 Vue 2.7 的内置性能。对于更老的 Vue 2 版本,能够应用官网保护的插件 @vue/composition-api。在 Vue 3 中,组合式 API 基本上都会配合 setup 组件被创立之前执行,不须要应用thisApp.vue <script>import Hello from "./components/Hello.vue";export default {data() { return { message: '', isShow: true };},setup(){//setup 组件被创立之前执行,不须要应用this console.log('setup') const msg='hellokugou666' console.log(msg)},beforeCreate() { console.log('beforeCreate')},created() { console.log('created')},methods:{ getChildMsg:function (value){ console.log(value); this.message=value }},components:{ Hello}}</script><template><div> <Hello v-if="isShow"/> <button @click="isShow=!isShow">销毁Hello组件</button></div></template> ...

November 30, 2022 · 1 min · jiezi

关于vue.js:✨-Vue3开发或许你需要这样使用请求API

大家好,我是vue-hooks-plus的作者,这里和大家分享一下属于Vue3的方便快捷的申请形式是怎么样的。 Vue3 当初曾经越来越多小伙伴用上了,在很多技术群中对于Vue3的评估是很高的,在技术博客、群里也会见到很多小伙伴展现本人的 Vue3 代码块以及对 Vue3 我的项目搭建的一些心得。 置信大部分我的项目采纳了 Vite+Vue3开发,联合网上的资源我发现对于我的项目整体大架构,比方 状态治理 pinia、开发构建 Vite 、UI 框架 Element-plus 、Vant 、Antd-vue 等支流框架,网络申请 axios 曾经有很成熟的搭建应用计划了,咱们搞业务开发,基本上围绕着网络申请打交道,这里和大家聊聊鲜为人知的、好保护、品质牢靠的业务API申请 。 列出我所知的申请应用的计划二次封装 axios、文件夹对立治理API申请,返回一个 Promise,在组件中应用链式调用二次封装 axios、文件夹对立治理API申请,返回一个 Promise,在组件中应用 async/await 应用二次封装axios、全局注入axios,组件内间接调用中这个实例去传参数调用间接应用 axios 申请(反复繁冗的代码,不利于保护,这里只做举例,不举荐 ❌)我置信很多小伙伴都属于以上的应用计划,我会一一和大家剖析,谈一下对于 Vue3 网络申请这块的见解。 剖析二次封装 Axios const axiosInstance = axios.create({ baseURL: import.meta.env.VITE_SCREEN_BASE_URL, timeout: 1_000 * 10});// ... 省略拦截器治理API的文件夹 export function getData(params,options){ return new Promise((resolve, reject) => {   axiosInstance({     url,     params,     ...options,   })     .then((res) => {       resolve(res?.data?.data);     })     .catch((err) => {       reject(err);     }); }}链式调用,比拟传统const data = ref()getData({...xxx},{...xxx}).then((res)=>{ // ...这里解决数据 data.value = res.data}).catch(err=>{ // ...xxx})Async/Await 调用,比拟优雅 const data = ref() onMounted(async () => { const res = await getData({...x},{...x}) data.value = res }Provide/Inject 调用,和链式用法基本一致,只是代码量稍少。main.tsimport axios from 'axios'import VueAxios from 'vue-axios'app.use(VueAxios, axios)app.provide('axios', app.config.globalProperties.axios) App.vueconst axios: any = inject('axios') // inject axiosaxios({url,data,...其余配置}).then() // 同上 认识我置信很多小伙伴会比拟喜爱第二种的 async/await 的语法糖,比拟优雅,简洁。 ...

November 30, 2022 · 3 min · jiezi

关于vue.js:elementui中Checkbox-多选框使用后端返回的数据并更改状态提交给后端

最近在开发我的项目,用到了element-ui的多选框性能,因为前端渲染的字段和提交给后端的字段不统一,还是参考了其余的我的项目中的性能,才实现。上面记录一下: <!DOCTYPE html><html><head> <meta charset="utf-8"> <title>element-ui中Checkbox 多选框应用后端返回的数据</title> <!--引入 element-ui 的款式,--> <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"> <script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script> <!-- 引入element 的组件库--> <script src="https://unpkg.com/element-ui/lib/index.js"></script> <style> * { margin: 0; padding: 0; } #app { margin: 100px; } </style></head><body> <div id="app"> <el-form ref="form" :model="form" label-width="80px"> <el-form-item label="流动性质"> <el-checkbox-group v-model="form.checkList"> <el-checkbox label="1">上海</el-checkbox> <el-checkbox label="2">南京</el-checkbox> </el-checkbox-group> </el-form-item> <el-button type="primary" @click="onSubmit">立刻创立</el-button> </el-form-item> </el-form> </div> <script> new Vue({ el: '#app', data() { return { // 模仿ajax返回的数据 ajaxDate: { // city1返回0的时候应该选中, 返回空字符串'' 应该不选中 city1: '', // city1返回0的时候应该选中, 返回空字符串'' 应该不选中 city2: '', }, // 本地渲染 form: { checkList: [], } } }, created() { // 模仿ajax返回的数据 setTimeout(() => { this.ajaxDate.city1 == '0' ? this.form.checkList.push('1') : ''; this.ajaxDate.city2 == '0' ? this.form.checkList.push('2') : ''; }, 500) }, methods: { // 本地渲染的值转换为要传递给后端定义的值 checkConvertFun(dataList, val) { if (dataList && dataList.length > 0) { return dataList.indexOf(val) > -1 ? '0' : '' } else { return '' } }, // 表单提交 onSubmit() { const city1 = this.checkConvertFun(this.form.checkList, '1'); const city2 = this.checkConvertFun(this.form.checkList, '2'); const param = { ...this.ajaxDate, ...{ city1, city2 } }; console.log(param, '传递ajax的参数') } } }) </script></body></html>

November 27, 2022 · 1 min · jiezi

关于vue.js:Vue登录跳转问题

实现一个网页未登录时主动跳转至登录界面?在地址栏输出url之后,如果以后localStorage中并未存储==token==并且咱们要去的网页并不是登录页面,可想而知,该当强制跳转至登录页面。这里就能够利用vue-router的路由守卫来实现。 利用beforeEach,当token存在或者要去往的页面是登录页面(我要登录总还是能够的吧~),间接放行;否则,利用next跳转至登录界面(路由为'/login')// src/router/index.jsrouter.beforeEach((to, from, next) => { const token = localStorage.getItem('token') if (token || to.path === '/login') { next() } else { next('/login') }})用户名与明码正确后登录又如何跳转至首页(或者其余页面)?实现了下面的束缚之后,咱们就能够来实现登录性能了。 当用户名明码正确之后,点击登录,但这时咱们还无奈跳转至首页,因为下面的路由守卫中还须要token,咱们应能从后端获取到token,并将该token存入localStorage中,并利用router.replace('/')来进行路由跳转。 以下是一个小例子: // 利用element plus的表单性能const submitForm = (formRef) => { formRef.validate((valid) => { if (valid) { // 如果表单校验胜利并且用户名和明码正确,则将token存储起来,并跳转至首页 if (loginForm.value.username === 'admin' && loginForm.value.password === 'admin') { localStorage.setItem('token', 'i have token!') router.replace('/') } } else { console.log('error') } })}

November 25, 2022 · 1 min · jiezi

关于vue.js:P20-vue3-生命周期-勾子

Vue每个生命周期的具体介绍:beforeCreate(){}:Vue创立前,此阶段为实例初始化之后,this指向创立的实例,数据察看,数据监听事件机制都未造成,不能取得DOM节点。data,computed,watch,methods 上的办法和数据均不能拜访,注:date和methods的数据都还未初始化。 Created(){}: Vue创立后,此阶段为实例初始化之后,data、props、computed的初始化导入实现, 注:要调用methods中的办法,或者操作data中的数据,最早只能在Created中操作 能拜访 data computed watch methods 上的办法和数据,初始化实现时的事件写这个外面, 此阶段还未挂载DOM。 beforeMount(){}: Vue载入前,阶段执行时, 模板曾经在内存中编译好了,然而未挂载到页面中,(页面还是旧的) 注:这个阶段是过渡性的,个别一个我的项目只能用到一两次。 Mounted(){}:Vue载入后,(实现创立vm.$el,和双向绑定); 只有执行完mounted,就示意整个Vue实例曾经初始化实现了,此时组件曾经脱离里了创立阶段, 进入到了运行阶段。 beforeUpdate(){}:Vue更新前, 当执行beforeUpdate的时候,页面中显示的数据还是旧的,此时date数据是最新的,页面尚未和最新数据数据放弃同步。然而DOM中的数据会扭转,这是vue双向数据绑定的作用,可在更新前拜访现有的DOM,如手动移出增加的事件监听器。 Updated(){}:Vue更新后, Updated执行时数据曾经放弃同步了,都是最新的, 实现虚构DOM的从新渲染和打补丁。组件DOM已实现更新,可执行依赖的DOM操作。 留神:不要在此函数中操作数据(批改属性),否则就会陷入死循环。 beforeUnmount(){}:(Vue销毁前,可做一些删除提醒,比方:您确定删除**吗?) 当执行beforeDestroy的时候,Vue实例就曾经从运行阶段进入到销毁阶段了。实例上的所有date和methods以及过滤器和指令都是处于可用状态,此时还没有真正的执行销毁过程。 unmounted(){}:Vue销毁后, 当执行到destroted函数的时候,组件曾经齐全销毁(渣都不剩),此时组件中的所有的数据,办法,指令,过滤器...都曾经销毁(不可用了)。 createApp.vue<script>import Hello from "./components/Hello.vue";export default { data() { return { message: '', }; }, methods:{ getChildMsg:function (value){ console.log(value); this.message=value } }, components:{ Hello }}</script><template> <div> <Hello/> </div></template>Hello.vue<template> <div>Hellokugou</div> </template><script>export default { data(){ return{ counter: 0, }; }, beforeCreate() { console.log('beforeCreate'); }, created() { console.log('created'); }, beforeMount() { console.log('beforeMount'); }, mounted() { console.log('mounted'); }, beforeUpdate() { console.log('beforeUpdate'); }, updated() { console.log('updated'); }, beforeUnmount() { console.log('beforeUnmount'); }, unmounted() { console.log('unmounted'); }, name: "Hello"}</script><style scoped></style> ...

November 25, 2022 · 2 min · jiezi

关于vue.js:Vue3封装elupload

前言在Vue3我的项目中,如果咱们想上传图片个别能够利用element-ui中的el-upload,为了防止代码的反复,咱们能够本人封装一个图片上传组件。 其中,次要实现思维为前端利用el-upload组件抉择上传的图片,并利用其http-request属性来自定义函数来实现文件上传申请:该申请函数应用七牛云的对象存储,在通过后端失去的上传凭证token起初实现文件上传。 后端代码应用express框架,获取七牛云上传凭证并响应给前端我的项目构造- routes |- token.js |- index.js- app.js- config.js- package.json装置七牛云的SDK:npm i qiniu获取上传凭证编写获取上传凭证的相干代码: /* config.js */const qiniu = require('qiniu')// 创立上传凭证const accessKey = '*****' // 这里填写七牛云的accessKeyconst secretKey = '*****'// 这里填写七牛云的secretKeyconst mac = new qiniu.auth.digest.Mac(accessKey, secretKey)const options = { scope: '*****', // 这里填写七牛云空间名称 expires: 60 * 60 * 24 * 7 // 这里是凭证的无效工夫,默认是一小时}const putPolicy = new qiniu.rs.PutPolicy(options)const uploadToken = putPolicy.uploadToken(mac)module.exports = { uploadToken}配置路由token.js const tokenRouter = require('express').Router()const qnconfig = require('../config') // 引入七牛云配置tokenRouter.get('/qiniu', (req, res, next) => { res.status(200).send(qnconfig.uploadToken)})module.exports = tokenRouterindex.js ...

November 25, 2022 · 2 min · jiezi

关于vue.js:vue2-element-ui-input输入格式限制

import Vue from "vue";/** * element-input 输出限度 * *///v-positiveInteger 正整数//v-positiveInteger.2 保留两位小数//v-positiveInteger.4 保留四位小数Vue.directive("positiveInteger", { bind(el, binding, vnode) { let dom = findDom(el, "el-input__inner"); let modifiers = binding.modifiers let mantissa = 0 for (let x in modifiers) { mantissa = x } el.handler = function () { if (vnode.inputLocking) { return; } if(mantissa) { let reg = new RegExp(`^\\D*(\\d*(?:\.\\d{0,${mantissa}})?).*$`, 'gmi') el.childNodes[1].value = el.childNodes[1].value.replace(reg, "$1"); }else { el.childNodes[1].value = el.childNodes[1].value.replace(/\D+/g, ""); } }; dom.addEventListener("compositionstart", () => { vnode.inputLocking = true; }); dom.addEventListener("compositionend", () => { vnode.inputLocking = false; dom.dispatchEvent(new Event("input")); }); dom.onfocus = function () { if (dom.value == 0) { dom.value = ""; } }; el.addEventListener("keyup", el.handler); el.handler1 = function () { el.childNodes[1].value = el.childNodes[1].value; dom.dispatchEvent(new Event("input")); }; el.childNodes[1].addEventListener("blur", el.handler1); }, unbind(el) { el.removeEventListener("keyup", el.handler); el.childNodes[1].removeEventListener("blur", el.handler); },});//递归查找某个元素节点function findDom(el, className) { let dom; for (let i = 0; i < el.childNodes.length; i++) { if (el.childNodes[i].nodeType == 1) { let str = el.childNodes[i].getAttribute("class"); if (str.indexOf(className) > -1) { dom = el.childNodes[i]; break; } else { dom = findDom(el.childNodes[i], className); } } } return dom;}参考文章 ...

November 25, 2022 · 1 min · jiezi

关于vue.js:P19-vue3-Provide和-Inject

App.vue<script>import HomeView from "./components/HomeView.vue";export default { data() { return { message: '', }; }, methods:{ getChildMsg:function (value){ console.log(value); this.message=value } }, components:{ HomeView }}</script><template> <div> <HomeView/> </div></template>HomeView.vue<template> <div> <Content/> </div></template><script>import Content from "./Content.vue";export default { data(){ return{ message: "Hellokugou", } }, //provide:{message:"Hellokugou"}, provide(){ return{ message:this.message } }, name: "HomeView", components: { Content }}</script><style scoped></style>Content.vue<template> <div> <!--组件是能够复用 --> <HelloKugou></HelloKugou> </div></template><script>import HelloKugou from "./HelloKugou.vue";export default { data(){//让每一个组件对象都返回一个对象,不对数据净化 return{ }; }, components:{ HelloKugou }, methods:{ }, name: "Content"}</script><style scoped></style>HelloKugou.vue<template> <div> <h2>I am hello 组件</h2> <h2>{{message}}</h2> </div></template><script>export default { name: "HelloKugou", data(){ return{}; }, inject:['message']};</script> ...

November 25, 2022 · 2 min · jiezi

关于vue.js:P18-vue-插槽的基本使用

根本用法App.vue <script>import Content from "./components/Content.vue";export default { data() { return { message: '', }; }, methods:{ getChildMsg:function (value){ console.log(value); this.message=value } }, components:{ Content }}</script><template><div> <Content><button>btn</button></Content> <Content><input type="text"></Content></div></template>Content.vue<template> <div> <h2>I am content</h2> <div> <slot></slot> </div> </div></template> 具名插槽 App.vue <script>import Content from "./components/Content.vue";export default { data() { return { message: '', }; }, methods:{ getChildMsg:function (value){ console.log(value); this.message=value } }, components:{ Content }}</script><template><div> <Content><button>btn</button></Content> <Content><input type="text"><button>btn2</button></Content> <Content> <template v-slot:button><button>btn4</button></template> <template v-slot:input><input type="text"></template> <template v-slot:h2><h2>插槽</h2></template> </Content></div></template>Content.vue<template> <div> <h2>I am content</h2> <div> <slot name="button"></slot> <slot name="input"></slot> <slot name="h2"></slot> </div> </div></template> ...

November 23, 2022 · 1 min · jiezi

关于vue.js:2022倾城之链运营第-6-年感记

转眼间,间隔「倾城之链」诞生之时,已有六年之久。现在(2022.10.25),倾城收录网站已冲破 1000 款,值此之时,有必要督促本人深刻思考,不仅是「倾城」过往的总结、将来之构想,更要确立后续业余我的项目方向、乃至职业规划。于是乎,便有了这篇文章,也无意将其做成年度系列,年与时驰,环境变迁,认知更替,载之于文,以慰这似水流年。 利用名称倾城之链。 利用平台Web 利用、小程序、快利用。 利用简介倾城之链,新一代开放型导航平台,为星散寰球「优质网站」而生。在这里,您能够便捷的摸索互联网中那更广大的世界,同时还能分享为您所欢喜的网站。 官网地址https://nicelinks.site/ 。 利用简介摸索更广大的世界,为您在这个信息化的世界,海量的讯息可能让您手足无措;放心错过她而致力吸取的同时,却可能错过更多;「倾城之链」的存在,即是为您解决这种困扰;在这里,您能够浏览寰球各类智慧的结晶;丰盛视线的同时,能够标注抑或分享您喜爱的站点,从而为更多开掘讯息的人提供建设性参考。 分享,为您所欢喜的网站在当今这信息化时代,即使是再小的个体,也当有本人的品牌。=然而,独立的才是本人的。「倾城之链」作为一个开放平台,激励您发明属于您的集体品牌,烙印着本人的格调,替本人代言、发声。如果您曾经这样做了,您能够纵情分享在这里,让更多人晓得,且从中受害。当然,您也能够分享出您欢喜的其余有意思站点,让您的见识惠及更多人。 利用截图 网站特色收集有价值网站,并在后盾审核,力争所收录的内容,可对别人产生踊跃作用;激励用户自荐、举荐欢喜的网站,使得见闻、见识能够相互,从而惠及更多人;尽最大可能为收录的网站,提供欠缺举荐语,使用户能轻易晓得该网站价值;内置搜寻性能,并在不断完善中,使得用户能够便捷索引到被动想要的内容;继续在经营的社交网站等,对优质网站,进行分享流传,从而晋升其访问量;陆续更新其它性能如箴言锦语(星散所喜爱的曼妙句子),以促成网站趣味性。所用技术前端:Vue、vue-router、Webpack、vuex、axios、marked 等后端:Node(Koa2) + MongoDB + Redis 等工具:Mac、Git、VsCode、prettier、Yarn 等;其余: Prerender(For SEO)、Waline(评论)、Gatsby作者简介业余独立开发者杨轩帅,目前在国内一家智能手机研发公司做快利用相干;工作内容繁冗,偏重工具型产品的思考与设计,当然也仍会写些代码;出于对高效工作的谋求,比拟热衷与发明一些好产品 / 工具;相比之下,业余时间写代码会更多一些。 独立开发者?目前仍是一名业余独立开发者。工作内外,都有很多想法,以及一些痛点;集体十分偏向将其形象进去,加以设计,用代码实现出一个工具,或是一款产品,为本人和别人都能带来价值;即使只有本人用,也感觉很酷(极客范儿)。 从另一角度答复这个问题,有必要了解下其定义;『独立开发者』,个别指的是“从产品立项、设计、开发、推广、到盈利的闭环全副独立实现的人”。也想有更多气味相投敌人,组成一个团队,汇集起来实现一款产品;但这并不容易,只能是本人身体力行,孤军奋战。 因而,目前所开拓的业余我的项目,包含倾城之链在内,波及的全副工作,都须本人去实现;在不善于的畛域,不免顾此失彼,比方 UI 设计、交互设计,经营推广、监控运维等环节。但,始终放弃学习,并踊跃实际,受益匪浅。 我的项目初衷那些年,在搭建这个人博客平台 ──「晚晴幽草轩」之时,就有粗浅的意识到:当今时代,即使是再小的个体,也当有本人的品牌;这一观点在过来很多文章中,都有竭力的去出现、鼓吹。然而,这种影响力毕竟无限,况且对于那些优质品牌,也无奈起到实质性作用。要晓得,当今时代,最重要莫过于「信息」;对信息的承载,能够说绝大部分是源于网络;而信息在网络中流传,起着相对作用的则是各类网站;故此,不难得出:对于很多品牌最佳的承载,即「专属网站」;因而,在 2016 年初,就信心本人开发一款产品,为这观点以布道,使那优良能广传;这即是「倾城之链」得诞生的动机与起源;整体而言呢,可总结为以下几点: 尝试解决大数据信息时代,高效吸取优质、有价值信息,以更好服务网民;搭建汇聚优质网站平台,并赋予其、、分享等性能,以促成个体品牌倒退;作为前端开发工程师(过后),欲借此契机,学习、磨难各项技术,晋升自我;如果您对「倾城」 想要理解更多,可参见晚期撰写的文章: 星散优站,尽在「倾城之链」星散优站,尽在「倾城之链」其二网络应用百科之 ── 倾城之链如何经营?倾城之链反对用户注册、登录,以提交举荐的网站。截至目前,从开发到经营,乃至推广,仍由「@轩帅」实现;次要负责审核举荐网站、重设「主题 & 标签」、编写举荐语、公布倾城周刊等工作(其中大部分精确性工作,比方生成周刊,通过 Node.js 或 Deno 编写脚本来实现)。遇见特地有用的产品,会通过小程序或网址推给共事或敌人。无暇,也返回 Product Hunt、阿酷导航等平台,发现更多有价值 Web 利用。 如何推广?从 2019 年开始,次要推广形式变更为:私域互链(还保护了其余几个网站)、购买 Google ADS(谷歌广告)、社区发推广帖、友情链接、SEO 优化。Google Ads 有两段工夫,因为每次点击价格问题折腾蛮多,其余的就是不定期减少投入、批改广告内容形容、以及设计并制作广告素材;关乎广告素材制作,虽留有谷歌自适应广告素材,制作心得分享一文,至今也不得其法,只能不断改进设计,而后交由 Google 机器学习去评判,不现实就撤掉从新再来。社区发帖,有在以下平台尝试: 晚晴幽草轩:星散优站,尽在「倾城之链」 2017-12-31晚晴幽草轩:星散优站,尽在「倾城之链」其二 2018-12-23链滴社区:「自荐」:集体开源 Web 利用——倾城之链 2019-10v2ex 社区:「自荐」集体开源 Web 利用:「倾城之链」 2019-12创造者日报社区:倾城之链 - 收费实用的资源网站导航 2020-04思否社区:轩帅:开启技术变现之路,摸索第三支出起源 2020-11为爱发电:致力于塑造新一代、高质量的 Web 利用(网站)导航;2021.02悠然宜想亭:倾城之链:星散寰球优良网站(举荐) 2021-03电鸭社区:「自荐」:集体开源多平台利用——「倾城之链」 2021.10线圈社区:倾城之链 | NICE LINKS 2022.09小众软件:【自荐】倾城之链:在线导航平台,专一优质网站 2022.10独立开发者社区:我的作品 倾城之链 - 优质网站导航利用 2022.10从流量角度来看,社区发帖所能带来的流量无限,不迭投放一天 Google 广告;值此市场低迷之际,继续广告投入,也非长久之计。优化 SEO,从用户所需——「搜寻行为」来夺取黄金,相比之下,是更为理智的抉择;这也是目前次要致力方向之一。 ...

November 23, 2022 · 1 min · jiezi

关于vue.js:P17-vue3子组件访问父组件和跟组件-parent-and-root

$parentApp.vue <script>import Content from "./components/Content.vue";export default { data() { return { message: '', }; }, methods:{ getChildMsg:function (value){ console.log(value); this.message=value } }, components:{ Content }}</script><template><div> <!--拿到子组件 Content 的msg数据 --> <!--在父组件通过v-on监听自定义的子组件的自定义事件 --> <Content @injectMsg="getChildMsg"> </Content> <h2>{{message}}</h2></div></template>Content.vue<template> <div> <!--组件是能够复用 --> <Hello_kugou :message="msg" static='56' :list="list" ref="hellokugou"></Hello_kugou> <!--父子组件拜访形式 ,父组件拜访子组件 $refs $children-数组类型(vue2)--> <!-- 子组件拜访父组件 $parent 尽量不必--> <!-- 子组件拜访跟组件 $root--> <p ref="p"></p> </div></template><script>import Hello_kugou from "./Hello_kugou.vue";export default { data(){//让每一个组件对象都返回一个对象,不对数据净化 return{ msg: 'hellokugoumsg', list: [1,2,3], a: 20 }; }, components:{ Hello_kugou }, methods:{ // 在子组件理 $emit 触发事件 sendParent:function (){ //this.$emit('事件名称', '发送的事件参数') this.$emit('injectMsg', this.msg) } }, mounted() { //console.log(this.$refs); }, name: "Content"}</script><style scoped></style>Hello_kugou.vue<template> <div> <h2>hello kugou</h2> <h2>{{message2}}--调用父组件的变量</h2> </div></template><script>export default { data(){ return{ a: 10, } }, name: "Hello_kugou", //props: ['message', 'static'] props:{ // message: String,//类型限度 // static: String message2:{ type:String, default:"nihhaokugou", //required:true }, }, mounted() { console.log(this.$parent.a) }}</script><style scoped></style>拿到了父组件的数据 ...

November 22, 2022 · 1 min · jiezi

关于vue.js:记录VueelementUI报错及解决方法

Invalid prop: custom validator check failed for prop "percentage" 当呈现这种Invalid prop谬误的时候,应该去查一下elementUI的文档,看一下prop的取值范畴,例如:percentage的取值范畴就是0-100之间。我在算百分比的时候,当数据更新的时候,没有即时更新分母,导致算进去的数据存在大于100的值。 Cannot read properties of undefined (reading ‘0’) 代码背景:一个很大的页面嵌套了几个component(func-arrow-table是其中之一) <func-arrow-table :comparedFunctions.sync="comparedFunctions" :performIndex="performIndex" :sessionList="sessionList" :tableData.sync="tableData" :deleteFunction="deleteFunction" :clickBarChart="clickBarChart" :isGroupData="false"></func-arrow-table>func-arrow-table的主题是一个el-table,左一列是依据prop comparedFunctions计算compute而来的,表头是依据sessionList渲染进去的,表格的数据则是tableData。这个表格里的comparedFunctions是能够依据用户须要动静增删的,也就是说,comparedFunctions和tableData须要设置为sync。然而,在理论削减数据的时候,控制台里还是会报错。和mentor钻研了一下,起因是因为,el-table须要渲染的数据没有被一把赋值,会有先后顺序,所以,存在当tableData 或者 comparedFunctions以及被传递过来的时候,另一个值还没有筹备好,因而拜访谬误。解决办法如下,将所有el-table画表所须要的数据变成一个构造体,一把传过来。 <func-arrow-table :tableDataSet="tableDataSet" :performIndex="performIndex" :sessionList="sessionList" :deleteFunction="deleteFunction" :clickBarChart="clickBarChart" :isGroupData="true"></func-arrow-table>

November 21, 2022 · 1 min · jiezi

关于vue.js:基于微前端架构的项目动态换肤方案

前言本计划对于微前端架构我的项目,针对不同业态可展现不同的主题。 示例我的项目采纳vue2.0+vant 思路:1.依据css伪类 :root配置全局变量,按照vant定制主题,在覆盖文件中取变量值进行笼罩。2.主框架通过URL携带色值作为参数传给子利用,子利用在页面加载结束后更新页面根元素定义的css变量,从而更新我的项目中所有对该变量的援用。引入款式源文件 //babel.config.jsmodule.exports = { plugins: [ [ 'import', { libraryName: 'vant', libraryDirectory: 'es', // 指定款式门路 style: (name) => `${name}/style/less`, }, 'vant', ], ],};批改款式变量 // vue.config.jsconst path = require('path')const themePath = path.join(__dirname, './src/assets/css/theme.less')module.exports = { css: { loaderOptions: { less: { // 若 less-loader 版本小于 6.0,请移除 lessOptions 这一级,间接配置选项。 lessOptions: { modifyVars: { // 间接笼罩变量 'text-color': '#111', 'border-color': '#eee', // 或者能够通过 less 文件笼罩(文件门路为绝对路径) hack: `true; @import "${themePath}";` } } } } }};APP.vue中定义全局变量默认值 ...

November 21, 2022 · 1 min · jiezi

关于vue.js:P16-vue-父子组件访问方式-refs

Hello_kugou.vue <template> <div> <!--组件是能够复用 --> <Hello_kugou :message="msg" static='56' :list="list" ref="hellokugou"></Hello_kugou> <!--父子组件拜访形式 ,父组件拜访子组件 $refs $children-数组类型(vue2)--> <!-- 子组件拜访父组件 $parent--> <!-- 子组件拜访跟组件 $root--> <p ref="p"></p> </div></template><script>import Hello_kugou from "./Hello_kugou.vue";export default { data(){//让每一个组件对象都返回一个对象,不对数据净化 return{ msg: 'hellokugoumsg', list: [1,2,3] }; }, components:{ Hello_kugou }, methods:{ // 在子组件理 $emit 触发事件 sendParent:function (){ //this.$emit('事件名称', '发送的事件参数') this.$emit('injectMsg', this.msg) } }, mounted() { console.log(this.$refs); }, name: "Content"}</script><style scoped></style>

November 21, 2022 · 1 min · jiezi

关于vue.js:P15-vue-通过自定义事件-向父组件组件传值

子组件Content向App.vue通工自定义事件传值App.vue <script>import Content from "./components/Content.vue";export default { data() { return { message: '', }; }, methods:{ getChildMsg:function (value){ console.log(value); this.message=value } }, components:{ Content }}</script><template><div> <!--拿到子组件 Content 的msg数据 --> <!--在父组件通过v-on监听自定义的子组件的自定义事件 --> <Content @injectMsg="getChildMsg"> </Content> <h2>{{message}}</h2></div></template>Content.vue<template> <div> <!--组件是能够复用 --> <Hello_kugou :message="msg" :static='56'></Hello_kugou> <h3>{{msg}}</h3> <button @click="msg='酷狗'"> chagebut</button> <button @click="sendParent">提交数据给父组件</button> </div></template><script>const obj={ msg:"hello---kugou"}import Hello_kugou from "./Hello_kugou.vue";export default { data(){//让每一个组件对象都返回一个对象,不对数据净化 return{ msg: 'hellokugoumsg', list: [1,2,3] }; }, components:{ Hello_kugou }, methods:{ // 在子组件理 $emit 触发事件 sendParent:function (){ //this.$emit('事件名称', '发送的事件参数') this.$emit('injectMsg', this.msg) } }, name: "Content"}</script><style scoped></style>Hello_kugou.vue<template> <div> <h2>hello kugou</h2> <h2>{{message2}}--调用父组件的变量</h2> </div></template><script>export default { name: "Hello_kugou", //props: ['message', 'static'] props:{ // message: String,//类型限度 // static: String message2:{ type:String, default:"nihhaokugou", //required:true }, }}</script><style scoped></style> ...

November 19, 2022 · 1 min · jiezi

关于vue.js:P14-vue3-向子组件传值-Prop

从父组件Content向子组件Hello_kugou传递数据App.vue<script> import Content from "./components/Content.vue"; export default { data() { return { }; }, components:{ Content } }</script><template> <div> <Content></Content> </div></template>Content.vue<template> <div> <!--组件是能够复用 --> <Hello_kugou :message="msg" static="123"></Hello_kugou> <h3>{{msg}}</h3> <button @click="msg='酷狗'"> chagebut</button> </div></template><script>const obj={ msg:"hello---kugou"}import Hello_kugou from "./Hello_kugou.vue";export default { data(){//让每一个组件对象都返回一个对象,不对数据净化 return{ msg: 'hellokugoumsg' }; }, components:{ Hello_kugou }, name: "Content"}</script><style scoped></style>Hello_kugou.vue<template> <div> <h2>hello kugou</h2> <h2>{{message}}--调用父组件的变量</h2> <h2>{{static}}--调用父组件的动态变量</h2> </div></template><script>export default { name: "Hello_kugou", props: ['message', 'static']}</script><style scoped></style> 动态变量 Prop 类型到这里,咱们只看到了以字符串数组模式列出的 prop: props: ['title', 'likes', 'isPublished', 'commentIds', 'author']然而,通常你心愿每个 prop 都有指定的值类型。这时,你能够以对象模式列出 prop,这些 property 的名称和值别离是 prop 各自的名称和类型: ...

November 18, 2022 · 2 min · jiezi

关于vue.js:个人记录vue2与3生命周期的改变

vue2中的生命周期创立前 beforecreate此时处于vue实例创立之前,数据和办法都生成创立后 created此处vue实例创立实现,能够获取到data和methods此时dom还没渲染,个别申请放入这里进行数据的申请挂载前 beforemount此处曾经编译好了模板然而没有挂载到页面上,仅仅存在内存中挂载后 mounted此时模板曾经实现挂载,能够进行dom操作批改前 beforeupdate在数据批改之前进行调用,此时data中数据曾经批改实现,但dom中为进行更新批改后 updated页面dom中数据也进行更新实现登记前 beforedistory在组件卸载之前进行调用,个别用于用户确认敞开登记后 distoryed卸载之后,此时组件卸载,无奈获取到data和methodskeep-alive缓存组件中有2个生命周期函数缓存后进入组件前activted缓存后来到组件后deactivted vue3中的生命周期根本与vue2中大体一致beforeDestroy,distoryed改成beforeunmount,unmounted成果统一在组合式中应用setup写入因为setup是围绕beforecreate和created运行的所以不须要显示的定义他们用on结尾进行援用新增生命周期onRenderTracted 在页面渲染或从新渲染的时候都会触发,首次渲染页面和从新渲染页面都会触发onRenderTrggiend 只有在页面从新渲染的时候才会触发,此时onRenderTracted也会进行触发

November 18, 2022 · 1 min · jiezi

关于vue.js:P13-组件-数据

数据必须是对象App.vue<script> import Content from "./components/Content.vue"; export default { data() { return { }; }, components:{ Content } }</script><template> <div> <Content></Content> <Content></Content> <Content></Content> </div></template>Content.vue<template> <div> <!--组件是能够复用 --> <Hello_kugou></Hello_kugou> <h2> content hello </h2> <h3>{{msg}}</h3> <button @click="msg='酷狗'"> chagebut</button> <Hello_kugou></Hello_kugou> </div></template><script>import Hello_kugou from "./Hello_kugou.vue";export default { data(){ return{ msg: 'hellokugoumsg' }; }, components:{ Hello_kugou }, name: "Content"}</script><style scoped></style>Hello_kugou.vue<template> <div> <h2>hello kugou</h2> </div></template><script>export default { name: "Hello_kugou"}</script><style scoped></style>

November 18, 2022 · 1 min · jiezi

关于vue.js:前端常见vue面试题合集

Vue3有理解过吗?能说说跟vue2的区别吗?1. 哪些变动 从上图中,咱们能够概览Vue3的新个性,如下: 速度更快体积缩小更易保护更靠近原生更易使用1.1 速度更快 vue3相比vue2 重写了虚构Dom实现编译模板的优化更高效的组件初始化undate性能进步1.3~2倍SSR速度进步了2~3倍 1.2 体积更小 通过webpack的tree-shaking性能,能够将无用模块“剪辑”,仅打包须要的 可能tree-shaking,有两大益处: 对开发人员,可能对vue实现更多其余的性能,而不用担心整体体积过大对使用者,打包进去的包体积变小了vue能够开发出更多其余的性能,而不用担心vue打包进去的整体体积过多 1.3 更易保护 compositon Api 可与现有的Options API一起应用灵便的逻辑组合与复用Vue3模块能够和其余框架搭配应用 更好的Typescript反对 VUE3是基于typescipt编写的,能够享受到主动的类型定义提醒 1.4 编译器重写 1.5 更靠近原生 能够自定义渲染 API 1.6 更易使用 响应式 Api 裸露进去 轻松辨认组件从新渲染起因 2. Vue3新增个性 Vue 3 中须要关注的一些新性能包含: framentsTeleportcomposition ApicreateRenderer2.1 framents 在 Vue3.x 中,组件当初反对有多个根节点 <!-- Layout.vue --><template> <header>...</header> <main v-bind="$attrs">...</main> <footer>...</footer></template>2.2 Teleport Teleport 是一种可能将咱们的模板挪动到 DOM 中 Vue app 之外的其余地位的技术,就有点像哆啦A梦的“任意门” 在vue2中,像 modals,toast 等这样的元素,如果咱们嵌套在 Vue 的某个组件外部,那么解决嵌套组件的定位、z-index 和款式就会变得很艰难 ...

November 9, 2022 · 18 min · jiezi

关于vue.js:每日一题之Vue数据劫持原理是什么

什么是数据劫持?定义: 数据劫持,指的是在拜访或者批改对象的某个属性时,通过一段代码拦挡这个行为,进行额定的操作或者批改返回后果。 简略地说,就是当咱们 触发函数的时候 动一些手脚做点咱们本人想做的事件,也就是所谓的 "劫持"操作 数据劫持的两种计划:Object.definePropertyProxy1).Object.defineProperty语法:Object.defineProperty(obj,prop,descriptor) 参数: obj:指标对象prop:须要定义的属性或办法的名称descriptor:指标属性所领有的个性可供定义的个性列表: value:属性的值writable:如果为false,属性的值就不能被重写。get: 一旦指标属性被拜访就会调回此办法,并将此办法的运算后果返回用户。set:一旦指标属性被赋值,就会调回此办法。configurable:如果为false,则任何尝试删除指标属性或批改属性性以下个性(writable, configurable, enumerable)的行为将被有效化。enumerable:是否能在for...in循环中遍历进去或在Object.keys中列举进去。例子在Vue中其实就是通过Object.defineProperty来劫持对象属性的setter和getter操作,并“种下”一个监听器,当数据发生变化的时候发出通知,如下: var data = {name:'test'}Object.keys(data).forEach(function(key){ Object.defineProperty(data,key,{ enumerable:true, configurable:true, get:function(){ console.log('get'); }, set:function(){ console.log('监听到数据产生了变动'); } })});data.name //控制台会打印出 “get”data.name = 'hxx' //控制台会打印出 "监听到数据产生了变动"下面的这个例子能够看出,咱们齐全能够管制对象属性的设置和读取。在Vue中,在很多中央都十分奇妙的使用了Object.defineProperty这个办法,具体用在哪里并且它又解决了哪些问题,上面就简略的说一下: 监听对象属性的变动它通过observe每个对象的属性,增加到订阅器dep中,当数据发生变化的时候收回一个notice。 相干源代码如下:(作者采纳的是ES6+flow写的,代码在src/core/observer/index.js模块外面) export function defineReactive ( obj: Object, key: string, val: any, customSetter?: Function) { const dep = new Dep()//创立订阅对象 const property = Object.getOwnPropertyDe述 //属性的形容个性外面如果configurable为false则属性的任何批改将有效 if (property && property.configurable === false) { return }scriptor(obj, key)//获取obj对象的key属性的描 // cater for pre-defined getter/setters const getter = property && property.get const setter = property && property.set let childOb = observe(val)//创立一个观察者对象 Object.defineProperty(obj, key, { enumerable: true,//可枚举 configurable: true,//可批改 get: function reactiveGetter () { const value = getter ? getter.call(obj) : val//先调用默认的get办法取值 //这里就劫持了get办法,也是作者一个奇妙设计,在创立watcher实例的时候,通过调用对象的get办法往订阅器dep上增加这个创立的watcher实例 if (Dep.target) { dep.depend() if (childOb) { childOb.dep.depend() } if (Array.isArray(value)) { dependArray(value) } } return value//返回属性值 }, set: function reactiveSetter (newVal) { const value = getter ? getter.call(obj) : val//先取旧值 if (newVal === value) { return } //这个是用来判断生产环境的,能够忽视 if (process.env.NODE_ENV !== 'production' && customSetter) { customSetter() } if (setter) { setter.call(obj, newVal) } else { val = newVal } childOb = observe(newVal)//持续监听新的属性值 dep.notify()//这个是真正劫持的目标,要对订阅者发告诉了 } })}参考 前端vue面试题具体解答 ...

November 9, 2022 · 4 min · jiezi

关于vue.js:什么样的vue面试题答案才是面试官满意的

Vue组件渲染和更新过程渲染组件时,会通过 Vue.extend 办法构建子组件的构造函数,并进行实例化。最终手动调用$mount() 进行挂载。更新组件时会进行 patchVnode 流程,外围就是diff算法 如何在组件中批量应用Vuex的getter属性应用mapGetters辅助函数, 利用对象开展运算符将getter混入computed 对象中 import {mapGetters} from 'vuex'export default{ computed:{ ...mapGetters(['total','discountTotal']) }}个别在哪个生命周期申请异步数据咱们能够在钩子函数 created、beforeMount、mounted 中进行调用,因为在这三个钩子函数中,data 曾经创立,能够将服务端端返回的数据进行赋值。 举荐在 created 钩子函数中调用异步申请,因为在 created 钩子函数中调用异步申请有以下长处: 能更快获取到服务端数据,缩小页面加载工夫,用户体验更好;SSR不反对 beforeMount 、mounted 钩子函数,放在 created 中有助于一致性。action 与 mutation 的区别 mutation 是同步更新, $watch 严格模式下会报错 action 是异步操作,能够获取数据后调用 mutation 提交最终数据参考:前端vue面试题具体解答 Vue data 中某一个属性的值产生扭转后,视图会立刻同步执行从新渲染吗?不会立刻同步执行从新渲染。Vue 实现响应式并不是数据发生变化之后 DOM 立刻变动,而是按肯定的策略进行 DOM 的更新。Vue 在更新 DOM 时是异步执行的。只有侦听到数据变动, Vue 将开启一个队列,并缓冲在同一事件循环中产生的所有数据变更。 如果同一个watcher被屡次触发,只会被推入到队列中一次。这种在缓冲时去除反复数据对于防止不必要的计算和 DOM 操作是十分重要的。而后,在下一个的事件循环tick中,Vue 刷新队列并执行理论(已去重的)工作。 SPA首屏加载速度慢的怎么解决一、什么是首屏加载首屏工夫(First Contentful Paint),指的是浏览器从响应用户输出网址地址,到首屏内容渲染实现的工夫,此时整个网页不肯定要全副渲染实现,但须要展现以后视窗须要的内容 首屏加载能够说是用户体验中最重要的环节 对于计算首屏工夫 利用performance.timing提供的数据: 通过DOMContentLoad或者performance来计算出首屏工夫 // 计划一:document.addEventListener('DOMContentLoaded', (event) => { console.log('first contentful painting');});// 计划二:performance.getEntriesByName("first-contentful-paint")[0].startTime// performance.getEntriesByName("first-contentful-paint")[0]// 会返回一个 PerformancePaintTiming的实例,构造如下:{ name: "first-contentful-paint", entryType: "paint", startTime: 507.80000002123415, duration: 0,};二、加载慢的起因在页面渲染的过程,导致加载速度慢的因素可能如下: ...

November 9, 2022 · 5 min · jiezi

关于vue.js:每日一题之Vue的异步更新实现原理是怎样的

最近面试总是会被问到这么一个问题:在应用vue的时候,将for循环中申明的变量i从1减少到100,而后将i展现到页面上,页面上的i是从1跳到100,还是会怎么?答案当然是只会显示100,并不会有跳转的过程。 怎么能够让页面上有从1到100显示的过程呢,就是用setTimeout或者Promise.then等办法去模仿。 讲道理,如果不在vue里,独自运行这段程序的话,输入肯定是从1到100,然而为什么在vue中就不一样了呢? for(let i=1; i<=100; i++){ console.log(i);}这就波及到Vue底层的异步更新原理,也要说一说nextTick的实现。不过在说nextTick之前,有必要先介绍一下JS的事件运行机制。 JS运行机制家喻户晓,JS是基于事件循环的单线程的语言。执行的步骤大抵是: 当代码执行时,所有同步的工作都在主线程上执行,造成一个执行栈;在主线程之外还有一个工作队列(task queue),只有异步工作有了运行后果就在工作队列中搁置一个事件;一旦执行栈中所有同步工作执行结束(主线程代码执行结束),此时主线程不会闲暇而是去读取工作队列。此时,异步的工作就完结期待的状态被执行。主线程一直反复以上的步骤。 咱们把主线程执行一次的过程叫一个tick,所以nextTick就是下一个tick的意思,也就是说用nextTick的场景就是咱们想在下一个tick做一些事的时候。所有的异步工作后果都是通过工作队列来调度的。而工作分为两类:宏工作(macro task)和微工作(micro task)。它们之间的执行规定就是每个宏工作完结后都要将所有微工作清空。常见的宏工作有setTimeout/MessageChannel/postMessage/setImmediate,微工作有MutationObsever/Promise.then。 nextTick原理派发更新大家都晓得vue的响应式的靠依赖收集和派发更新来实现的。在批改数据之后的派发更新过程,会触发setter的逻辑,执行dep.notify(): // src/core/observer/watcher.jsclass Dep { notify() { //subs是Watcher的实例数组 const subs = this.subs.slice() for(let i=0, l=subs.length; i<l; i++){ subs[i].update() } }}遍历subs里每一个Watcher实例,而后调用实例的update办法,上面咱们来看看update是怎么去更新的: class Watcher { update() { ... //各种状况判断之后 else{ queueWatcher(this) } }}参考 前端vue面试题具体解答 update执行后又走到了queueWatcher,那就持续去看看queueWatcher干啥了(心愿不要持续套娃了: //queueWatcher 定义在 src/core/observer/scheduler.jsconst queue: Array<Watcher> = []let has: { [key: number]: ?true } = {}let waiting = falselet flushing = falselet index = 0export function queueWatcher(watcher: Watcher) { const id = watcher.id //依据id是否反复做优化 if(has[id] == null){ has[id] = true if(!flushing){ queue.push(watcher) }else{ let i=queue.length - 1 while(i > index && queue[i].id > watcher.id){ i-- } queue.splice(i + 1, 0, watcher) } if(!waiting){ waiting = true //flushSchedulerQueue函数: Flush both queues and run the watchers nextTick(flushSchedulerQueue) } }}这里queue在pushwatcher时是依据id和flushing做了一些优化的,并不会每次数据扭转都触发watcher的回调,而是把这些watcher先增加到⼀个队列⾥,而后在nextTick后执⾏flushSchedulerQueue。 ...

November 9, 2022 · 2 min · jiezi

关于vue.js:Vue中的diff算法深度解析

模板tamplate通过parse,optimize,generate等一些列操作之后,把AST转为render function code进而生成虚构VNode,模板编译阶段根本曾经实现了,那么这一章,咱们来探讨一下Vue中的一个算法策略--dom diff 首先来介绍下什么叫dom diff 什么是虚构dom咱们通过后面的章节学习曾经晓得,要晓得渲染实在DOM的开销是很大的,比方有时候咱们批改了某个数据,如果间接渲染到实在dom上会引起整个dom树的重绘和重排,有没有可能咱们只更新咱们批改的那一小块dom而不要更新整个dom呢? 为了解决这个问题,咱们的解决方案是--依据实在DOM生成一颗virtual DOM,当virtual DOM某个节点的数据扭转后会生成一个新的Vnode,而后Vnode和oldVnode作比照,发现有不一样的中央就间接批改在实在的DOM上,而后使oldVnode的值为Vnode。这也就是咱们所说的一个虚构dom diff的过程 图示 传统的Diff算法所消耗的工夫复杂度为O(n^3),那么这个O(n^3)是怎么算进去的? 传统diff算法工夫复杂度为n(第一次Old与新的所有节点比照)----O(n)传统diff算法工夫复杂度为n(第二次Old树的所有节点与新的所有节点比照)----O(n^2)新树的生成,节点可变编辑,工夫复杂度为n(遍历以后树)----O(n^3)第一次比照 (1:n) 第二次比照 (1:n) 第n次比照 (n:n) 到这里那么n个节点与n个节点暴力比照就比照完了,那么就开启第三轮可编辑树节点遍历,更改之后的树由vdom(old)到vdom(new) 故而传统diff算法O(n^3)是这么算进去的,然而这不是咱们明天钻研的重点。 古代diff算法古代diff算法策略说的是,同层级比拟,广度优先 那么这里的话咱们要深刻源码了,在深刻源码之前咱们在心中应该造成这样一个概念,整个diff的流程是什么?咱们再比照着源码解读 diff算法流程图 深刻源码咱们在Vue初始化的时候调用lifecycleMixin函数的时候,会给Vue的原型上挂载_update办法 _updateVue.prototype._update = function (vnode: VNode, hydrating?: boolean) { const vm: Component = this if (vm._isMounted) { //会调用申明周期中的beforeUpdate回调函数 callHook(vm, 'beforeUpdate') } const prevEl = vm.$el const prevVnode = vm._vnode const prevActiveInstance = activeInstance activeInstance = vm vm._vnode = vnode // Vue.prototype.__patch__ is injected in entry points // based on the rendering backend used. //若组件自身的vnode未生成,间接用传入的vnode生成dom if (!prevVnode) { // initial render vm.$el = vm.__patch__( vm.$el, vnode, hydrating, false /* removeOnly */, vm.$options._parentElm, vm.$options._refElm ) // no need for the ref nodes after initial patch // this prevents keeping a detached DOM tree in memory (#5851) vm.$options._parentElm = vm.$options._refElm = null } else { //对新旧vnode进行diff // updates vm.$el = vm.__patch__(prevVnode, vnode) } activeInstance = prevActiveInstance // update __vue__ reference if (prevEl) { prevEl.__vue__ = null } if (vm.$el) { vm.$el.__vue__ = vm } // if parent is an HOC, update its $el as well if (vm.$vnode && vm.$parent && vm.$vnode === vm.$parent._vnode) { vm.$parent.$el = vm.$el }咱们在这里能够看到vm.$el = vm.__patch__办法,追根溯源_patch_的定义: ...

November 8, 2022 · 22 min · jiezi

关于vue.js:Vue响应式依赖收集原理分析vue高级必备

背景在 Vue 的初始化阶段,_init 办法执行的时候,会执行 initState(vm) ,它的定义在 src/core/instance/state.js 中。在初始化 data 和 props option 时咱们留神 initProps 和 initData 办法中都调用了 observe 办法。通过 observe (value),就能够将数据变成响应式。 export function initState (vm: Component) { vm._watchers = [] const opts = vm.$options if (opts.props) initProps(vm, opts.props) if (opts.methods) initMethods(vm, opts.methods) if (opts.data) { initData(vm) } else { observe(vm._data = {}, true /* asRootData */) } if (opts.computed) initComputed(vm, opts.computed) if (opts.watch && opts.watch !== nativeWatch) { initWatch(vm, opts.watch) }}initProps ...

November 8, 2022 · 9 min · jiezi

关于vue.js:Vue响应式系统原理并实现一个双向绑定

这一章就着重讲两个点: 响应式零碎如何收集依赖响应式零碎如何更新视图 咱们晓得通过Object.defineProperty做了数据劫持,当数据扭转的时候,get办法收集依赖,进而set办法调用dep.notify办法去告诉Watcher调用自身update办法去更新视图。那么咱们抛开其余问题,就探讨get,notify,update等办法,间接上代码:get( ) get: function reactiveGetter () { const value = getter ? getter.call(obj) : val if (Dep.target) { dep.depend() if (childOb) { childOb.dep.depend() if (Array.isArray(value)) { dependArray(value) } } } return value }咱们晓得Dep.target在创立Watcher的时候是null,并且它只是起到一个标记的作用,当咱们创立Watcher实例的时候,咱们的Dep.target就会被赋值到Watcher实例,进而放入target栈中,咱们这里调用的是pushTarget函数: // 将watcher实例赋值给Dep.target,用于依赖收集。同时将该实例存入target栈中export function pushTarget (_target: ?Watcher) { if (Dep.target) targetStack.push(Dep.target) Dep.target = _target}那咱们继续执行到if (Dep.target)语句的时候就会调用Dep.depend函数: // 将本身退出到全局的watcher中 depend () { if (Dep.target) { Dep.target.addDep(this) } }那上面的childOb是啥货色呢? let childOb = !shallow && observe(val)咱们通过这个变量判断以后属性上面是否还有ob属性,如果有的话持续调用Dep.depend函数,没有的话则不解决。咱们还须要解决以后传入的value类型,是数组属性的话则会调用dependArray收集数组依赖 ...

November 8, 2022 · 4 min · jiezi

关于vue.js:前端一面经典vue面试题总结

个别在哪个生命周期申请异步数据咱们能够在钩子函数 created、beforeMount、mounted 中进行调用,因为在这三个钩子函数中,data 曾经创立,能够将服务端端返回的数据进行赋值。 举荐在 created 钩子函数中调用异步申请,因为在 created 钩子函数中调用异步申请有以下长处: 能更快获取到服务端数据,缩小页面加载工夫,用户体验更好;SSR不反对 beforeMount 、mounted 钩子函数,放在 created 中有助于一致性。computed 和 watch 的区别和使用的场景?computed: 是计算属性,依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值产生扭转,下一次获取 computed 的值时才会从新计算 computed 的值; watch: 更多的是「察看」的作用,相似于某些数据的监听回调 ,每当监听的数据变动时都会执行回调进行后续操作; 使用场景: 当咱们须要进行数值计算,并且依赖于其它数据时,应该应用 computed,因为能够利用 computed 的缓存个性,防止每次获取值时,都要从新计算;当咱们须要在数据变动时执行异步或开销较大的操作时,应该应用 watch,应用 watch 选项容许咱们执行异步操作 ( 拜访一个 API ),限度咱们执行该操作的频率,并在咱们失去最终后果前,设置中间状态。这些都是计算属性无奈做到的。Vue中组件生命周期调用程序说一下组件的调用程序都是先父后子,渲染实现的程序是先子后父。 组件的销毁操作是先父后子,销毁实现的程序是先子后父。 加载渲染过程 父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount- >子mounted->父mounted子组件更新过程 父beforeUpdate->子beforeUpdate->子updated->父updated父组件更新过程 父 beforeUpdate -> 父 updated销毁过程 父beforeDestroy->子beforeDestroy->子destroyed->父destroyeddefineProperty和proxy的区别Vue 在实例初始化时遍历 data 中的所有属性,并应用 Object.defineProperty 把这些属性全副转为 getter/setter。这样当追踪数据发生变化时,setter 会被主动调用。 Object.defineProperty 是 ES5 中一个无奈 shim 的个性,这也就是 Vue 不反对 IE8 以及更低版本浏览器的起因。 然而这样做有以下问题: ...

November 8, 2022 · 4 min · jiezi

关于vue.js:在vue的vfor中key为什么不能用index

写在后面在前端中,次要波及的基本上就是 DOM的相干操作 和 JS,咱们都晓得 DOM 操作是比拟耗时的,那么在咱们写前端相干代码的时候,如何缩小不必要的 DOM 操作便成了前端优化的重要内容。 虚构DOM(virtual DOM)在 jQuery 时代,基本上所有的 DOM 相干的操作都是由咱们本人编写(当然博主是没有写过 jQuery 滴,可能因为博主太年老了吧,错过了 jQuery 大法的时代),如何操作 DOM, 操作 DOM 的机会应该如何安顿成了决定性能的要害,而到了 Vue、React 这些框架流行的时代,框架采纳数据驱动视图,封装了大量的 DOM 操作细节,使得更多的 DOM 操作细节的优化从开发者本人抉择、管制转移到了框架外部,那么在学会应用框架后,如果想要更加深刻学习框架,那就须要搞懂框架封装的底层原理,其中十分外围的一部分就是虚构DOM(virtual DOM) 什么是虚构 DOM简而言之,就是通过 JS 来模仿 DOM 构造,对于纠结以什么 JS 数据结构来模仿 DOM 并没有一套规范,只有能齐全笼罩 DOM 的所有构造即可,上面以较为通用的形式演示一下。 通过对 DOM 构造的剖析,咱们能够用 tag 示意 DOM 节点的类型,props 示意 DOM 节点的所有属性,包含 style、class 等,children 示意子节点(没有子节点则示意内容),这样子咱们就把整个 DOM 通过 JS 模仿进去了,而后呢? 而后看看下一章~~~ // DOM<div class="container"> <h1 style="color: black;" class="title">HeiHei~~</h1> <div class="inner-box"> <span class="myname">I am Yimwu</span> </div></div>// VDOMlet vdom = { tag: 'div', props: { classname: 'container', }, children: [ { tag: 'h1', props: { classname: 'title', style: { color: 'black' } }, children: 'HeiHei~~' }, { tag: 'div', props: { classname: 'inner-box', }, children: [ { tag: 'span', props: { classname: 'myname' }, children: 'I am Yimwu' } ] } ]}虚构 DOM 的作用当咱们可能在 JS 中模拟出 DOM 构造后,咱们就能够通过 JS 来对 DOM 操作进行优化了,怎么优化呢,这个时候 diff 算法就该退场了。当咱们通过 JS 对 DOM 进行批改后,并不会间接触发 DOM 更新,而是会学生成一个新的虚构 DOM,而后利用 diff 算法与批改前生成的虚构 DOM 进行比拟,找出须要批改的点,最初进行真正的 DOM 更新操作 ...

November 8, 2022 · 2 min · jiezi

关于vue.js:vue源码中的渲染过程是怎样的

4.1 Virtual DOM4.1.1 浏览器的渲染流程当浏览器接管到一个Html文件时,JS引擎和浏览器的渲染引擎便开始工作了。从渲染引擎的角度,它首先会将html文件解析成一个DOM树,与此同时,浏览器将辨认并加载CSS款式,并和DOM树一起合并为一个渲染树。有了渲染树后,渲染引擎将计算所有元素的地位信息,最初通过绘制,在屏幕上打印最终的内容。JS引擎和渲染引擎尽管是两个独立的线程,然而JS引擎却能够触发渲染引擎工作,当咱们通过脚本去批改元素地位或外观时,JS引擎会利用DOM相干的API办法去操作DOM对象,此时渲染引擎变开始工作,渲染引擎会触发回流或者重绘。上面是回流重绘的两个概念: 回流: 当咱们对DOM的批改引发了元素尺寸的变动时,浏览器须要从新计算元素的大小和地位,最初将从新计算的后果绘制进去,这个过程称为回流。重绘: 当咱们对DOM的批改只单纯扭转元素的色彩时,浏览器此时并不需要从新计算元素的大小和地位,而只有从新绘制新款式。这个过程称为重绘。很显然回流比重绘更加消耗性能。 通过理解浏览器根本的渲染机制,咱们很容易联想到当一直的通过JS批改DOM时,不经意间会触发到渲染引擎的回流或者重绘,这个性能开销是十分微小的。因而为了升高开销,咱们须要做的是尽可能减少DOM操作。有什么办法能够做到呢? 4.1.2 缓冲层-虚构DOM虚构DOM是为了解决频繁操作DOM引发性能问题的产物。虚构DOM(上面称为Virtual DOM)是将页面的状态形象为JS对象的模式,实质上是JS和实在DOM的中间层,当咱们想用JS脚本大批量进行DOM操作时,会优先作用于Virtual DOM这个JS对象,最初通过比照将要改变的局部告诉并更新到实在的DOM。只管最终还是操作实在的DOM,但Virtual DOM能够将多个改变合并成一个批量的操作,从而缩小 DOM 重排的次数,进而缩短了生成渲染树和绘制所花的工夫。 咱们看一个实在的DOM蕴含了什么: 浏览器将一个实在DOM设计得很简单,不仅蕴含了本身的属性形容,大小地位等定义,也囊括了DOM领有的浏览器事件等。正因为如此简单的构造,咱们频繁去操作DOM或多或少会带来浏览器的性能问题。而作为数据和实在DOM之间的一层缓冲,Virtual DOM 只是用来映射到实在DOM的渲染,因而不须要蕴含操作 DOM 的办法,它只有在对象中重点关注几个属性即可。 // 实在DOM<div id="real"><span>dom</span></div>// 实在DOM对应的JS对象{ tag: 'div', data: { id: 'real' }, children: [{ tag: 'span', children: 'dom' }]}4.2 VnodeVue在渲染机制的优化上,同样引进了virtual dom的概念,它是用Vnode这个构造函数去形容一个DOM节点。 4.2.1 Vnode构造函数var VNode = function VNode (tag,data,children,text,elm,context,componentOptions,asyncFactory) { this.tag = tag; // 标签 this.data = data; // 数据 this.children = children; // 子节点 this.text = text; ··· ··· };Vnode定义的属性差不多有20几个,显然用Vnode对象要比实在DOM对象形容的内容要简略得多,它只用来单纯形容节点的要害属性,例如标签名,数据,子节点等。并没有保留跟浏览器相干的DOM办法。除此之外,Vnode也会有其余的属性用来扩大Vue的灵活性。 ...

November 8, 2022 · 4 min · jiezi

关于vue.js:vue源码分析diff算法核心原理

这一节,仍然是深刻分析Vue源码系列,上几节内容介绍了Virtual DOM是Vue在渲染机制上做的优化,而渲染的外围在于数据变动时,如何高效的更新节点,这就是diff算法。因为源码中对于diff算法局部流程简单,间接分析每个流程不易于了解,所以这一节咱们换一个思路,参考源码来手动实现一个简易版的diff算法。之前讲到Vue在渲染机制的优化上,引入了Virtual DOM的概念,利用Virtual DOM形容一个实在的DOM,实质上是在JS和实在DOM之间架起了一层缓冲层。当咱们通过大量的JS运算,并将最终后果反馈到浏览器进行渲染时,Virtual DOM能够将多个改变合并成一个批量的操作,从而缩小 dom 重排的次数,进而缩短了生成渲染树和绘制节点所花的工夫,达到渲染优化的目标。之前的章节,咱们简略的介绍了Vue中Vnode的概念,以及创立Vnode到渲染Vnode再到实在DOM的过程。如果有遗记流程的,能够参考后面的章节剖析。 从render函数到创立虚构DOM,再到渲染实在节点,这一过程是残缺的,也是容易了解的。然而引入虚构DOM的外围不在这里,而在于当数据发生变化时,如何最优化数据变动到视图更新的过程。这一个过程才是Vnode更新视图的外围,也就是常说的diff算法。上面跟着我来实现一个简易版的diff算法 8.1 创立根底类代码编写过程会遇到很多根本类型的判断,第一步须要先将这些办法封装。 class Util { constructor() {} // 检测根底类型 _isPrimitive(value) { return (typeof value === 'string' || typeof value === 'number' || typeof value === 'symbol' || typeof value === 'boolean') } // 判断值不为空 _isDef(v) { return v !== undefined && v !== null }}// 工具类的应用const util = new Util()8.2 创立VnodeVnode这个类在之前章节曾经剖析过源码,实质上是用一个对象去形容一个实在的DOM元素,简易版关注点在于元素的tag标签,元素的属性汇合data,元素的子节点children,text为元素的文本节点,简略的形容类如下: class VNode { constructor(tag, data, children) { this.tag = tag; this.data = data; this.children = children; this.elm = '' // text属性用于标记Vnode节点没有其余子节点,只有纯文本 this.text = util._isPrimitive(this.children) ? this.children : '' }}8.3 模仿渲染过程接下来须要创立另一个类模仿将render函数转换为Vnode,并将Vnode渲染为实在DOM的过程,咱们将这个类定义为Vn,Vn具备两个根本的办法createVnode, createElement, 别离实现创立虚构Vnode,和创立实在DOM的过程。 ...

November 8, 2022 · 4 min · jiezi

关于vue.js:vue源码分析vmodel的本质

双向数据绑定这个概念或者大家并不生疏,视图影响数据,数据同样影响视图,两者间有双向依赖的关系。在响应式零碎构建的上,中,下篇我曾经对数据影响视图的原理具体论述分明了。而如何实现视图影响数据这一关联?这就是本节探讨的重点:指令v-model。因为v-model和后面介绍的插槽,事件统一,都属于vue提供的指令,所以咱们对v-model的剖析形式和以往大同小异。剖析会围绕模板的编译,render函数的生成,到最初实在节点的挂载程序执行。最终咱们仍然会失去一个论断,v-model无论什么应用场景,实质上都是一个语法糖。 11.1 表单绑定11.1.1 根底应用v-model和表单脱离不了关系,之所以视图能影响数据,实质上这个视图须要可交互的,因而表单是实现这一交互的前提。表单的应用以<input > <textarea> <select>为外围,更细的划分联合v-model的应用如下: // 一般输入框<input type="text" v-model="value1">// 多行文本框<textarea v-model="value2" cols="30" rows="10"></textarea>// 单选框<div class="group"> <input type="radio" value="one" v-model="value3"> one <input type="radio" value="two" v-model="value3"> two</div> // 原生单选框的写法 注:原生单选框的写法须要通过name绑定一组单选,两个radio的name属性雷同,能力体现为互斥<div class="group"> <input type="radio" name="number" value="one">one <input type="radio" name="number" value="two">two</div>// 多选框 (原始值: value4: [])<div class="group"> <input type="checkbox" value="jack" v-model="value4">jack <input type="checkbox" value="lili" v-model="value4">lili</div>// 下拉选项<select name="" id="" v-model="value5"> <option value="apple">apple</option> <option value="banana">banana</option> <option value="bear">bear</option></select>接下来的剖析,咱们以一般输入框为例 <div id="app"> <input type="text" v-model="value1"></div>new Vue({ el: '#app', data() { return { value1: '' } }})进入注释前先回顾一下模板到实在节点的过程。 模板解析成AST树;AST树生成可执行的render函数;render函数转换为Vnode对象;依据Vnode对象生成实在的Dom节点。接下来,咱们先看看模板解析为AST树的过程。 11.1.2 AST树的解析模板的编译阶段,会调用var ast = parse(template.trim(), options)生成AST树,parse函数的其余细节这里不开展剖析,后面的文章或多或少都波及过,咱们还是把关注点放在模板属性上的解析,也就是processAttrs函数上。 应用过vue写模板的都晓得,vue模板属性由两局部组成,一部分是指令,另一部分是一般html标签属性。z这也是属性解决的两大分支。而在指令的细分畛域,又将v-on,v-bind做非凡的解决,其余的一般分支会执行addDirective过程。 // 解决模板属性function processAttrs(el) { var list = el.attrsList; var i, l, name, rawName, value, modifiers, syncGen, isDynamic; for (i = 0, l = list.length; i < l; i++) { name = rawName = list[i].name; // v-on:click value = list[i].value; // doThis if (dirRE.test(name)) { // 1.针对指令的属性解决 ··· if (bindRE.test(name)) { // v-bind分支 ··· } else if(onRE.test(name)) { // v-on分支 ··· } else { // 除了v-bind,v-on之外的一般指令 ··· // 一般指令会在AST树上增加directives属性 addDirective(el, name, rawName, value, arg, isDynamic, modifiers, list[i]); if (name === 'model') { checkForAliasModel(el, value); } } } else { // 2. 一般html标签属性 } }}在深刻分析Vue源码 - 揭秘Vue的事件机制这一节,咱们介绍了AST产生阶段对事件指令v-on的解决是为AST树增加events属性。相似的,一般指令会在AST树上增加directives属性,具体看addDirective函数。 ...

November 8, 2022 · 7 min · jiezi

关于vue.js:一个合格的vue工程师必会的20道面试题

params和query的区别用法:query要用path来引入,params要用name来引入,接管参数都是相似的,别离是 this.$route.query.name 和 this.$route.params.name 。 url地址显示:query更加相似于ajax中get传参,params则相似于post,说的再简略一点,前者在浏览器地址栏中显示参数,后者则不显示 留神:query刷新不会失落query外面的数据 params刷新会失落 params外面的数据。 为什么Vue采纳异步渲染呢?Vue 是组件级更新,如果不采纳异步更新,那么每次更新数据都会对以后组件进行从新渲染,所以为了性能, Vue 会在本轮数据更新后,在异步更新视图。核心思想 nextTick 。 dep.notify() 告诉 watcher进行更新, subs[i].update 顺次调用 watcher 的 update , queueWatcher 将watcher 去重放入队列, nextTick( flushSchedulerQueue )在下一tick中刷新watcher队列(异步)。 Vue的生命周期办法有哪些Vue 实例有一个残缺的生命周期,也就是从开始创立、初始化数据、编译模版、挂载Dom -> 渲染、更新 -> 渲染、卸载等一系列过程,咱们称这是Vue的生命周期Vue生命周期总共分为8个阶段创立前/后,载入前/后,更新前/后,销毁前/后beforeCreate => created => beforeMount => Mounted => beforeUpdate => updated => beforeDestroy => destroyed。keep-alive下:activated deactivated生命周期vue2生命周期vue3形容beforeCreatebeforeCreate在实例初始化之后,数据观测(data observer) 之前被调用。createdcreated实例曾经创立实现之后被调用。在这一步,实例已实现以下的配置:数据观测(data observer),属性和办法的运算, watch/event 事件回调。这里没有$elbeforeMountbeforeMount在挂载开始之前被调用:相干的 render 函数首次被调用mountedmountedel 被新创建的 vm.$el 替换,并挂载到实例下来之后调用该钩子beforeUpdatebeforeUpdate组件数据更新之前调用,产生在虚构 DOM 打补丁之前updatedupdated因为数据更改导致的虚构 DOM 从新渲染和打补丁,在这之后会调用该钩子beforeDestroybeforeUnmount实例销毁之前调用。在这一步,实例依然齐全可用destroyedunmounted实例销毁后调用。调用后, Vue 实例批示的所有货色都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。 该钩子在服务器端渲染期间不被调用。其余几个生命周期 生命周期vue2生命周期vue3形容activatedactivatedkeep-alive专属,组件被激活时调用deactivateddeactivatedkeep-alive专属,组件被销毁时调用errorCapturederrorCaptured捕捉一个来自子孙组件的谬误时被调用-renderTracked调试钩子,响应式依赖被收集时调用-renderTriggered调试钩子,响应式依赖被触发时调用-serverPrefetchssr only,组件实例在服务器上被渲染前调用要把握每个生命周期外部能够做什么事beforeCreate 初始化vue实例,进行数据观测。执行时组件实例还未创立,通常用于插件开发中执行一些初始化工作created 组件初始化结束,能够拜访各种数据,获取接口数据等beforeMount 此阶段vm.el虽已实现DOM初始化,但并未挂载在el选项上mounted 实例曾经挂载实现,能够进行一些DOM操作beforeUpdate 更新前,可用于获取更新前各种状态。此时view层还未更新,可用于获取更新前各种状态。能够在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。updated 实现view层的更新,更新后,所有状态已是最新。能够执行依赖于 DOM 的操作。然而在大多数状况下,你应该防止在此期间更改状态,因为这可能会导致更新有限循环。 该钩子在服务器端渲染期间不被调用。destroyed 能够执行一些优化操作,清空定时器,解除绑定事件vue3 beforeunmount:实例被销毁前调用,可用于一些定时器或订阅的勾销vue3 unmounted:销毁一个实例。可清理它与其它实例的连贯,解绑它的全副指令及事件监听器 ...

November 8, 2022 · 6 min · jiezi

关于vue.js:vue面试考察知识点全梳理

一、简介vue几个核心思想: 数据驱动组件化虚构dom、diff部分最优更新源码目录介绍Vue.js 的源码在 src 目录下,其目录构造如下。 src├── compiler # 编译相干 ├── core # 外围代码 ├── platforms # 不同平台的反对├── server # 服务端渲染├── sfc # .vue 文件解析├── shared # 共享代码compiler:编译相干的代码。它包含把模板解析成 ast 语法树,ast 语法树优化,代码生成等性能。core:外围代码,包含内置组件、全局 API 封装,Vue 实例化、观察者、虚构 DOM、工具函数等等。platform:不同平台的反对,是 Vue.js 的入口,2 个目录代表 2 个次要入口,别离打包成运行在 web 上和 weex 上的 Vue.js。server:服务端渲染,把组件渲染为服务器端的 HTML 字符串,将它们间接发送到浏览器,最初将动态标记"混合"为客户端上齐全交互的应用程序。sfc: .vue 文件内容解析成一个 JavaScript 的对象。shared:浏览器端和服务端所共享的工具办法。源码构建基于 Rollup 构建,相干配置在 scripts 目录下。 构建时通过不同的命令执行不同的脚本,去读取不同用途的配置,而后生成适宜各种场景的Vue源码。 vue2.0有以下几种场景: 浏览器端服务端渲染配合weex平台在客户端应用类型查看在vue2.x版本中应用 Flow 作为js动态类型查看工具,3.x版本应用typescript实现,自带类型查看。 二、数据驱动vue核心思想之一就是数据驱动,指数据驱动生成视图,通过批改数据主动实现对视图的批改。这里次要剖析模板和数据是如何渲染成最终的DOM的。 1. new Vue的过程Vue 初始化次要就干了几件事件, 合并配置初始化生命周期初始化事件核心初始化渲染初始化 data、props、computed、watcher 等等。2. 实例挂载$mount办法 Vue 不能挂载在 body、html 这样的根节点上;如果没有定义 render 办法,则会把 el 或者 template 字符串转换成 render 办法在 Vue 2.0 版本中所有 Vue 的组件的渲染最终都须要 render 办法,是一个“在线编译”的过程;挂载组件: mountComponent外围就是先实例化一个渲染Watcher,在它的回调函数中会调用 updateComponent 办法,在此办法中调用 vm._render 办法学生成虚构 Node,最终调用 vm._update 更新 DOM。 ...

November 8, 2022 · 5 min · jiezi

关于vue.js:vue面试经常会问的那些题

为什么要应用异步组件节俭打包出的后果,异步组件离开打包,采纳jsonp的形式进行加载,无效解决文件过大的问题。外围就是包组件定义变成一个函数,依赖import() 语法,能够实现文件的宰割加载。components:{ AddCustomerSchedule:(resolve)=>import("../components/AddCustomer") // require([]) }原理 export function ( Ctor: Class<Component> | Function | Object | void, data: ?VNodeData, context: Component, children: ?Array<VNode>, tag?: string ): VNode | Array<VNode> | void { // async component let asyncFactory if (isUndef(Ctor.cid)) { asyncFactory = Ctor Ctor = resolveAsyncComponent(asyncFactory, baseCtor) // 默认调用此函数时返回 undefiend // 第二次渲染时Ctor不为undefined if (Ctor === undefined) { return createAsyncPlaceholder( // 渲染占位符 空虚构节点 asyncFactory, data, context, children, tag ) } } }function resolveAsyncComponent ( factory: Function, baseCtor: Class<Component> ): Class<Component> | void { if (isDef(factory.resolved)) { // 3.在次渲染时能够拿到获取的最新组件 return factory.resolved } const resolve = once((res: Object | Class<Component>) => { factory.resolved = ensureCtor(res, baseCtor) if (!sync) { forceRender(true) //2. 强制更新视图从新渲染 } else { owners.length = 0 } }) const reject = once(reason => { if (isDef(factory.errorComp)) { factory.error = true forceRender(true) } }) const res = factory(resolve, reject)// 1.将resolve办法和reject办法传入,用户调用 resolve办法后 sync = false return factory.resolved }diff算法工夫复杂度: 个树的齐全 diff 算法是一个工夫复杂度为 O(n*3) ,vue进行优化转化成 O(n) 。 ...

November 8, 2022 · 8 min · jiezi

关于vue.js:假如问你是怎样优化Vue项目的该怎么回答

咱们在开发Vue我的项目时候都晓得,在vue开发中某些问题如果后期疏忽掉,过后不会呈现显著的成果,然而越向后开发越难做,而且我的项目做久了就会呈现问题,这就是所说的蝴蝶效应,这样前期的保护老本会十分高,并且我的项目上线后还会影响用户体验,也会呈现加载慢等一系列的性能问题,上面举一个简略的例子。 举个简略的例子如果加载我的项目的时候加载一张图片须要0.1s,其实算不了什么能够忽略不计,然而如果我有20张图片,这就是2s的工夫, 2s的工夫不算长一下就过来了,然而这仅仅的只是加载了图片,还有咱们的js,css都须要加载,那就须要更长的工夫,可能是5s,6s...,比方加载工夫是5s,用户可能等都不会等,间接敞开咱们的网站,最初导致咱们网站流量很少,流量少就没人用,没人用就没有钱,没有钱就涨不了工资,涨不了工资最初就是跑路了。通过下面的例子能够看出性能问题是如许的重要甚至关系到了咱们薪资,那如何防止这些问题呢?废话不多说,上面分享一下本人在写我的项目的时用到的一些优化计划以及注意事项。 1.不要将所有的数据都放在data中能够将一些不被视图渲染的数据申明到实例内部而后在外部援用援用,因为Vue2初始化数据的时候会将data中的所有属性遍历通过Object.definePrototype从新定义所有属性;Vue3是通过Proxy去对数据包装,外部也会波及到递归遍历,在属性比拟多的状况下很消耗性能 <template> <button @click="updateValue">{{msg}}</button></template><script>let keys=true;export default { name:'Vueinput', data(){ return { msg:'true' } }, created(){ this.text = 'text' }, methods:{ updateValue(){ keys = !keys this.msg = keys?'true':'false' } }}</script> 2.watch 尽量不要应用deep:true深层遍历因为watch不存在缓存,是指定监听对象,如果deep:true,并且监听对象类型状况下,会递归解决收集依赖,最初触发更新回调3. vue 在 v-for 时给每项元素绑定事件须要用事件代理vue源码中是通过addEventLisener去给dom绑定事件的,比方咱们应用v-for须要渲染100条数据并且并为每个节点增加点击事件,如果每个都绑定事件那就存在很多的addEventLisener,这里不用说性能上必定不好,那咱们就须要应用事件代理解决这个问题<template> <ul @click="EventAgent"> <li v-for="(item) in mArr" :key="item.id" :data-set="item">{{item.day}}</li> </ul></template><script>let keys=true;export default { name:'Vueinput', data(){ return { mArr:[{ day:1, id:'xx1' },{ day:2, id:'xx2' },{ day:2, id:'xx2' }, ... ] } }, methods:{ EventAgent(e){ // 留神这里 在我的项目中千万不要写的这么简略,我只是为了不便了解才这么写的 console.log(e.target.getAttribute('data-set')) } }}</script>参考 前端vue面试题具体解答 ...

November 8, 2022 · 3 min · jiezi

关于vue.js:Vue-Router

1.1 相干了解1.1.1 vue-router 的了解Vue 的一个插件库,专门用来实现 SPA 利用 1.1.2 对 SPA 利用的了解单页 Web 利用(single page web application,SPA)整个利用只有一个残缺的页面点击页面中的导航链接不会刷新页面,只会做页面的部分更新数据须要通过 Ajax 申请获取1.1.3 路由的了解什么是路由 一个路由就是一组映射关系(key-value) key 为门路, value 可能是 function 或 component路由分类 后端路由: 了解:value 是 function , 用于解决客户端提交的申请工作过程:服务器接管到一个申请时,依据申请门路找到匹配的函数来解决申请,返回响应数据2.前端路由: 了解:value 是 component,用于展现页面内容工作过程:当浏览器的门路扭转时,对应的组件就会显示。1.2 根本路由1.2.1 装置与应用装置 vue-router,命令:npm install vue-router利用插件:Vue.use(VueRouter)编写 router 配置项: //引入VueRouterimport VueRouter from 'vue-router'//引入Luyou 组件import About from '../components/About'import Home from '../components/Home'//创立router实例对象,去治理一组一组的路由规定const router = new VueRouter({ routes:[ { path:'/about', component:About }, { path:'/home', component:Home } ]})//裸露routerexport default router实现切换(active-class 可配置高亮款式) ...

November 8, 2022 · 2 min · jiezi

关于vue.js:P9-vue3-事件处理

<script>export default { data() { return { counter: 0, }; }, methods:{ addCounter:function (number){ this.counter+=number } }};</script><template> <div> <!-- 绑定事件,js --> <h2 @click="counter++">{{counter}}</h2> <!--绑定事件,methods,没有传递参数 --> <h2 @click="addCounter">{{counter}}</h2> <!--绑定事件,methods,传递参数 --> <h2 @click="addCounter(2)">{{counter}}</h2> </div></template><style></style>

November 7, 2022 · 1 min · jiezi

关于vue.js:vuegridlayout拖拉拽

利落拽相干文档利落拽网站(vue-grid-layout) 1、warn正告:vue-grid-layout.common.js?7be8:11395 [interact.js] Consider adding CSS "touch-action: none" to this element2、从内部拖入后默认从右边有个闪动动画批改计划:.vue-grid-item { touch-action: none; // 勾销默认位移动画 transition: none;}

November 7, 2022 · 1 min · jiezi

关于vue.js:Vue3-setup语法糖Composition-API全方位解读

起初 Vue3.0 裸露变量必须 return 进去,template 中能力应用;Vue3.2 中 只须要在 script 标签上加上 setup 属性,组件在编译的过程中代码运行的上下文是在 setup() 函数中,无需 return,template 可间接应用。本文章以Vue2的角度学习Vue3的语法,让你疾速了解Vue3的Composition Api本文章第十四节为状态库 Pinia 的装置、应用解说一、文件构造Vue2中,<template> 标签中只能有一个根元素,在Vue3中没有此限度 <template> // ...</template><script setup> // ...</script><style lang="scss" scoped> // 反对CSS变量注入v-bind(color)</style>二、data<script setup> import { reactive, ref, toRefs } from 'vue' // ref申明响应式数据,用于申明根本数据类型 const name = ref('Jerry') // 批改 name.value = 'Tom' // reactive申明响应式数据,用于申明援用数据类型 const state = reactive({ name: 'Jerry', sex: '男' }) // 批改 state.name = 'Tom' // 应用toRefs解构 const {name, sex} = toRefs(state) // template可间接应用{{name}}、{{sex}}</script>三、method<template> // 调用办法 <button @click='changeName'>按钮</button> </template><script setup> import { reactive } from 'vue' const state = reactive({ name: 'Jery' }) // 申明method办法 const changeName = () => { state.name = 'Tom' } </script>四、computed<script setup> import { computed, ref } from 'vue' const count = ref(1) // 通过computed取得doubleCount const doubleCount = computed(() => { return count.value * 2 }) // 获取 console.log(doubleCount.value)</script>五、watch<script setup> import { watch, reactive } from 'vue' const state = reactive({ count: 1 }) // 申明办法 const changeCount = () => { state.count = state.count * 2 } // 监听count watch( () => state.count, (newVal, oldVal) => { console.log(state.count) console.log(`watch监听变动前的数据:${oldVal}`) console.log(`watch监听变动后的数据:${newVal}`) }, { immediate: true, // 立刻执行 deep: true // 深度监听 } )</script>六、props父传子子组件<template> <span>{{props.name}}</span> // 可省略【props.】 <span>{{name}}</span></template><script setup> // import { defineProps } from 'vue' // defineProps在<script setup>中主动可用,无需导入 // 需在.eslintrc.js文件中【globals】下配置【defineProps: true】 // 申明props const props = defineProps({ name: { type: String, default: '' } }) </script>父组件引入子组件,组件会主动注册 ...

November 7, 2022 · 7 min · jiezi

关于vue.js:Vue3必会技巧自定义Hooks

Vue3自定义Hooks定义:集体了解:一些可复用的办法像钩子一样挂着,能够随时被引入和调用以实现高内聚低耦合的指标,应该都能算是hook;为什么Vue3要用自定义Hook?:论断:就是为了让Compoosition Api更好用更饱满,让写Vue3更畅快!像写诗一样写代码!其实这个问题更深意义是为什么Vue3比Vue2更好!无外呼性能大幅度晋升,其实编码体验也是Vue3的长处Composition Api的引入(解决Option Api在代码量大的状况下的强耦合) 让开发者有更好的开发体验。 集体碎碎念:然而这些所谓的进步开发体验都是须要开发者一直学习养成编码好习惯,同样是Vue3写Compoosition Api有的人就能写得和诗一样,有的人却能写得像一样(衷心希望每个开发者都有一颗对技术热衷的心,不要为了开发而开发,前人写翔让前人尝!道歉最近因为保护老我的项目太多感叹) 写Vue3请解脱Vue2无脑this的思维:写Vue2中很多同学养成了 Option Api无脑this的习惯,来到Vue3的Composition Api还是习惯性想用this,更有人为了写this不惜引入getCurrentInstance!这大可不必!Composition Api的长处之一就是解脱无脑this导致的强耦合,性能之间相互this,变量和办法在各个办法混淆,无处不在的this是强耦合的,尽管不便,然而碎片化的option api 前期保护是麻烦的。 我置信写Vue2的同学,肯定深有感触,一个组件下定义大量变和大量办法,办法嵌套办法,办法之间相互共享变量,保护这样的代码,看似容易了解的Option Api写法,咱们须要在methos、data、template之间来回切,Option Api这种写法,代码量和性能玲珑时是非常简单明了的,然而代码量一多,性能一简单,我置信review代码的时候头都痛。 绝对的Composition Api在性能简单、代码量微小的组件下,咱们配合自定义Hooks,将代码通过性能分块写,响应变量和办法在一起定义和调用,这样前期咱们改性能A只须要关注性能A块下的代码,不会像Vue2在Option Api须要同时关注methos和data。。。。。 几张动图再来温习一遍 Composition Api 好!谢谢 大帅老猿 老师做的动图,Composition Api VS Option Api 的优缺点非常明了展现在了动画上!Option Api代码量少还好,代码量多容易导致高耦合!阐明:下面是Vue2 Option Api的写法,一个组件下含有data 、methos、computed、watch,同一个性能须要离开写在这些函数上,如果代码量少,那看起来仿佛非常明了清晰。一旦代码量大性能简单,各个性能离开写,保护的时候data 、methos、computed、watch都须要来回切,反而显得过于扩散,又高度耦合。 Composition Api解耦Vue2 Option Api实现低耦合高内聚阐明:如果是Composition Api在性能简单、代码量微小的组件下,咱们配合自定义Hook,将代码按性能分块写,变量和办法在一起定义和调用,比方A性能下集成了响应式变量和办法,咱们前期保护只须要改变A功能模块下的代码,不会像Vue2在Option Api须要同时关注逻辑扩散的methos和data。 所以自定义Hook的写Vue3必须把握的!它无不体现Vue3 Composition Api 低耦合高内聚的思维! 笔者在看了官网文档和开源的admin模板都是大量应用自定义Hooks的! 大胆定义一下Vue3的自定义Hook:尽管官网没有明确指明或定义什么是自定义Hooks,然而却无处不在用; 以函数模式抽离一些可复用的办法像钩子一样挂着,随时能够引入和调用,实现高内聚低耦合的指标; 将可复用性能抽离为内部JS文件函数名/文件名以use结尾,形如:useXX援用时将响应式变量或者办法显式解构裸露进去如:const {nameRef,Fn} = useXX() (在setup函数解构出自定义hooks的变量和办法) 实例:简略的加减法计算,将加法和减法抽离为2个自定义Hooks,并且互相传递响应式数据加法性能-Hookimport { ref, watch } from 'vue';const useAdd= ({ num1, num2 }) =>{ const addNum = ref(0) watch([num1, num2], ([num1, num2]) => { addFn(num1, num2) }) const addFn = (num1, num2) => { addNum.value = num1 + num2 } return { addNum, addFn }}export default useAdd减法性能-Hook//减法性能-Hookimport { ref, watch } from 'vue';export function useSub ({ num1, num2 }){ const subNum = ref(0) watch([num1, num2], ([num1, num2]) => { subFn(num1, num2) }) const subFn = (num1, num2) => { subNum.value = num1 - num2 } return { subNum, subFn }}加减法计算组件<template> <div> num1:<input v-model.number="num1" style="width:100px" /> <br /> num2:<input v-model.number="num2" style="width:100px" /> </div> <span>加法等于:{{ addNum }}</span> <br /> <span>减法等于:{{ subNum }}</span></template><script setup>import { ref } from 'vue'import useAdd from './useAdd.js' //引入主动hook import { useSub } from './useSub.js' //引入主动hook const num1 = ref(2)const num2 = ref(1)//加法性能-自定义Hook(将响应式变量或者办法模式裸露进去)const { addNum, addFn } = useAdd({ num1, num2 })addFn(num1.value, num2.value)//减法性能-自定义Hook (将响应式变量或者办法模式裸露进去)const { subNum, subFn } = useSub({ num1, num2 })subFn(num1.value, num2.value)</script>通过上述示例再来说说Vue3自定义Hooks和Vue2时代Mixin的关系:参考vue实战视频解说:进入学习 ...

November 7, 2022 · 2 min · jiezi

关于vue.js:Vue3知识点之数据侦测

Vue 的外围之一就是响应式零碎,通过侦测数据的变动,来驱动更新视图。 实现可响应对象的形式通过可响应对象,实现对数据的侦测,从而告知外界数据变动。实现可响应对象的形式: getter 和 setterdefinePropertyProxy对于前两个 API 的应用形式不多赘述,繁多的拜访器 getter/setter 性能绝对简略,而作为 Vue2.x 实现可响应对象的 API - defineProperty ,API 自身存在较多问题。 Vue2.x 中,实现数据的可响应,须要对 Object 和 Array 两种类型采纳不同的解决形式。 Object 类型通过 Object.defineProperty 将属性转换成 getter/setter ,这个过程须要递归侦测所有的对象 key,来实现深度的侦测。 为了感知 Array 的变动,对 Array 原型上几个扭转数组本身的内容的办法做了拦挡,尽管实现了对数组的可响应,但同样存在一些问题,或者说不够不便的状况。同时,defineProperty 通过递归实现 getter/setter 也存在肯定的性能问题。 更好的实现形式是通过 ES6 提供的 Proxy API。 Proxy API 的一些细节Proxy API 具备更加弱小的性能,相比旧的 defineProperty API ,Proxy 能够代理数组,并且 API 提供了多个 traps ,能够实现诸多性能。 这里次要说两个trap: get 、 set , 以及其中的一些比拟容易被疏忽的细节。 细节一:trap 默认行为let data = { foo: 'foo' }let p = new Proxy(data, { get(target, key, receiver) { return target[key] }, set(target, key, value, receiver) { console.log('set value') target[key] = value // ? }})p.foo = 123// set value通过 proxy 返回的对象 p 代理了对原始数据的操作,当对 p 设置时,便能够侦测到变动。然而这么写实际上是有问题,当代理的对象数据是数组时,会报错。 ...

November 7, 2022 · 6 min · jiezi

关于vue.js:Vue源码解读之InitState

后面咱们讲到了_init函数的执行流程,简略回顾下: 初始化生命周期-initLifecycle初始化事件-initEvents初始化渲染函数-initRender调用钩子函数-beforeCreate初始化依赖注入-initInjections初始化状态信息-initState初始化依赖提供-initProvide调用钩子函数-created一共通过下面8步,init函数执行实现,开始mount渲染。初始化状态信息本章咱们次要解说initState函数的处理过程,咱们先看下init的主函数 function initState(vm: Component) { vm._watchers = [] const opts = vm.$options if (opts.props) { initProps(vm, opts.props) } if (opts.methods) { initMethods(vm, opts.methods) } if (opts.data) { initData(vm) } else { observe(vm._data = {}, true /* asRootData */) } if (opts.computed) { initComputed(vm, opts.computed) } if (opts.watch && opts.watch !== nativeWatch) { initWatch(vm, opts.watch) }}看下面代码,先申明了一个_watchers的空数组;而后顺次判断传递进来的options是否蕴含系列参数;顺次执行initProps、initMethods、initData、initComputed、initWatch。 initPropsinitProps函数次要是解决传进来的props对象,然而这个props对象是在上一篇文章中讲到的normalizeProps函数解决后的对象,不是传递进来的原对象。来看下initProps的代码: function initProps(vm: Component, propsOptions: Object) { const propsData = vm.$options.propsData || {} const props = vm._props = {} const keys = vm.$options._propKeys = [] const isRoot = !vm.$parent if (!isRoot) { toggleObserving(false) } for (const key in propsOptions) { keys.push(key) const value = validateProp(key, propsOptions, propsData, vm) defineReactive(props, key, value) if (!(key in vm)) { proxy(vm, `_props`, key) } } toggleObserving(true)}下面代码解读: ...

November 7, 2022 · 4 min · jiezi

关于vue.js:vue源码中的nextTick是怎样实现的

一、Vue.nextTick 外部逻辑在执行 initGlobalAPI(Vue) 初始化 Vue 全局 API 中,这么定义 Vue.nextTick。 function initGlobalAPI(Vue) { //... Vue.nextTick = nextTick;}能够看出是间接把 nextTick 函数赋值给 Vue.nextTick,就能够了,非常简单。 二、vm.$nextTick 外部逻辑Vue.prototype.$nextTick = function (fn) { return nextTick(fn, this)};能够看出是 vm.$nextTick 外部也是调用 nextTick 函数。 三、前置常识nextTick 函数的作用能够了解为异步执行传入的函数,这里先介绍一下什么是异步执行,从 JS 运行机制说起。 1、JS 运行机制JS 的执行是单线程的,所谓的单线程就是事件工作要排队执行,前一个工作完结,才会执行后一个工作,这就是同步工作,为了防止前一个工作执行了很长时间还没完结,那下一个工作就不能执行的状况,引入了异步工作的概念。JS 运行机制简略来说能够按以下几个步骤。 所有同步工作都在主线程上执行,造成一个执行栈(execution context stack)。主线程之外,还存在一个工作队列(task queue)。只有异步工作有了运行后果,会把其回调函数作为一个工作增加到工作队列中。一旦执行栈中的所有同步工作执行结束,就会读取工作队列,看看外面有那些工作,将其增加到执行栈,开始执行。主线程一直反复下面的第三步。也就是常说的事件循环(Event Loop)。2、异步工作的类型nextTick 函数异步执行传入的函数,是一个异步工作。异步工作分为两种类型。 主线程的执行过程就是一个 tick,而所有的异步工作都是通过工作队列来一一执行。工作队列中寄存的是一个个的工作(task)。标准中规定 task 分为两大类,别离是宏工作(macro task)和微工作 (micro task),并且每个 macro task 完结后,都要清空所有的 micro task。 用一段代码形象介绍 task的执行程序。 for (macroTask of macroTaskQueue) { handleMacroTask(); for (microTask of microTaskQueue) { handleMicroTask(microTask); }}在浏览器环境中,常见的创立 macro task 的办法有 ...

November 7, 2022 · 5 min · jiezi

关于vue.js:如何准备好一场vue面试

对SSR的了解SSR也就是服务端渲染,也就是将Vue在客户端把标签渲染成HTML的工作放在服务端实现,而后再把html间接返回给客户端 SSR的劣势: 更好的SEO首屏加载速度更快SSR的毛病: 开发条件会受到限制,服务器端渲染只反对beforeCreate和created两个钩子;当须要一些内部扩大库时须要非凡解决,服务端渲染应用程序也须要处于Node.js的运行环境;更多的服务端负载。Vue的长处轻量级框架:只关注视图层,是一个构建数据的视图汇合,大小只有几十 kb ;简略易学:国人开发,中文文档,不存在语言障碍 ,易于了解和学习;双向数据绑定:保留了 angular 的特点,在数据操作方面更为简略;组件化:保留了 react 的长处,实现了 html 的封装和重用,在构建单页面利用方面有着独特的劣势;视图,数据,构造拆散:使数据的更改更为简略,不须要进行逻辑代码的批改,只须要操作数据就能实现相干操作;虚构DOM:dom 操作是十分消耗性能的,不再应用原生的 dom 操作节点,极大解放 dom 操作,但具体操作的还是 dom 不过是换了另一种形式;运行速度更快:相比拟于 react 而言,同样是操作虚构 dom,就性能而言, vue 存在很大的劣势。computed 的实现原理computed 实质是一个惰性求值的观察者。 computed 外部实现了一个惰性的 watcher,也就是 computed watcher,computed watcher 不会立即求值,同时持有一个 dep 实例。 其外部通过 this.dirty 属性标记计算属性是否须要从新求值。 当 computed 的依赖状态产生扭转时,就会告诉这个惰性的 watcher, computed watcher 通过 this.dep.subs.length 判断有没有订阅者, 有的话,会从新计算,而后比照新旧值,如果变动了,会从新渲染。 (Vue 想确保不仅仅是计算属性依赖的值发生变化,而是当计算属性最终计算的值发生变化时才会触发渲染 watcher 从新渲染,实质上是一种优化。) 没有的话,仅仅把 this.dirty = true。 (当计算属性依赖于其余数据时,属性并不会立刻从新计算,只有之后其余中央须要读取属性的时候,它才会真正计算,即具备 lazy(懒计算)个性。) 能说下 vue-router 中罕用的 hash 和 history 路由模式实现原理吗?(1)hash 模式的实现原理 晚期的前端路由的实现就是基于 location.hash 来实现的。其实现原理很简略,location.hash 的值就是 URL 中 # 前面的内容。比方上面这个网站,它的 location.hash 的值为 '#search': ...

November 7, 2022 · 5 min · jiezi

关于vue.js:vue这些原理你都知道吗面试版

前言在之前面试的时候我本人也常常会遇到一些vue原理的问题, 我也总结了下本人的常常的用到的,不便本人学习,明天也给大家分享进去, 欢送大家一起学习交换, 有更好的办法欢送评论区指出, 后序我也将继续整顿总结~ 形容 Vue 与 React 区别阐明概念:vue:是一套用于构建用户界面的渐进式框架,Vue 的外围库只关注视图层react:用于构建用户界面的 JavaScript 库 申明式, 组件化 定位vue 渐进式 响应式React 单向数据流写法 vue:template,jsx react: jsxHooks:vue3 和 react16 反对 hookUI 更新文化vue 官网提供React 第三方提供,本人抉择整个 new Vue 阶段做了什么?vue.prototype._init(option)initState(vm)Observer(vm.data)new Observer(data)调用 walk 办法,遍历 data 中的每个属性,监听数据的变动执行 defineProperty 监听数据读取和设置数据描述符绑定实现后,咱们就能失去以下的流程图 图中咱们能够看出,vue 初始化的时候,进行了数据的 get\set 绑定,并创立了一个dep 对象就是用来依赖收集, 他实现了一个公布订阅模式,完后了数据 data 的渲染视图 watcher 的订阅class Dep { // 依据 ts 类型提醒,咱们能够得出 Dep.target 是一个 Watcher 类型。 static target: ?Watcher; // subs 寄存收集到的 Watcher 对象汇合 subs: Array<Watcher>; constructor() { this.subs = []; } addSub(sub: Watcher) { // 收集所有应用到这个 data 的 Watcher 对象。 this.subs.push(sub); } depend() { if (Dep.target) { // 收集依赖,最终会调用下面的 addSub 办法 Dep.target.addDep(this); } } notify() { const subs = this.subs.slice(); for (let i = 0, l = subs.length; i < l; i++) { // 调用对应的 Watcher,更新视图 subs[i].update(); } }}形容 vue 的响应式原理 ...

November 7, 2022 · 6 min · jiezi

关于vue.js:谈谈vue面试那些题

Vue组件data为什么必须是个函数?根实例对象data能够是对象也能够是函数 (根实例是单例),不会产生数据净化状况组件实例对象data必须为函数 一个组件被复用屡次的话,也就会创立多个实例。实质上,这些实例用的都是同一个构造函数。如果data是对象的话,对象属于援用类型,会影响到所有的实例。所以为了保障组件不同的实例之间data不抵触,data必须是一个函数,简版了解 // 1.组件的渲染流程 调用Vue.component -> Vue.extend -> 子类 -> new 子类// Vue.extend 依据用户定义产生一个新的类function Vue() {}function Sub() { // 会将data存起来 this.data = this.constructor.options.data();}Vue.extend = function(options) { Sub.options = options; // 动态属性 return Sub;}let Child = Vue.extend({ data:()=>( { name: 'zf' })});// 两个组件就是两个实例, 心愿数据互不感化let child1 = new Child();let child2 = new Child();console.log(child1.data.name);child1.data.name = 'poetry';console.log(child2.data.name);// 根不须要 任何的合并操作 根才有vm属性 所以他能够是函数和对象 然而组件mixin他们都没有vm 所以我就能够判断 以后data是不是个函数相干源码 // 源码地位 src/core/global-api/extend.jsexport function initExtend (Vue: GlobalAPI) { Vue.extend = function (extendOptions: Object): Function { extendOptions = extendOptions || {} const Super = this const SuperId = Super.cid const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {}) if (cachedCtors[SuperId]) { return cachedCtors[SuperId] } const name = extendOptions.name || Super.options.name if (process.env.NODE_ENV !== 'production' && name) { validateComponentName(name) } const Sub = function VueComponent (options) { this._init(options) } // 子类继承大Vue父类的原型 Sub.prototype = Object.create(Super.prototype) Sub.prototype.constructor = Sub Sub.cid = cid++ Sub.options = mergeOptions( Super.options, extendOptions ) Sub['super'] = Super // For props and computed properties, we define the proxy getters on // the Vue instances at extension time, on the extended prototype. This // avoids Object.defineProperty calls for each instance created. if (Sub.options.props) { initProps(Sub) } if (Sub.options.computed) { initComputed(Sub) } // allow further extension/mixin/plugin usage Sub.extend = Super.extend Sub.mixin = Super.mixin Sub.use = Super.use // create asset registers, so extended classes // can have their private assets too. ASSET_TYPES.forEach(function (type) { Sub[type] = Super[type] }) // enable recursive self-lookup if (name) { Sub.options.components[name] = Sub // 记录本人 在组件中递归本人 -> jsx } // keep a reference to the super options at extension time. // later at instantiation we can check if Super's options have // been updated. Sub.superOptions = Super.options Sub.extendOptions = extendOptions Sub.sealedOptions = extend({}, Sub.options) // cache constructor cachedCtors[SuperId] = Sub return Sub }}理解history有哪些办法吗?说下它们的区别history 这个对象在html5的时候新退出两个api history.pushState() 和 history.repalceState() 这两个API能够在不进行刷新的状况下,操作浏览器的历史纪录。惟一不同的是,前者是新增一个历史记录,后者是间接替换以后的历史记录。从参数上来说: ...

November 7, 2022 · 5 min · jiezi

关于vue.js:vue面试之CompositionAPI响应式包装对象原理

本文次要分以下两个局部对 Composition API 的原理进行解读: reactive API 原理ref API 原理reactive API 原理关上源码能够找到reactive的入口,在composition-api/src/reactivity/reactive.ts,咱们先从函数入口开始剖析reactive产生了什么事件,通过之前的学习咱们晓得,reactive用于创立响应式对象,须要传递一个一般对象作为参数。 export function reactive<T = any>(obj: T): UnwrapRef<T> { if (process.env.NODE_ENV !== 'production' && !obj) { warn('"reactive()" is called without provide an "object".'); // @ts-ignore return; } if (!isPlainObject(obj) || isReactive(obj) || isNonReactive(obj) || !Object.isExtensible(obj)) { return obj as any; } // 创立一个响应式对象 const observed = observe(obj); // 标记一个对象为响应式对象 def(observed, ReactiveIdentifierKey, ReactiveIdentifier); // 初始化对象的访问控制,便于拜访ref属性时主动解包装 setupAccessControl(observed); return observed as UnwrapRef<T>;}首先,在开发环境下,会进行传参测验,如果没有传递对应的obj参数,开发环境下会给予开发者一个正告,在这种状况,为了不影响生产环境,生产环境下会将正告放过。 ...

November 7, 2022 · 4 min · jiezi

关于vue.js:P8-vue3-数组更新检查

<script>export default { data() { return { list: [1, 2, 3, 4, 5], }; }, methods:{ changeList:function (){ //vue2 不能够通过批改索引值更新数组 this.list[5]=7 // push();给数组开端增加元素 // pop(); // shift() // unshift() // splice() // sort() // reverse() }, }};</script><template> <div> <ul> <li v-for="itme in list" :key="itme"> {{itme}}</li> </ul> <button @click="changeList">change list</button> </div></template><style></style>

November 5, 2022 · 1 min · jiezi

关于vue.js:Vue学习笔记二-相识篇

浏览本文须要根本把握HTML、CSS和JavaScript的中级常识,还有《Vue学习笔记(二) 初遇篇》。本篇在某种程度上并不是承接上一篇,更像是初遇篇的重构。前言去思否翻了翻本人第一篇写Vue相干的文章《Vue 学习笔记(一)初遇》, 发表的日期是2019年12月14号,也就是这一年呈现了疫情,到当初大略有三年了,不胜唏嘘。往年据说是“寒意凛然”,为了晋升本人的性价比,加强本人的竞争力,我决定重新学习一下前端。这是开玩笑的话,其实是为了做一个开源我的项目做筹备。让咱们来回顾一下《Vue 学习笔记(一)初遇》讲的货色,在这篇内容中咱们次要讲了JavaScript的大抵倒退历史,晚期的浏览器对JavaScript适配不齐全,雷同的JavaScript可能在不同的浏览器上没有统一的行为,而且在写管制DOM结点方面非常繁琐,于是有人推出了JQuery,化繁为简,然而随着网页在越来越简单,因为JQuery间接操纵DOM结点,DOM的节点的扭转就会带来网页的重绘,于是前面的前端框架的思路就是推出虚构DOM,使用diff算法来计算出真正须要更新的节点,最大限度地缩小DOM操作以及DOM操作带来的排版与重绘损耗,从而显著进步性能。 等等,JQuery操纵结点须要重绘,你的Vue也须要重绘啊? 那么你的Vue到底好在哪里呢? 好在,会合并运算,将屡次更改合并为一次,举一个例子,在JQuery中假如须要操纵三次Dom,由三个办法触发,但其实最终不须要更新那么屡次结点,咱们将DOM了解为一个数字,每次操作像是对这个数字进行加减,那么三次DOM操作可能就像是 5+ 3 - 5 , 最终只须要加3渲染一次就行了,这是Vue的做法。然而对于JQuery来说就是运算三次,带来三次页面重绘。这个性能节俭就在这里。 那么对于一个简单的页面,你这个diff算法的计算不须要工夫吗?当然也须要工夫, 其实咱们Vue次要还是在晋升开发效率、代码复用性。 这也就是Angular、Vue、React的思路,然而这些前端框架所带来的并不仅仅是虚构DOM,还带来了响应式、MVVM。但Vue并不具备侵入性,是渐进式的,所谓渐进式也就是说,如果你当初就有一个利用,那么你能够抉择将Vue嵌入到你的利用中,来享受Vue提供的便当,而不会对全局进行扭转。等一等,你说Vue提供的便当,你说到这个我就不困了,能举一个例子来阐明下Vue的便当吗? 好的,上面是一个最终效果图: 对html有一点相熟的同学可能一下子就看进去了,这是四个无序列表标签,列表标签前面是一个json。如果这些json是从服务端传递过去的,那么用JQuery实现下面的思路就是首先应用Ajax获取前端数据,而后拼接成对应的html字符串,通过JQuery选择器选中对应的元素,获取到JQuery对象之后,将对应的html字符串传给对象的append办法,此办法会将咱们拼接的字符串渲染为实在的DOM结点。 <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title></head><body> <div id = "app"> </div> </body> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.min.js"> // 这个标签用于引入JQuery</script><script> $(document).ready(function(){ // dom加载结点之后触发getJSON,获取的数据会传给result $.getJSON("http://localhost:8080/hello",function(result){ var products = result.products; console.log(products); var targetStr = ""; // 通过foreach办法拼接成最终的字符串 $.each(products, function(i, field){ field = JSON.stringify(field); targetStr = targetStr + "<li>" + field + "</li>" }); // 通过append办法创立结点 $("#app").append("<ul>"+targetStr+"</ul>"); });});</script></html>最终的后果如下图所示: ...

November 5, 2022 · 5 min · jiezi

关于vue.js:P7-vue3-列表渲染-vfor

数组<script>export default { data() { return { prersion: ['tom', 'sean', 'green'] }; },};</script><template> <div> <!-- v-for 应用数组 --> <ul> <li v-for="item in prersion" :key="item"> {{item}}</li> </ul> <ul> <li v-for="(item,index) in prersion" :key="index"> {{item}}--{{index}}</li> </ul> <ul> <li v-for="(item,index) of prersion" :key="index"> {{item}}--{{index}}</li> </ul> </div></template><style></style>of 和 in 一样能够作为分隔符。 对象<script>export default { data() { return { prersion: ['tom', 'sean', 'green'], prersonObj: {name: 'tom', age: 18, sex: 'nan'} }; },};</script><template> <div> <!-- v-for 应用数组 --> <ul> <li v-for="item in prersion" :key="item"> {{item}}</li> </ul> <ul> <li v-for="(item,index) in prersion" :key="index"> {{item}}--{{index}}</li> </ul> <ul> <li v-for="(item,index) of prersion" :key="index"> {{item}}--{{index}}</li> </ul> <!-- v-for 应用对象 i 示意键值--> <ul> <li v-for="(i,k) in prersonObj" :key="k">value:{{i}} --key:{{k}}</li> </ul> </div></template><style></style> ...

November 4, 2022 · 1 min · jiezi

关于vue.js:聊聊Vuex原理

背景Vuex 是一个专为 Vue.js 利用程序开发的状态管理模式。Vuex 是专门为 Vue.js 设计的状态治理库,以利用 Vue.js 的细粒度数据响应机制来进行高效的状态更新。如果你曾经灵活运用,然而仍然好奇它底层实现逻辑,无妨一探到底。Vue 组件开发咱们晓得开发 Vue 插件,装置的时候须要执行 Vue.use(Vuex) import Vue from 'vue'import Vuex from '../vuex'Vue.use(Vuex)通过查看 Vue API Vue-use 开发文档,咱们晓得装置 Vue.js 插件。如果插件是一个对象,必须提供 install 办法。如果插件是一个函数,它会被作为 install 办法。install 办法调用时,会将 Vue 作为参数传入。该办法须要在调用 new Vue() 之前被调用。当 install 办法被同一个插件屡次调用,插件将只会被装置一次。为了更好了的去了解源码意思,这里写了一个简略的测试实例。 测试实例代码import Vue from 'vue'import Vuex from '../vuex'Vue.use(Vuex)export default new Vuex.Store({ plugins: [], state: { time: 1, userInfo: { avatar: '', account_name: '', name: '' }, }, getters: { getTime (state) { console.log('1212',state) return state.time } }, mutations: { updateTime(state, payload){ state.time = payload } }, actions: { operateGrou({ commit }) { // commit('updateTime', 100) return Promise.resolve().then(()=>{ return { rows: [1,2,3] } }) } }, modules: { report: { namespaced: true, state: { title: '', }, getters: { getTitle (state) { return state.title } }, mutations: { updateTitle(state, payload){ state.title = payload } }, actions: { operateGrou({ commit }) { commit('updateTitle', 100) return Promise.resolve().then(()=>{ return { rows: [1,2,2,3] } }) } }, modules: { reportChild: { namespaced: true, state: { titleChild: '', }, mutations: { updateTitle(state, payload){ state.title = payload } }, actions: { operateGrou({ commit }) { commit('updateTitle', 100) return Promise.resolve().then(()=>{ return { rows: [1,2,2,3] } }) } }, } } }, part: { namespaced: true, state: { title: '', }, mutations: { updateTitle(state, payload){ state.title = payload }, updateTitle1(state, payload){ state.title = payload } }, actions: { operateGrou({ commit }) { commit('updateTitle', 100) return Promise.resolve().then(()=>{ return { rows: [1,2,2,3] } }) } }, modules: { partChild: { namespaced: true, state: { titleChild: '', }, getters: { getTitleChild (state) { return state.titleChild } }, mutations: { updateTitle(state, payload){ state.titleChild = payload } }, actions: { operateGrou({ commit }) { commit('updateTitle', 1000) return Promise.resolve().then(()=>{ return { rows: [1,2,2,3] } }) } }, modules: { partChildChild: { namespaced: true, state: { titleChild: '', }, getters: { getTitleChild (state) { return state.titleChild } }, mutations: { updateTitle(state, payload){ state.titleChild = payload } }, actions: { operateGrou({ commit }) { commit('updateTitle', 1000) return Promise.resolve().then(()=>{ return { rows: [1,2,2,3] } }) } }, } } } } } }})Graphviz 父子结点关系图用 Graphviz 图来示意一下父子节点的关系,不便了解 ...

November 4, 2022 · 7 min · jiezi

关于vue.js:解读Vue3模板编译优化

明天的文章打算学习下 Vue3 下的模板编译与 Vue2 下的差别,以及 VDOM 下 Diff 算法的优化。 编译入口理解过 Vue3 的同学必定晓得 Vue3 引入了新的组合 Api,在组件 mount 阶段会调用 setup 办法,之后会判断 render 办法是否存在,如果不存在会调用 compile 办法将 template 转化为 render。 // packages/runtime-core/src/renderer.tsconst mountComponent = (initialVNode, container) => { const instance = ( initialVNode.component = createComponentInstance( // ...params ) ) // 调用 setup setupComponent(instance)}// packages/runtime-core/src/component.tslet compileexport function registerRuntimeCompiler(_compile) { compile = _compile}export function setupComponent(instance) { const Component = instance.type const { setup } = Component if (setup) { // ...调用 setup } if (compile && Component.template && !Component.render) { // 如果没有 render 办法 // 调用 compile 将 template 转为 render 办法 Component.render = compile(Component.template, {...}) }}这部分都是 runtime-core 中的代码,之前的文章有讲过 Vue 分为完整版和 runtime 版本。如果应用 vue-loader 解决 .vue 文件,个别都会将 .vue 文件中的 template 间接解决成 render 办法。 ...

November 4, 2022 · 5 min · jiezi

关于vue.js:VuenextTick核心原理

置信大家在写vue我的项目的时候,肯定会发现一个神奇的api,Vue.nextTick。为什么说它神奇呢,那是因为在你做某些操作不失效时,将操作写在Vue.nextTick内,就神奇的失效了。那这是什么起因呢? 让咱们一起来钻研一下。 简述vue 实现响应式并不是数据发生变化后 DOM 立刻变动,而是依照肯定策略异步执行 DOM 更新的vue 在批改数据后,视图不会立即进行更新,而是要等同一事件循环机制内所有数据变动实现后,再对立进行DOM更新nextTick 能够让咱们在下次 DOM 更新循环完结之后执行提早回调,用于取得更新后的 DOM。事件循环机制在探讨Vue.nextTick之前,须要先搞清楚事件循环机制,算是实现的基石了,那咱们来看一下。 在浏览器环境中,咱们能够将咱们的执行工作分为宏工作和微工作, 宏工作: 包含整体代码script,setTimeout,setInterval 、setImmediate、 I/O 操作、UI 渲染微工作: Promise.then、MuationObserver 事件循环的程序,决定js代码的执行程序。事件循环如下: 用代码解释,浏览器中事件循环的程序同如下代码: for (macroTask of macroTaskQueue) { // 1. 执行一个宏工作 handleMacroTask(); // 2. 执行所有的微工作 for (microTask of microTaskQueue) { handleMicroTask(microTask); } }vue数据驱动视图的解决(异步变动DOM)<template> <div> <div>{{count}}</div> <div @click="handleClick">click</div> </div></template>export default { data () { return { number: 0 }; }, methods: { handleClick () { for(let i = 0; i < 10000; i++) { this.count++; } } }}剖析上述代码: ...

November 4, 2022 · 3 min · jiezi

关于vue.js:vue源码分析组件

咱们晓得,组件是Vue体系的外围,纯熟应用组件是把握Vue进行开发的根底。上一节中,咱们深刻理解了Vue组件注册到应用渲染的残缺流程。这一节咱们会在上一节的根底上介绍组件的两个高级用法:异步组件和函数式组件。6.1 异步组件6.1.1 应用场景Vue作为单页面利用遇到最辣手的问题是首屏加载工夫的问题,单页面利用会把页面脚本打包成一个文件,这个文件蕴含着所有业务和非业务的代码,而脚本文件过大也是造成首页渲染速度迟缓的起因。因而作为首屏性能优化的课题,最罕用的解决办法是对文件的拆分和代码的拆散。按需加载的概念也是在这个前提下引入的。咱们往往会把一些非首屏的组件设计成异步组件,局部不影响首次视觉体验的组件也能够设计为异步组件。这个思维就是按需加载。艰深点了解,按需加载的思维让利用在须要应用某个组件时才去申请加载组件代码。咱们借助webpack打包后的后果会更加直观。 webpack遇到异步组件,会将其从主脚本中拆散,缩小脚本体积,放慢首屏加载工夫。当遇到场景须要应用该组件时,才会去加载组件脚本。 6.1.2 工厂函数Vue中容许用户通过工厂函数的模式定义组件,这个工厂函数会异步解析组件定义,组件须要渲染的时候才会触发该工厂函数,加载后果会进行缓存,以供下一次调用组件时应用。具体应用: // 全局注册:Vue.component('asyncComponent', function(resolve, reject) { require(['./test.vue'], resolve)})// 部分注册:var vm = new Vue({ el: '#app', template: '<div id="app"><asyncComponent></asyncComponent></div>', components: { asyncComponent: (resolve, reject) => require(['./test.vue'], resolve), // 另外写法 asyncComponent: () => import('./test.vue'), }})6.1.3 流程剖析有了上一节组件注册的根底,咱们来剖析异步组件的实现逻辑。简略回顾一下上一节的流程,实例的挂载流程分为依据渲染函数创立Vnode和依据Vnode产生实在节点的过程。期间创立Vnode过程,如果遇到子的占位符节点会调用creatComponent,这里会为子组件做选项合并和钩子挂载的操作,并创立一个以vue-component-为标记的子Vnode,而异步组件的解决逻辑也是在这个阶段解决。参考Vue3源码视频解说:进入学习 // 创立子组件过程 function createComponent ( Ctor, // 子类结构器 data, context, // vm实例 children, // 子节点 tag // 子组件占位符 ) { ··· // 针对部分注册组件创立子类结构器 if (isObject(Ctor)) { Ctor = baseCtor.extend(Ctor); } // 异步组件分支 var asyncFactory; if (isUndef(Ctor.cid)) { // 异步工厂函数 asyncFactory = Ctor; // 创立异步组件函数 Ctor = resolveAsyncComponent(asyncFactory, baseCtor); if (Ctor === undefined) { return createAsyncPlaceholder( asyncFactory, data, context, children, tag ) } } ··· // 创立子组件vnode var vnode = new VNode( ("vue-component-" + (Ctor.cid) + (name ? ("-" + name) : '')), data, undefined, undefined, undefined, context, { Ctor: Ctor, propsData: propsData, listeners: listeners, tag: tag, children: children }, asyncFactory ); return vnode }工厂函数的用法使得Vue.component(name, options)的第二个参数不是一个对象,因而不论是全局注册还是部分注册,都不会执行Vue.extend生成一个子组件的结构器,所以Ctor.cid不会存在,代码会进入异步组件的分支。 ...

November 4, 2022 · 4 min · jiezi

关于vue.js:上帝视角看Vue源码整体架构相关源码问答

前言这段时间利用课余时间夹杂了很多很多事把 Vue2 源码学习了一遍,但很多都是跟着视频大略过了一遍,也都画了本人的思维导图。但还是对详情的感怀模糊不清,故这段时间对源码进行了总结梳理。 本篇文章更适合于已看过 Vue2 源码,进一步总结加深概念的人群。若还未读过源码或系统只知其一;不知其二的小伙伴,也能够筛选阶段进行总结梳理,集体还是强烈认为须要过一遍源码。目录构造├── benchmarks 性能、基准测试├── dist 构建打包的输入目录├── examples 案例目录├── flow flow 语法的类型申明├── packages 一些额定的包,比方:负责服务端渲染的包 vue-server-renderer、配合 vue-loader 应用的的 vue-template-compiler,还有 weex 相干的│ ├── vue-server-renderer│ ├── vue-template-compiler│ ├── weex-template-compiler│ └── weex-vue-framework├── scripts 所有的配置文件的寄存地位,比方 rollup 的配置文件├── src vue 源码目录│ ├── compiler 编译器│ ├── core 运行时的外围包│ │ ├── components 全局组件,比方 keep-alive│ │ ├── config.js 一些默认配置项│ │ ├── global-api 全局 API,比方相熟的:Vue.use()、Vue.component() 等│ │ ├── instance Vue 实例相干的,比方 Vue 构造函数就在这个目录下│ │ ├── observer 响应式原理│ │ ├── util 工具办法│ │ └── vdom 虚构 DOM 相干,比方相熟的 patch 算法就在这儿│ ├── platforms 平台相干的编译器代码│ │ ├── web│ │ └── weex│ ├── server 服务端渲染相干├── test 测试目录├── types TS 类型申明Vue 初始化地位:/src/core/instance/index.js入口// Vue 的构造函数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') } // 在 /src/core/instance/init.js, // 1.初始化组件实例关系属性 // 2.自定义事件的监听 // 3.插槽和渲染函数 // 4.触发 beforeCreate 钩子函数 // 5.初始化 inject 配置项 // 6.初始化响应式数据,如 props, methods, data, computed, watch // 7.初始化解析 provide // 8.触发 created 钩子函数 this._init(options)}外围代码源码外围代码程序以深度遍历模式 ...

November 4, 2022 · 24 min · jiezi

关于vue.js:如何正确学习vue30源码

为什么要学源码技术是第一生产力学习 API 的设计目标、思路、取舍学习优良的代码格调学习组织代码的形式学习实现办法的技巧学习 ES67 新 API、TS 高级用法不给本人设限,不要让你四周人的技术下限成为你的下限面试加分项装逼利器学习源码副作用画虎不成反类犬(强行下马 vue3,本人焦头烂额、我的项目难以保护、共事苦不堪言)为了用而用,而不是就地取材喜爱炫技写一下看似搞大上,理论没有可读性,影响团队合作的奇技淫巧vue3 设计动机与目标更好的逻辑复用与代码组织 vue2 option api 的代码格调将同一逻辑点的代码扩散在各处,会导致读者关注点拆散,也不利于代码的逻辑复用;而 vue3 composition api 将同一业务逻辑的代码聚合在一起命名为 useXXX 函数,再通过 setup 将不同的逻辑组装起来并返回给组件 data,显著更不便逻辑复用。vue2 mixin 用于逻辑复用的时候容易导致命名抵触和数据起源不清晰;而 vue3 provide/inject 配合 composition api 能够很不便的找到数据起源并通过解构重命名,显著更不便逻辑复用。更好的类型推导 在 methods 中 this 指向组件实例而不是 method 自身,不利于类型推导。例如 this.router、this.store,每个新的插件都会须要向 Vue 追加类型定义。更新前后比照优化打包更小(全局 API tree-shaking)渲染、更新更快,内存占用缩小应用 proxy 取代 Object.definePropertyv-model 代替以前的 v-model 和.sync生命周期变更 例如 destroyed beforeDestroy 改为 unmounted beforeUnmount自定义指令 API 与生命周期保持一致Diff 算法的晋升(动态标记、动态晋升)新个性Template 反对多个根标签composition API 实现逻辑模块化和复用Teleport 传送门组件 代码块挂载到任意地位Suspense 悬停组件 异步加载组件应用(试验属性)应用 @vue/runtime-core 的 createRenderer 自定义渲染器(跨平台利器)应用 ts 编写源码,更好的类型推导、更好的适配 ts更多变动v3.cn.vuejs.org/guide/migra…疑难解答问题一:compostion api 基本没有解决任何问题,只是追赶新玩意的货色尤雨溪: 不批准这个观点。Vue 最开始很小,然而当初被广泛应用到不同级别复杂度的业务畛域,有些能够基于 option API 很轻松解决,然而有些不能够。例如上面的场景: ...

November 4, 2022 · 1 min · jiezi

关于vue.js:你可能需要的vue相关考点汇总

组件中写name属性的益处能够标识组件的具体名称不便调试和查找对应属性// 源码地位 src/core/global-api/extend.js// enable recursive self-lookupif (name) { Sub.options.components[name] = Sub // 记录本人 在组件中递归本人 -> jsx}Vuex中actions和mutations有什么区别题目剖析 mutations和actions是vuex带来的两个独特的概念。老手程序员容易混同,所以面试官喜爱问。咱们只需记住批改状态只能是mutations,actions只能通过提交mutation批改状态即可答复范例 更改 Vuex 的 store 中的状态的惟一办法是提交 mutation,mutation 十分相似于事件:每个 mutation 都有一个字符串的类型 (type)和一个 回调函数 (handler) 。Action 相似于 mutation,不同在于:Action能够蕴含任意异步操作,但它不能批改状态, 须要提交mutation能力变更状态开发时,蕴含异步操作或者简单业务组合时应用action;须要间接批改状态则提交mutation。但因为dispatch和commit是两个API,容易引起混同,实际中也会采纳对立应用dispatch action的形式。调用dispatch和commit两个API时简直齐全一样,然而定义两者时却不甚雷同,mutation的回调函数接管参数是state对象。action则是与Store实例具备雷同办法和属性的上下文context对象,因而个别会解构它为{commit, dispatch, state},从而不便编码。另外dispatch会返回Promise实例便于解决外部异步后果实现上commit(type)办法相当于调用options.mutations[type](state);dispatch(type)办法相当于调用options.actions[type](store),这样就很容易了解两者应用上的不同了实现 咱们能够像上面这样简略实现commit和dispatch,从而分别两者不同 class Store { constructor(options) { this.state = reactive(options.state) this.options = options } commit(type, payload) { // 传入上下文和参数1都是state对象 this.options.mutations[type].call(this.state, this.state, payload) } dispatch(type, payload) { // 传入上下文和参数1都是store自身 this.options.actions[type].call(this, this, payload) }}异步组件是什么?应用场景有哪些?剖析 因为异步路由的存在,咱们应用异步组件的次数比拟少,因而还是有必要两者的不同。 体验 ...

November 4, 2022 · 10 min · jiezi

关于vue.js:vue组件通信6种方式总结常问知识点

前言在Vue组件库开发过程中,Vue组件之间的通信始终是一个重要的话题,尽管官网推出的 Vuex 状态治理计划能够很好的解决组件之间的通信问题,然而在组件库外部应用 Vuex 往往会比拟重,本文将零碎的列举出几种不应用 Vuex,比拟实用的组件间的通信形式,供大家参考。 组件之间通信的场景在进入咱们明天的主题之前,咱们先来总结下Vue组件之间通信的几种场景,个别能够分为如下几种场景: 父子组件之间的通信兄弟组件之间的通信隔代组件之间的通信父子组件之间的通信父子组件之间的通信应该是 Vue 组件通信中最简略也最常见的一种了,概括为两个局部:父组件通过prop向子组件传递数据,子组件通过自定义事件向父组件传递数据。 父组件通过 prop 向子组件传递数据Vue组件的数据流向都遵循单向数据流的准则,所有的 prop 都使得其父子 prop 之间造成了一个单向上行绑定:父级 prop 的更新会向下流动到子组件中,然而反过来则不行。这样会避免从子组件意外变更父级组件的状态,从而导致你的利用的数据流向难以了解。 额定的,每次父级组件产生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件外部扭转 prop。如果你这样做了,Vue 会在浏览器的控制台中收回正告。 父组件 ComponentA: <template> <div> <component-b title="welcome"></component-b> </div></template><script>import ComponentB from './ComponentB'export default { name: 'ComponentA', components: { ComponentB }}</script>子组件 ComponentB: <template> <div> <div>{{title}}</div> </div></template><script>export default { name: 'ComponentB', props: { title: { type: String, } }} </script>子组件通过自定义事件向父组件传递数据在子组件中能够通过 $emit 向父组件产生一个事件,在父组件中通过 v-on/@ 进行监听。 子组件 ComponentA: <template> <div> <component-b :title="title" @title-change="titleChange"></component-b> </div></template><script>import ComponentB from './ComponentB'export default { name: 'ComponentA', components: { ComponentB }, data: { title: 'Click me' }, methods: { titleChange(newTitle) { this.title = newTitle } }}</script>子组件 ComponentB: ...

November 4, 2022 · 5 min · jiezi

关于vue.js:一大波vue面试题及答案精心整理

keep-alive 中的生命周期哪些keep-alive是 Vue 提供的一个内置组件,用来对组件进行缓存——在组件切换过程中将状态保留在内存中,避免反复渲染DOM。 如果为一个组件包裹了 keep-alive,那么它会多出两个生命周期:deactivated、activated。同时,beforeDestroy 和 destroyed 就不会再被触发了,因为组件不会被真正销毁。 当组件被换掉时,会被缓存到内存中、触发 deactivated 生命周期;当组件被切回来时,再去缓存里找这个组件、触发 activated钩子函数。 Vue组件如何通信?Vue组件通信的办法如下: props/$emit+v-on: 通过props将数据自上而下传递,而通过$emit和v-on来向上传递信息。EventBus: 通过EventBus进行信息的公布与订阅vuex: 是全局数据管理库,能够通过vuex治理全局的数据流$attrs/$listeners: Vue2.4中退出的$attrs/$listeners能够进行跨级的组件通信provide/inject:以容许一个先人组件向其所有子孙后代注入一个依赖,不管组件档次有多深,并在起上下游关系成立的工夫里始终失效,这成为了跨组件通信的根底还有一些用solt插槽或者ref实例进行通信的,应用场景过于无限就不赘述了。 vue和react的区别=> 相同点: 1. 数据驱动页面,提供响应式的试图组件2. 都有virtual DOM,组件化的开发,通过props参数进行父子之间组件传递数据,都实现了webComponents标准3. 数据流动单向,都反对服务器的渲染SSR4. 都有反对native的办法,react有React native, vue有wexx=> 不同点: 1.数据绑定:Vue实现了双向的数据绑定,react数据流动是单向的 2.数据渲染:大规模的数据渲染,react更快 3.应用场景:React配合Redux架构适宜大规模多人合作简单我的项目,Vue适宜小快的我的项目 4.开发格调:react举荐做法jsx + inline style把html和css都写在js了 vue是采纳webpack + vue-loader单文件组件格局,html, js, css同一个文件Vue模版编译原理晓得吗,能简略说一下吗?简略说,Vue的编译过程就是将template转化为render函数的过程。会经验以下阶段: 生成AST树优化codegen首先解析模版,生成AST语法树(一种用JavaScript对象的模式来形容整个模板)。 应用大量的正则表达式对模板进行解析,遇到标签、文本的时候都会执行对应的钩子进行相干解决。 Vue的数据是响应式的,但其实模板中并不是所有的数据都是响应式的。有一些数据首次渲染后就不会再变动,对应的DOM也不会变动。那么优化过程就是深度遍历AST树,依照相干条件对树节点进行标记。这些被标记的节点(动态节点)咱们就能够跳过对它们的比对,对运行时的模板起到很大的优化作用。 编译的最初一步是将优化后的AST树转换为可执行的代码。 参考:前端vue面试题具体解答 为什么在 Vue3.0 采纳了 Proxy,摈弃了 Object.defineProperty?Object.defineProperty 自身有肯定的监控到数组下标变动的能力,然而在 Vue 中,从性能/体验的性价比思考,尤大大就弃用了这个个性。为了解决这个问题,通过 vue 外部解决后能够应用以下几种办法来监听数组push();pop();shift();unshift();splice();sort();reverse();因为只针对了以上 7 种办法进行了 hack 解决,所以其余数组的属性也是检测不到的,还是具备肯定的局限性。 Object.defineProperty 只能劫持对象的属性,因而咱们须要对每个对象的每个属性进行遍历。Vue 2.x 里,是通过 递归 + 遍历 data 对象来实现对数据的监控的,如果属性值也是对象那么须要深度遍历,显然如果能劫持一个残缺的对象是才是更好的抉择。 ...

November 4, 2022 · 4 min · jiezi

关于vue.js:vue组件通信方式有哪些

vue组件通信形式一、props(父向子传值----自定义属性) / $emit(子向父传值----- 自定义事件)父组件通过props的形式向子组件传递数据,而通过$emit 子组件能够向父组件通信。 1. 父组件向子组件传值(props)上面通过一个例子阐明父组件如何向子组件传递数据:在子组件article.vue中如何获取父组件section.vue中的数据articles:['红楼梦', '西游记','三国演义'] // section父组件<template> <div class="section"> <com-article :articles="articleList"></com-article> </div></template><script>import comArticle from './test/article.vue'export default { name: 'HelloWorld', components: { comArticle }, data() { return { articleList: ['红楼梦', '西游记', '三国演义'] } }}</script>// 子组件 article.vue<template> <div> <span v-for="(item, index) in articles" :key="index">{{item}}</span> </div></template><script>export default { props: ['articles']}</script>留神: prop 能够从上一级组件传递到下一级组件(父子组件),即所谓的单向数据流。而且 prop 只读,不可被批改,强行批改能失效,然而控制台会有错误信息。 在子组件批改父组件传入的值的办法:1 .sync 父组件v-on绑定自定义属性时增加修饰符.sync 在子组件中通过调用emit(′update:自定义属性′,要批改的新值)==>emit('update:自定义属性',新值) 固定写法 此时子组件中接管的值就更新成了新值(父组件中的原始值会跟着变动,控制台不会报错) 父组件中: <child :value.sync='xxx'/> 子组件中: this.$emit('update:value',yyy) 2.在子组件data中申明本人的数据,让接管的数据作为这个数据的值 ==> 子组件的数据=this.value (这种办法理论批改的是本人的数据 父组件的数据没变) ...

November 4, 2022 · 4 min · jiezi

关于vue.js:Vue-Vuex状态管理

1.1 了解 Vuex1.1.1 Vuex 是什么概念:专门在 Vue 中实现集中式状态(数据)治理的一个 Vue 插件,对 Vue 利用中多个组件的共享状态进行集中式的治理(读/写),也是一种组件间通信的形式,且实用于任意组件间通信。Github地址1.1.2 什么时候应用 Vuex多个组件依赖于同一状态来自不同组件的行为须要变更同一状态1.1.3 Vuex 工作原理图<img src="https://vuex.vuejs.org/flow.png" alt="flow.png" style="zoom:67%;" /> 1.2 搭建 Vuex 环境与根本应用1.2.1 环境 Vuex 搭建创立文件:src/store/index.js //引入Vue外围库import Vue from 'vue'//引入Vueximport Vuex from 'vuex'//利用Vuex插件Vue.use(Vuex)//筹备actions对象——响应组件中用户的动作const actions = {}//筹备mutations对象——批改state中的数据const mutations = {}//筹备state对象——保留具体的数据const state = {}//创立并裸露storeexport default new Vuex.Store({ actions, mutations, state})在 main.js 中创立 vm 时传入 store 配置项 ......//引入storeimport store from './store' ...... //创立vm new Vue({ el:'#app', render: h => h(App), store })1.2.2 根本应用初始化数据、配置 actions、配置 mutations,操作文件 store.js ...

November 3, 2022 · 2 min · jiezi

关于vue.js:P6-vue-条件渲染-vif-vshow

v-if 简略实例<script>export default { data() { return { age: 6 }; },};</script><template> <div> <p v-if="age>18"> 我是成年人</p> <p v-if="age<=18"> 我是未成年人</p> </div></template><style></style> v-else v-else-if<script>export default { data() { return { age: 18 }; },};</script><template> <div> <p v-if="age>18"> 我是成年人</p> <p v-else-if="age==18">正好成年</p> <p v-else> 我是未成年人</p> </div></template><style></style>

November 2, 2022 · 1 min · jiezi

关于vue.js:vue中的相对和绝对路径的问题

有任何问题都能够留言征询。 相对路径但凡相对路径,都会被webpack解决。 以 . 结尾,都会作为一个绝对模块来解释。 比方:url(./test.png) 会被翻译为 require('./test.png')。 <img src="./test.png">// 就会被编译为:h('img', { attrs: { src: require('./test.png') }})绝对路径绝对路径,拜访的是public文件夹上面的动态资源。 留神,在public文件夹上面的动态资源,都会被简略的复制,而不是通过webpack解决。 比方页面http://localhost:8080/#/conso...中的连贯,代码如下所示: <a href="/bucket/test.csv" download>查看样例</a>此时,点击"查看样例",就会到根目录查找bucket目录和其下的test.csv文件。 但用绝对路径的时候,须要留神拜访门路的问题。 因为绝对路径,绝对的是拜访域名,而不包含门路。 比方当拜访的是: 详情 请查看原文。 https://mp.weixin.qq.com/s?__... 有问题可群征询:https://public-1253796280.cos...

November 2, 2022 · 1 min · jiezi

关于vue.js:vue实战中的一些小技巧

能让你首次加载更快的路由懒加载,怎么能忘?路由懒加载能够让咱们的包不须要一次把所有的页面的加载进来,只加载以后页面的路由组件就行。 举个,如果这样写,加载的时候会全副都加载进来。 const router = new VueRouter({ routes:[ { path: '/', name: 'Home', component: Home }, { path: '/about', name: 'About', component: About } ]})所以,应该防止下面的写法,尽量应用懒加载 懒加载写法,联合webpack的import食用 const router = new VueRouter({ routes:[ { path: '/', name: 'Home', component: () => import(/* webpackChunkName: "home" */ '../views/Home.vue') }, { path: '/about', name: 'About', component: () => import(/* webpackChunkName: "about" */ '../views/About.vue') } ]})你是否还记得有一个叫Object.freeze的办法?应该所有同学都晓得,vue初始化的时候会将data外面的数据都搞成响应式数据吧。然而,咱们在写业务逻辑的时候会有些数据一初始化就永远不会扭转,它基本就不须要被vue做成响应式数据,因而咱们应该将这些不必扭转的数据通过Object.freeze办法解冻它,防止vue初始化的时候,做一些无用的操作。 export default { data:()=>({ list:Object.freeze([{title:'我永远不须要扭转,我不须要响应式'}]) })}异步组件那么强,你是不是没用过?异步组件能够让咱们在须要一些组件时才将它加载进来,而不是一初始化就加载进来,这跟路由懒加载时一个概念。 ...

November 2, 2022 · 2 min · jiezi

关于vue.js:vue的几个提效技巧

1.动静组件 <component :is='组件名'></component>联合v-for循环应用应用环境 如图,这是一个v-for渲染的列表(只是目前这个版块才刚开始做,目前只有一个),圆圈内的就是一个组件,也就是要v-for动静组件 理论应用一开始就是根本的组件引入了 import ColorIn from '@/components/Magic/ColorIn.vue'import LineIn from "@/components/Magic/LineIn.vue";import LineIn from "@/components/Magic/Header.vue";import LineIn from "@/components/Magic/Footer.vue";export default{ components:{ ColorIn, LineIn, Header, Footer }}接下来就是动静v-for动静组件的应用,componentList:['ColorIn','LineIn','Header','Footer']应用上面的代码即可将代码顺次循环 <component v-for="(item,index) in componentList" :key="index" :is="item"></component>编译当前的成果就是 <ColorIn></ColorIn><LineIn></LineIn><Header></Header><Footer></Footer>2.watch进阶应用立刻执行应用环境例如场景为页面一进来就调用拉取列表数据getList(),而后监听路由的$route.query.id而后触发列表数据的更新 理论应用为了让它一开始就执行,咱们须要在created()生命周期中执行一次拉取数据的办法 watch:{ '$route.query.id':{ handle(){ this.getList(); }, }},created(){ this.getList();},然而应用immediate即可立刻执行,改写当前的代码如下 watch:{ '$route.query.id':{ handle(){ this.getList(); }, immediate:true }},深度监听应用环境在监听对象的时候,对象的外部属性发生变化watch无奈监听到,这种时候就须要应用深度监听 理论应用只须要设置deep:true即可开启深度监听 data(){ return{ queryList:{ count:0, name:'', } }},watch:{ queryList:{ handle(newValue,oldValue){ //do something }, deep:true }},计算属性之setter理论应用咱们个别平时应用的都是getter,但其实它还有个setter,当计算属性的fullName触发更新的时候,就会触发setter回调data(){ return{ firstName:'', lastName:'', }},computed:{ fullName:{ get(){ return `${this.firstName} ${this.lastName}`; }, set(newValue){ let names=newValue.split(' '); this.firstName=names[0]; this.lastName=names[1]; } }},$on('hook:生命周期')来简化window监听理论应用先来看一下平时的应用办法,参考vue实战视频解说:进入学习 ...

November 2, 2022 · 2 min · jiezi

关于vue.js:vue源码分析挂载流程和模板编译

后面几节咱们从new Vue创立实例开始,介绍了创立实例时执行初始化流程中的重要两步,配置选项的资源合并,以及响应式零碎的核心思想,数据代理。在合并章节,咱们对Vue丰盛的选项合并策略有了根本的认知,在数据代理章节咱们又对代理拦挡的意义和应用场景有了深刻的意识。依照Vue源码的设计思路,初始化过程还会进行很多操作,例如组件之间创立关联,初始化事件核心,初始化数据并建设响应式零碎等,并最终将模板和数据渲染成为dom节点。如果间接按流程的先后顺序剖析每个步骤的实现细节,会有很多概念很难了解。因而在这一章节,咱们先重点剖析一个概念,实例的挂载渲染流程。3.1 Runtime Only VS Runtime + Compiler在注释开始之前,咱们先理解一下vue基于源码构建的两个版本,一个是runtime only(一个只蕴含运行时的版本),另一个是runtime + compiler(一个同时蕴含编译器和运行时的版本)。而两个版本的区别仅在于后者蕴含了一个编译器。 什么是编译器,百度百科这样解释道: 简略讲,编译器就是将“一种语言(通常为高级语言)”翻译为“另一种语言(通常为低级语言)”的程序。一个古代编译器的次要工作流程:源代码 (source code) → 预处理器 (preprocessor) → 编译器 (compiler) → 指标代码 (object code) → 链接器 (Linker) → 可执行程序 (executables)。艰深点讲,编译器是一个提供了将源代码转化为指标代码的工具。从Vue的角度登程,内置的编译器实现了将template模板转换编译为可执行javascript脚本的性能。 3.1.1 Runtime + Compiler一个残缺的Vue版本是蕴含编译器的,咱们能够应用template进行模板编写。编译器会主动将模板字符串编译成渲染函数的代码,源码中就是render函数。如果你须要在客户端编译模板 (比方传入一个字符串给 template 选项,或挂载到一个元素上并以其 DOM 外部的 HTML 作为模板),就须要一个蕴含编译器的版本。 // 须要编译器的版本new Vue({ template: '<div>{{ hi }}</div>'})3.1.2 Runtime Only只蕴含运行时的代码领有创立Vue实例、渲染并解决Virtual DOM等性能,基本上就是除去编译器外的残缺代码。Runtime Only的实用场景有两种:1.咱们在选项中通过手写render函数去定义渲染过程,这个时候并不需要蕴含编译器的版本便可残缺执行。 // 不须要编译器new Vue({ render (h) { return h('div', this.hi) }})2.借助vue-loader这样的编译工具进行编译,当咱们利用webpack进行Vue的工程化开发时,经常会利用vue-loader对.vue进行编译,只管咱们也是利用template模板标签去书写代码,然而此时的Vue曾经不须要利用编译器去负责模板的编译工作了,这个过程交给了插件去实现。 很显著,编译过程对性能会造成肯定的损耗,并且因为退出了编译的流程代码,Vue代码的总体积也更加宏大(运行时版本相比完整版体积要小大概 30%)。因而在理论开发中,咱们须要借助像webpack的vue-loader这类工具进行编译,将Vue对模板的编译阶段合并到webpack的构建流程中,这样不仅缩小了生产环境代码的体积,也大大提高了运行时的性能,两全其美。 3.2 实例挂载的基本思路有了下面的根底,咱们回头看初始化_init的代码,在代码中咱们察看到initProxy后有一系列的函数调用,这些函数包含了创立组件关联,初始化事件处理,定义渲染函数,构建数据响应式零碎等,最初还有一段代码,在el存在的状况下,实例会调用$mount进行实例挂载。 Vue.prototype._init = function (options) { ··· // 选项合并 vm.$options = mergeOptions( resolveConstructorOptions(vm.constructor), options || {}, vm ); // 数据代理 initProxy(vm); vm._self = vm; initLifecycle(vm); // 初始化事件处理 initEvents(vm); // 定义渲染函数 initRender(vm); // 构建响应式零碎 initState(vm); // 等等 ··· if (vm.$options.el) { vm.$mount(vm.$options.el); }}以手写template模板为例,理分明什么是挂载。咱们会在选项中传递template为属性的模板字符串,如<div>{{message}}</div>,最终这个模板字符串通过两头过程将其转成实在的DOM节点,并挂载到选项中el代表的根节点上实现视图渲染。这个两头过程就是接下来要剖析的挂载流程。 ...

November 2, 2022 · 4 min · jiezi

关于vue.js:vue源码分析插槽原理

Vue组件的另一个重要概念是插槽,它容许你以一种不同于严格的父子关系的形式组合组件。插槽为你提供了一个将内容搁置到新地位或使组件更通用的进口。这一节将围绕官网对插槽内容的介绍思路,依照一般插槽,具名插槽,再到作用域插槽的思路,逐渐深刻外在的实现原理,有对插槽应用不相熟的,能够先参考官网对插槽的介绍。10.1 一般插槽插槽将<slot></slot>作为子组件承载散发的载体,简略的用法如下 10.1.1 根底用法var child = { template: `<div class="child"><slot></slot></div>`}var vm = new Vue({ el: '#app', components: { child }, template: `<div id="app"><child>test</child></div>`})// 最终渲染后果<div class="child">test</div>10.1.2 组件挂载原理插槽的原理,贯通了整个组件零碎编译到渲染的过程,所以首先须要回顾一下对组件相干编译渲染流程,简略总结一下几点: 从根实例动手进行实例的挂载,如果有手写的render函数,则间接进入$mount挂载流程。只有template模板则须要对模板进行解析,这里分为两个阶段,一个是将模板解析为AST树,另一个是依据不同平台生成执行代码,例如render函数。$mount流程也分为两步,第一步是将render函数生成Vnode树,子组件会以vue-componet-为tag标记,另一步是把Vnode渲染成真正的DOM节点。创立实在节点过程中,如果遇到子的占位符组件会进行子组件的实例化过程,这个过程又将回到流程的第一步。接下来咱们对slot的剖析将围绕这四个具体的流程开展,对组件流程的详细分析,能够参考深刻分析Vue源码 - 组件根底大节。 10.1.3 父组件解决回到组件实例流程中,父组件会优先于子组件进行实例的挂载,模板的解析和render函数的生成阶段在解决上没有非凡的差别,这里就不开展剖析。接下来是render函数生成Vnode的过程,在这个阶段会遇到子的占位符节点(即:child),因而会为子组件创立子的Vnode。createComponent执行了创立子占位节点Vnode的过程。咱们把重点放在最终Vnode代码的生成。 // 创立子Vnode过程 function createComponent ( Ctor, // 子类结构器 data, context, // vm实例 children, // 父组件须要散发的内容 tag // 子组件占位符 ){ ··· // 创立子vnode,其中父保留的children属性会以选项的模式传递给Vnode var vnode = new VNode( ("vue-component-" + (Ctor.cid) + (name ? ("-" + name) : '')), data, undefined, undefined, undefined, context, { Ctor: Ctor, propsData: propsData, listeners: listeners, tag: tag, children: children }, asyncFactory ); }// Vnode结构器var VNode = function VNode (tag,data,children,text,elm,context,componentOptions,asyncFactory) { ··· this.componentOptions = componentOptions; // 子组件的选项相干}createComponent函数接管的第四个参数children就是父组件须要散发的内容。在创立子Vnode过程中,会以会componentOptions配置传入Vnode结构器中。最终Vnode中父组件须要散发的内容以componentOptions属性的模式存在,这是插槽剖析的第一步。 ...

November 2, 2022 · 5 min · jiezi

关于vue.js:vue源码分析渲染过程

继上一节内容,咱们将Vue简单的挂载流程通过图解流程,代码剖析的形式简略梳理了一遍,最初也讲到了模板编译的大抵流程。然而在挂载的外围处,咱们并没有剖析模板编译后渲染函数是如何转换为可视化DOM节点的。因而这一章节,咱们将从新回到Vue实例挂载的最初一个环节:渲染DOM节点。在渲染实在DOM的过程中,Vue引进了虚构DOM的概念,这是Vue架构设计中另一个重要的理念。虚构DOM作为JS对象和实在DOM两头的一个缓冲层,对JS频繁操作DOM的引起的性能问题有很好的缓解作用。4.1 Virtual DOM4.1.1 浏览器的渲染流程当浏览器接管到一个Html文件时,JS引擎和浏览器的渲染引擎便开始工作了。从渲染引擎的角度,它首先会将html文件解析成一个DOM树,与此同时,浏览器将辨认并加载CSS款式,并和DOM树一起合并为一个渲染树。有了渲染树后,渲染引擎将计算所有元素的地位信息,最初通过绘制,在屏幕上打印最终的内容。JS引擎和渲染引擎尽管是两个独立的线程,然而JS引擎却能够触发渲染引擎工作,当咱们通过脚本去批改元素地位或外观时,JS引擎会利用DOM相干的API办法去操作DOM对象,此时渲染引擎变开始工作,渲染引擎会触发回流或者重绘。上面是回流重绘的两个概念: 回流: 当咱们对DOM的批改引发了元素尺寸的变动时,浏览器须要从新计算元素的大小和地位,最初将从新计算的后果绘制进去,这个过程称为回流。重绘: 当咱们对DOM的批改只单纯扭转元素的色彩时,浏览器此时并不需要从新计算元素的大小和地位,而只有从新绘制新款式。这个过程称为重绘。很显然回流比重绘更加消耗性能。 通过理解浏览器根本的渲染机制,咱们很容易联想到当一直的通过JS批改DOM时,不经意间会触发到渲染引擎的回流或者重绘,这个性能开销是十分微小的。因而为了升高开销,咱们须要做的是尽可能减少DOM操作。有什么办法能够做到呢? 4.1.2 缓冲层-虚构DOM虚构DOM是为了解决频繁操作DOM引发性能问题的产物。虚构DOM(上面称为Virtual DOM)是将页面的状态形象为JS对象的模式,实质上是JS和实在DOM的中间层,当咱们想用JS脚本大批量进行DOM操作时,会优先作用于Virtual DOM这个JS对象,最初通过比照将要改变的局部告诉并更新到实在的DOM。只管最终还是操作实在的DOM,但Virtual DOM能够将多个改变合并成一个批量的操作,从而缩小 DOM 重排的次数,进而缩短了生成渲染树和绘制所花的工夫。 咱们看一个实在的DOM蕴含了什么: 浏览器将一个实在DOM设计得很简单,不仅蕴含了本身的属性形容,大小地位等定义,也囊括了DOM领有的浏览器事件等。正因为如此简单的构造,咱们频繁去操作DOM或多或少会带来浏览器的性能问题。而作为数据和实在DOM之间的一层缓冲,Virtual DOM 只是用来映射到实在DOM的渲染,因而不须要蕴含操作 DOM 的办法,它只有在对象中重点关注几个属性即可。 // 实在DOM<div id="real"><span>dom</span></div>// 实在DOM对应的JS对象{ tag: 'div', data: { id: 'real' }, children: [{ tag: 'span', children: 'dom' }]}4.2 VnodeVue在渲染机制的优化上,同样引进了virtual dom的概念,它是用Vnode这个构造函数去形容一个DOM节点。 4.2.1 Vnode构造函数var VNode = function VNode (tag,data,children,text,elm,context,componentOptions,asyncFactory) { this.tag = tag; // 标签 this.data = data; // 数据 this.children = children; // 子节点 this.text = text; ··· ··· };Vnode定义的属性差不多有20几个,显然用Vnode对象要比实在DOM对象形容的内容要简略得多,它只用来单纯形容节点的要害属性,例如标签名,数据,子节点等。并没有保留跟浏览器相干的DOM办法。除此之外,Vnode也会有其余的属性用来扩大Vue的灵活性。 ...

November 2, 2022 · 4 min · jiezi

关于vue.js:Vue的computed和watch的区别是什么

一、computed介绍computed 用来监控本人定义的变量,该变量在 data 内没有申明,间接在 computed 外面定义,页面上可间接应用。 //根底应用{{msg}}<input v-model="name" /> //计算属性 computed:{ msg:function(){ return this.name }}在输入框中,扭转 name 值得时候,msg 也会跟着扭转。这是因为 computed 监听本人的属性 msg,发现 name 一旦变动,msg 立马会更新。 留神:msg 不可在 data 中定义,否则会报错。 1.1、get 和 set 用法 <input v-model="full" ><br><input v-model="first" > <br><input v-model="second" > data(){ return{ first:'美女', second:'姐姐' }},computed:{ full:{ get(){ //回调函数 当须要读取以后属性值是执行,依据相干数据计算并返回以后属性的值 return this.first + ' ' + this.second }, set(val){ //监督以后属性值的变动,当属性值发生变化时执行,更新相干的属性数据 let names = val.split(' ') this.first = names[0] this.second = names[1] } }}get 办法:first 和 second 扭转时,会调用 get 办法,更新 full 的值。 ...

November 2, 2022 · 2 min · jiezi

关于vue.js:一文搞定Vue面试

你有对 Vue 我的项目进行哪些优化?(1)代码层面的优化 v-if 和 v-show 辨别应用场景computed 和 watch 辨别应用场景v-for 遍历必须为 item 增加 key,且防止同时应用 v-if长列表性能优化事件的销毁图片资源懒加载路由懒加载第三方插件的按需引入优化有限列表性能服务端渲染 SSR or 预渲染(2)Webpack 层面的优化 Webpack 对图片进行压缩缩小 ES6 转为 ES5 的冗余代码提取公共代码模板预编译提取组件的 CSS优化 SourceMap构建后果输入剖析Vue 我的项目的编译优化(3)根底的 Web 技术的优化 开启 gzip 压缩浏览器缓存CDN 的应用应用 Chrome Performance 查找性能瓶颈Vuex中action和mutation的区别mutation中的操作是一系列的同步函数,用于批改state中的变量的的状态。当应用vuex时须要通过commit来提交须要操作的内容。mutation 十分相似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是理论进行状态更改的中央,并且它会承受 state 作为第一个参数: const store = new Vuex.Store({ state: { count: 1 }, mutations: { increment (state) { state.count++ // 变更状态 } }})当触发一个类型为 increment 的 mutation 时,须要调用此函数: ...

November 2, 2022 · 9 min · jiezi

关于vue.js:new-Vue的时候到底做了什么

Vue加载流程1.初始化的第一阶段是Vue实例也就是vm对象创立前后:首先Vue进行生命周期,事件初始化产生在beforeCreate生命周期函数前,而后进行数据监测和数据代理的初始化,也就是创立vm对象的过程,当vm对象创立实现就能够通过vm对象拜访到劫持的数据,比方data中的数据,methods中的办法等。而后Vue调用外部的render函数开始解析模板将其解析为一个JS对象也即在内存中生成虚构DOM也就是Vnode对象。第二阶段是vm对象挂载前后:挂载实现前页面出现的是未通过Vue编译的DOM构造,所有对DOM的操作最终都不会失效。挂载前首先将内存中的Vnode转换为实在DOM插入页面,此时实现挂载。页面中出现的就是通过Vue编译的DOM构造,至此初始化过程完结。 2.开启订阅音讯也就是数据劫持代理监听,其实就是写了一个watcher函数去监听数据的扭转,发送网络申请,绑定自定义事件等初始化操作。当数据发生变化当前即状态变更的时候,会从新结构新的Vnode对象。而后用新的Vnode对象和旧的Vnode对象进行差别比拟也就是DIFF算法,而后把差别利用到旧的Vnode对象所构建的真正的DOM树上这个过程就是patch,视图就更新了 每一个组件在加载时都会调用Vue外部的render函数把该组件的tamplate选项的模板解析为一个JS对象,这个对象和DOM节点对象构造一样,而后是数据劫持代理监听,当数据发生变化当前,将旧Vnode对象和生成的新Vnode对象比拟差别而后更新DOM Vnode: {tag:"", id:, name:"Box", $el:实在页面上的DOM的援用, //等等属性 chiren:[ { tag:"", id:, name:"Box2",$el:实在页面上的DOM的援用, //等等属性 }, { tag:"", id:, name:"Box3",$el:实在页面上的DOM的援用,//等等属性 }] } 什么是DIFFdiff算法是一种比照算法。比照两者是旧虚构DOM和新虚构DOM,比照出是哪个虚构节点更改了,找出这个虚构节点,并只更新这个虚构节点所对应的实在节点,而不必更新其余数据没产生扭转的节点,实现精准地更新实在DOM,进而提高效率 其有两个特点: 比拟只会在同层级进行, 不会跨层级比拟在diff比拟的过程中,循环从两边向两头比拟参考:前端vue面试题具体解答 DIFF算法的过程: 当数据产生扭转时,订阅者watcher就会调用patch给实在的DOM打补丁通过isSameVnode进行判断,雷同则调用patchVnode办法patchVnode做了以下操作: 找到对应的实在dom,称为el如果都有都有文本节点且不相等,将el文本节点设置为Vnode的文本节点如果oldVnode有子节点而VNode没有,则删除el子节点如果oldVnode没有子节点而VNode有,则将VNode的子节点实在化后增加到el如果两者都有子节点,则执行updateChildren函数比拟子节点updateChildren次要做了以下操作: 设置新旧VNode的头尾指针新旧头尾指针进行比拟,循环向两头聚拢,依据状况调用patchVnode进行patch反复流程、调用createElem创立一个新节点,从哈希表寻找 key统一的VNode 节点再分状况操作 对于Vue中el,template,render,$mount的渲染渲染根节点: 先判断有无el属性,有的话间接获取el根节点,没有的话调用$mount去获取根节点。渲染模板: 有render:这时候优先执行render函数,render优先级 > template。无render:有template时拿template去解析成render函数的所需的格局,并应用调用render函数渲染。无template时拿el根节点的outerHTML去解析成render函数的所需的格局,并应用调用render函数渲染渲染的形式:无论什么状况,最初都对立是要应用render函数渲染

November 2, 2022 · 1 min · jiezi

关于vue.js:vue3-实现-亚克力材质

如何设计 Acrylic咱们微调 Acrylic 的要害组件以凸显其独特外观和属性。 咱们从半透明度、含糊和噪点设置开始,为平滑图面削减视觉深度和维度。 咱们增加了排除混合模式层,以确保搁置在 Acrylic 背景上的 UI 的对比度和可读性。 最初,咱们增加了各种色彩色调,以供用户进行个性化设置。 这些图层协同作用,造成了全新的实用资料。 Demohttps://huodoushigemi.github.... 须要环境Chorme 76+Vue 3+⚙️ 装置 npm i -S vue-acrylic 在 JS 中应用<h1 id="acrylic1">ACRYLIC</h1><h1 id="acrylic2">ACRYLIC</h1><script> import { useAcrylic } from 'vue-acrylic' const options1 = { bulr: 20, noiseOpacity: 1, noiseSize: 50 } useAcrylic(document.getElementById('acrylic1')) useAcrylic(document.getElementById('acrylic2'), options1)</script> 在 Vue 中应用import { createApp } from 'vue'import Acrylic from 'vue-acrylic'import App from './App.vue'createApp(App).use(Acrylic).mount('#app')<script setup> const opt = { bulr: 20, noiseOpacity: 1, noiseSize: 50 }</script><template> <div v-acrylic>Acrylic</div> <div v-acrylic="opt">Acrylic</div></template> 选项你能够抉择在利用的 Acrylic 中增加色彩色调,以展现个性化设计或实现与页面其余元素之间的视觉均衡。 若要显示色彩而非灰度,你须要应用以下属性定义属于你本人的 Acrylic 画笔。 ...

November 1, 2022 · 1 min · jiezi

关于vue.js:vue3实战完全掌握refreactive

晓得大家应用 Vue3 的时候有没有这样的纳闷,“ref、rective 都能创立一个响应式对象,我该如何抉择?”,“为什么响应式对象解构之后就失去了响应式?应该如何解决?” 明天咱们就来全面盘点一下 ref、reactive,置信看完你肯定会有不一样的播种,一起学起来吧! reactive()根本用法在 Vue3 中咱们能够应用 reactive() 创立一个响应式对象或数组: import { reactive } from 'vue'const state = reactive({ count: 0 })这个响应式对象其实就是一个 Proxy, Vue 会在这个 Proxy 的属性被拜访时收集副作用,属性被批改时触发副作用。 要在组件模板中应用响应式状态,须要在 setup() 函数中定义并返回。 <script>import { reactive } from 'vue'export default { setup() { const state = reactive({ count: 0 }) return { state } }}</script><template> <div>{{ state.count }}</div></template>当然,也能够应用 <script setup> ,<script setup> 中顶层的导入和变量申明能够在模板中间接应用。 <script setup>import { reactive } from 'vue'const state = reactive({ count: 0 })</script><template> <div>{{ state.count }}</div></template>响应式代理 vs 原始对象reactive() 返回的是一个原始对象的 Proxy,他们是不相等的: ...

November 1, 2022 · 5 min · jiezi

关于vue.js:vue中的几个高级概念

混入mixins官网解释混入 (mixin) 提供了一种非常灵活的形式,来散发 Vue 组件中的可复用性能。一个混入对象能够蕴含任意组件选项。当组件应用混入对象时,所有混入对象的选项将被“混合”进入该组件自身的选项。简略的来说就是 Mixins 是咱们能够重用的代码块,在理论开发中,如果有些代码重复性比拟高,这时候能够思考 Mixins 这个个性。 简略的mixin示例 export default { data() { return { name: '来自mixin的name', arr: [ 1, { arrName: '来自mixin', arrMixin: '来自mixin' }, 1233 ], obj: { name: '来自mixin', value: '来自mixin', mixin: '只有mixin才有的字段' } } }, created() { console.log('我是mixin的created---') }, mounted() { console.log('我是mixin的mounted---') this.getInfo() }, methods: { getInfo() { console.log('我是mixin, getInfo:', this.name) console.log('我是mixin的obj:', this.obj) console.log('我是mixin的arr:', this.arr) } }}组件中应用 import mixinDemo from './mixin.js'export default { name: '', mixins: [mixinDemo], components: {}, data() { return { name: '组件中的name', arr: [ 2, { arrName: '来自组件的arrName', title: '来自组件的独有字段title' } ], obj: { name: '来自组件name', value: '来自组件value', title: '只有组件才有的title字段' } } }, computed: {}, watch: {}, created() { console.log('---我是组件的created---') }, mounted() { console.log('---我是组件的mounted---') this.getInfo() }, methods: { getInfo() { console.log('我是组件的, getInfo:', this.name) console.log('我是组件的obj:', this.obj) console.log('我是组件的arr:', this.arr) } }}控制台后果 ...

November 1, 2022 · 3 min · jiezi

关于vue.js:vue实战完全掌握Vue自定义指令

筹备:自定义指令介绍除了外围性能默认内置的指令 (v-model 和 v-show等),Vue 也容许注册自定义指令。留神,在 Vue2.0 中,代码复用和形象的次要模式是组件。然而,有的状况下,你依然须要对一般 DOM 元素进行底层操作,这时候就会用到自定义指令。 ———Vue官网 作为应用Vue的开发者,咱们对Vue指令肯定不生疏,诸如v-model、v-on、v-for、v-if等,同时Vue也为开发者提供了自定义指令的api,纯熟的应用自定义指令能够极大的进步了咱们编写代码的效率,让咱们能够节省时间开心的摸鱼~ 对于Vue的自定义指令置信很多同学曾经有所理解,自定义指令的具体写法这里就不细讲了,官网文档很具体。 然而不晓得各位同学有没有这种感觉,就是这个技术感觉很不便,也不难,我也感觉学会了,就是不晓得如何去利用。这篇文档就是为了解决一些同学的这些问题才写进去的。 PS:这次要讲的自定义指令咱们次要应用的是vue2.x的写法,不过vue3.x不过是几个钩子函数有所扭转,只有了解每个钩子函数的含意,两者的用法差异并不大。 试炼:实现v-mymodel我的上篇文章说到要本人实现一个v-model指令,这里应用v-myodel模仿一个简易版的,顺便再领不相熟的同学相熟一下自定义指令的步骤和注意事项。 定义指令首先梳理思路:原生input控件与组件的实现形式须要辨别,input的实现较为简单,咱们先实现一下input的解决。首先咱们先定义一个不做任何操作的指令 Vue.directive('mymodel', { //只调用一次,指令第一次绑定到元素时调用。在这里能够进行一次性的初始化设置。 bind(el, binding, vnode, oldVnode) { }, //被绑定元素插入父节点时调用 (仅保障父节点存在,但不肯定已被插入文档中),须要父节点dom时应用这个钩子 inserted(el, binding, vnode, oldVnode) { }, //所在组件的 VNode 更新时调用,**然而可能产生在其子 VNode 更新之前**。指令的值可能产生了扭转,也可能没有。然而你能够通过比拟更新前后的值来疏忽不必要的模板更新 (具体的钩子函数参数见下)。 update(el, binding, vnode, oldVnode) { }, //指令所在组件的 VNode **及其子 VNode** 全副更新后调用。 componentUpdated(el, binding, vnode, oldVnode) { }, 只调用一次,指令与元素解绑时调用。 unbind(el, binding, vnode, oldVnode) { },})下面的正文中具体的阐明了各个钩子函数的调用机会,因为咱们是给组件上增加input事件和value绑定,因而咱们在bind这个钩子函数中定义即可。所以咱们把其余的先去掉,代码变成这样。 Vue.directive('mymodel', { //只调用一次,指令第一次绑定到元素时调用。在这里能够进行一次性的初始化设置。 bind(el, binding, vnode, oldVnode) { }})简略说一下bind函数的几个回调参数,el是指令绑定组件对应的dom,binding是咱们的指令自身,蕴含name、value、expression、arg等,vnode就是以后绑定组件对应的vnode结点,oldVnode就是vnode更新前的状态。 ...

November 1, 2022 · 4 min · jiezi

关于vue.js:vue源码分析响应式系统二

为了深刻介绍响应式零碎的外部实现原理,咱们花了一整节的篇幅介绍了数据(包含data, computed,props)如何初始化成为响应式对象的过程。有了响应式数据对象的常识,上一节的后半局部咱们还在保留源码构造的根底上构建了一个以data为数据的响应式零碎,而这一节,咱们持续深刻响应式零碎外部构建的细节,详细分析Vue在响应式零碎中对data,computed的解决。7.8 相干概念在构建繁难式响应式零碎的时候,咱们引出了几个重要的概念,他们都是响应式原理设计的外围,咱们先简略回顾一下: Observer类,实例化一个Observer类会通过Object.defineProperty对数据的getter,setter办法进行改写,在getter阶段进行依赖的收集,在数据产生更新阶段,触发setter办法进行依赖的更新watcher类,实例化watcher类相当于创立一个依赖,简略的了解是数据在哪里被应用就须要产生了一个依赖。当数据产生扭转时,会告诉到每个依赖进行更新,后面提到的渲染wathcer便是渲染dom时应用数据产生的依赖。Dep类,既然watcher了解为每个数据须要监听的依赖,那么对这些依赖的收集和告诉则须要另一个类来治理,这个类便是Dep,Dep须要做的只有两件事,收集依赖和派发更新依赖。这是响应式零碎构建的三个根本外围概念,也是这一节的根底,如果还没有印象,请先回顾上一节对极简风响应式零碎的构建。 7.9 data7.9.1 问题思考在开始剖析data之前,咱们先抛出几个问题让读者思考,而答案都蕴含在接下来内容分析中。 后面曾经晓得,Dep是作为治理依赖的容器,那么这个容器在什么时候产生?也就是实例化Dep产生在什么时候?Dep收集了什么类型的依赖?即watcher作为依赖的分类有哪些,别离是什么场景,以及区别在哪里?Observer这个类具体对getter,setter办法做了哪些事件?手写的watcher和页面数据渲染监听的watch如果同时监听到数据的变动,优先级怎么排?有了依赖的收集是不是还有依赖的解除,依赖解除的意义在哪里?带着这几个问题,咱们开始对data的响应式细节开展剖析。 7.9.2 依赖收集data在初始化阶段会实例化一个Observer类,这个类的定义如下(疏忽数组类型的data): // initData function initData(data) { ··· observe(data, true)}// observefunction observe(value, asRootData) { ··· ob = new Observer(value); return ob}// 观察者类,对象只有设置成领有察看属性,则对象下的所有属性都会重写getter和setter办法,而getter,setting办法会进行依赖的收集和派发更新var Observer = function Observer (value) { ··· // 将__ob__属性设置成不可枚举属性。内部无奈通过遍历获取。 def(value, '__ob__', this); // 数组解决 if (Array.isArray(value)) { ··· } else { // 对象解决 this.walk(value); } };function def (obj, key, val, enumerable) { Object.defineProperty(obj, key, { value: val, enumerable: !!enumerable, // 是否可枚举 writable: true, configurable: true });}Observer会为data增加一个__ob__属性, __ob__属性是作为响应式对象的标记,同时def办法确保了该属性是不可枚举属性,即外界无奈通过遍历获取该属性值。除了标记响应式对象外,Observer类还调用了原型上的walk办法,遍历对象上每个属性进行getter,setter的改写。 ...

November 1, 2022 · 6 min · jiezi

关于vue.js:vue源码分析响应式系统工作原理

上一章,咱们讲到了Vue初始化做的一些操作,那么咱们这一章来讲一个Vue外围概念响应式零碎。咱们先来看一下官网对深刻响应式零碎的解释: 当你把一个一般的 JavaScript 对象传给 Vue 实例的 data 选项,Vue 将遍历此对象所有的属性。并应用 Object.defineProperty 把这些属性全副转为 getter/setter。Object.defineProperty 是 ES5 中一个无奈 shim 的个性。这也就是为什么 Vue 不反对 IE8 以及更低版本浏览器的起因。 上图是Vue官网放出的一张图,而且提到外围概念Object.defineProperty,那么咱们间接看源码,咱们看到的Object.defineProperty在defineReactive函数的外部,而defineReactive函数在walk函数外部,顺次找到源头是Observer类 ./core/observer/indexexport class Observer { value: any; dep: Dep; vmCount: number; // number of vms that has this object as root $data /** * 生成的Observer实例上挂载三个属性 * 1. value, 即观测数据对象自身 * 2. dep, 用于依赖收集的容器 * 3. vmCount, 间接写死为0 */ constructor (value: any) { this.value = value this.dep = new Dep() this.vmCount = 0 // 在观测数据对象上增加__ob__属性, 是Observer实例的援用 // def相当于Object.defineProperty, 区别是dep里会把__ob__属性设置为不可枚举 // 须要留神的是, value.__ob__.value 显然就是 value 自身, 这里有一个循环援用 def(value, '__ob__', this) if (Array.isArray(value)) { const augment = hasProto ? protoAugment : copyAugment augment(value, arrayMethods, arrayKeys) this.observeArray(value) } else { this.walk(value) } } // 用于解决对象类型的观测值, 循环所有的key都调用一次defineReactive walk (obj: Object) { const keys = Object.keys(obj) for (let i = 0; i < keys.length; i++) { defineReactive(obj, keys[i]) } } // 对数组的每一项进行监听 observeArray (items: Array<any>) { for (let i = 0, l = items.length; i < l; i++) { observe(items[i]) } }}value是须要被察看的数据对象,在构造函数中,会给value减少ob属性,作为数据曾经被Observer察看的标记。如果value是数组,就应用observeArray遍历value,对value中每一个元素调用observe别离进行察看。如果value是对象,则应用walk遍历value上每个key,对每个key调用defineReactive来取得该key的set/get控制权。 ...

November 1, 2022 · 6 min · jiezi