Cet article résume et partage quelques questions d'entretien Vue (avec analyse des réponses) pour vous aider à trier les connaissances de base et à améliorer votre réserve de connaissances Vue. Cela vaut la peine d'être collecté, venez y jeter un œil !
(Partage de vidéos d'apprentissage : Tutoriel vidéo Vue)
Classes d'implémentation de base :
Observateur : son rôle est d'ajouter des getters et des setters aux propriétés de l'objet pour la collecte des dépendances et la distribution des mises à jour. Dep : utilisé pour collecter les dépendances de l'objet réactif actuel, y compris les sous-objets, possède une instance Dep (. (les sous-marins à l'intérieur se trouvent un tableau d'instances de Watcher). Lorsque les données changent, chaque observateur sera averti via dep.notify().
Watcher : Objet Observer, l'instance est divisée en trois types : observateur de rendu (observateur de rendu), observateur d'attribut calculé (observateur calculé), observateur d'écoute (observateur utilisateur)
La relation entre Watcher et Dep : l'observateur est instancié dep et ajouté des abonnés à dep.subs, dep a parcouru dep.subs via notify pour notifier chaque mise à jour de l'observateur.
Collection de dépendances : Lorsque l'attribut calculé est initialisé pendant initState, la collection de dépendances de l'observateur calculée est déclenchée.
Lorsque l'attribut initState est initialisé, la collection de dépendances de l'observateur utilisateur est déclenchée.
Le processus de render() déclenche l'observateur de rendu. collection de dépendances
Lors du nouveau rendu, vm.render() est à nouveau exécuté et les abonnements de l'observateur dans tous les sous-marins seront supprimés et réaffectés.
Distribuer les mises à jour : Les données de réponse sont modifiées dans le composant, déclenchant la logique du setter
Appelez dep.notify()
Parcourez tous les sous-marins (instances Watcher) et appelez la méthode de mise à jour de chaque observateur.
Principe : Lors de la création d'une instance Vue, Vue parcourra les propriétés de l'option data et utilisera Object.defineProperty pour ajouter des getters et des setters aux propriétés afin de détourner la lecture des données (les getters sont utilisés pour s'appuyer sur la collection, et les setters sont utilisés pour distribuer les mises à jour) et suivre les dépendances en interne, notifiant les changements lorsque les propriétés sont consultées et modifiées.
Chaque instance de composant aura une instance d'observateur correspondante, qui enregistrera tous les attributs de données de la dépendance pendant le processus de rendu du composant (collecte de dépendances, observateur calculé, instances d'observateur utilisateur). Lorsque la dépendance est modifiée ultérieurement, la méthode de définition vous avertira. l'instance d'observateur qui dépend de ces données pour recalculer (distribuer les mises à jour), restituant ainsi ses composants associés.
Résumé en une phrase : vue.js utilise le piratage de données combiné au modèle de publication-abonnement et utilise Object.defineproperty pour
détourner les setters et getters de chaque propriété, publier des messages aux abonnés lorsque les données changent et déclencher les rappels de surveillance des réponses
Facile à utiliser : simple, facile à apprendre, rapide à démarrerFlexible : (Progressif) Un écosystème en croissance qui peut évoluer librement entre une bibliothèque et un cadre complet.
Efficace : taille d'exécution de 20 Ko min + gzip ; DOM virtuel ultra-rapide ; optimisation sans souci
Liaison bidirectionnelle : haute efficacité de développement
Partage de code basé sur les composants
Ingénierie de projets Web, augmentant la lisibilité et la maintenabilité
Vue.js 2.0 utilise le détournement de données (mode Proxy) combiné au mode éditeur-abonné (mode PubSub) pour détourner chaque objet individuel via Object.defineProperty() Le setter de la propriété. et le getter publie des messages aux abonnés lorsque les données changent, déclenchant les rappels d'écoute correspondants.Vue.js 3.0, abandonné Object.defineProperty et utilisé le proxy natif ES6 plus rapide (intercepteur d'objet d'accès, également appelé proxy) Étapes :Chaque instance de composant a une instance de programme d'observation correspondante. Il enregistrera les propriétés en tant que dépendances pendant le processus de rendu du composant. Plus tard, lorsque le paramètre de la dépendance sera appelé, l'observateur sera averti de recalculer, provoquant ainsi ses composants associés. à renouveler.
1. L'objet de données qui doit être observé est parcouru de manière récursive, y compris les attributs de l'objet sous-attribut, et des setters et des getters sont ajoutés si une valeur est attribuée à cet objet, le setter sera déclenché, puis. les modifications des données peuvent être surveillées.
2.compile analyse les instructions du modèle, remplace les variables du modèle par des données, puis initialise la vue de la page de rendu, lie la fonction de mise à jour au nœud correspondant à chaque instruction et ajoute des abonnés pour surveiller le data.Une fois les données modifiées, elles seront reçues Notification, mise à jour de la vue
3. L'abonné Watcher est le pont de communication entre Observer et Compile. Les principales choses qu'il fait sont : ① S'ajouter à l'attribut abonné (dep) lorsqu'il l'est. instancié. ② Il doit avoir une méthode update() ③ Lorsque vous êtes averti par dep.notice() des changements d'attribut, vous pouvez appeler votre propre méthode update() et déclencher le rappel lié dans Compile, alors vous aurez terminé.
4. Comme entrée dans la liaison de données, MVVM intègre Observer, Compile et Watcher. Il utilise Observer pour surveiller les modifications de ses propres données de modèle, utilise Compile pour analyser et compiler les instructions du modèle, et enfin utilise Watcher pour établir la communication entre Observer et Compilez. Bridge pour obtenir l'effet de liaison bidirectionnelle de la modification des données -> mise à jour de la vue ; vue de la modification interactive (entrée) -> modification du modèle de données.
Par exemple, nous devons maintenant surveiller les changements d'obj.a dans les données. Vous pouvez surveiller les changements dans les attributs des objets dans Vue comme ceci :
watch: { obj: { handler (newValue, oldValue) { console.log('obj changed') }, deep: true }
L'attribut deep représente une traversée profonde, mais écrire de cette façon surveillera tous les changements d'attributs de obj, ce qui n'est pas l'effet que nous souhaitons, alors apportez quelques modifications :
watch: { 'obj.a': { handler (newName, oldName) { console.log('obj.a changed') } } }
Il existe une autre façon La méthode peut être implémentée via calculé, ce qui nécessite seulement :
computed: { a1 () { return this.obj.a } }
En utilisant les caractéristiques des attributs calculés pour implémenter, lorsque la dépendance change, une nouvelle valeur sera recalculée.
Défauts Object.defineProperty
1. La surveillance des modifications dans les indices du tableau est très coûteuse. Vue.js a donc abandonné la détection des changements d'indice ;
2.Object.defineProperty ne peut détourner que les propriétés de l'objet, alors que Proxy est un objet proxy direct. 3.Object.defineProperty doit parcourir chaque propriété de l'objet. Si la valeur de la propriété est également un objet, une traversée approfondie est requise. Le proxy proxy directement les objets et ne nécessite pas d'opérations de traversée.
4. Object.defineProperty nécessite l'observation manuelle des nouvelles propriétés. vue2 doit utiliser vm.$set pour garantir que les nouvelles propriétés sont également réactives
5. Proxy prend en charge 13 types d'opérations d'interception, que DefineProperty n'a pas
6. Proxy est un nouveau standard à long terme, le moteur JS. continuera à Proxy est optimisé, mais les getters et setters ne seront fondamentalement plus optimisés de manière ciblée
La vue n'est pas rafraîchie. En effet, lorsque l'instance Vue est créée, les nouvelles propriétés ne sont pas déclarées, elles ne sont donc pas converties en propriétés réactives par Vue, et naturellement la mise à jour de la vue ne sera pas déclenchée. Dans ce cas, vous devez utiliser le global de Vue. api $set() :
this.$set(this.obj, 'new_property', 'new_value')
attribut calculé : dépend des autres valeurs d'attribut, et la valeur calculée est mise en cache uniquement la valeur d'attribut dont elle dépend. en cas de changement, et la valeur calculée sera obtenue la prochaine fois. La valeur calculée ne sera recalculée que lorsque la valeur sera atteinte.
watch listening : Il s'agit plutôt d'une fonction d'observation, sans mise en cache, similaire au rappel de surveillance de certaines données. Chaque fois que les données surveillées changent, le rappel sera exécuté pour les opérations ultérieures.
Scénarios d'application :
1. Lorsque nous devons effectuer des calculs numériques et dépendre d'autres données, calculé doit être utilisé, car la fonction de cache de calculé peut être utilisée pour éviter un recalcul à chaque fois que la valeur est obtenue.
2. Lorsque nous devons effectuer des opérations asynchrones ou coûteuses lorsque les données changent, nous devons utiliser watch L'utilisation de l'option watch nous permet d'effectuer des opérations asynchrones (accéder à une API), de limiter la fréquence à laquelle nous effectuons l'opération et le moment où nous le faisons. get Avant le résultat final, définissez l'état intermédiaire. Ce sont des choses que les propriétés calculées ne peuvent pas faire.
3. Si plusieurs facteurs affectent un affichage, utilisez Calculé ; si un changement dans un facteur affecte plusieurs autres facteurs et affichages, utilisez Watch
1.computed : Calculé ; les attributs sont mis en cache en fonction de leurs dépendances ne seront réévalués que lorsque ses dépendances associées changent. Pour la méthode, tant que le nouveau rendu se produit,
.
2.les appels de méthode exécuteront toujours cette fonction
1. N'opérons pas directement les éléments du DOM, mais exploitons uniquement les données pour restituer la page
2. Le DOM virtuel est conçu pour résoudre les problèmes de performances du navigateur
Lors de l'utilisation données, les éléments dom modifiés sont mis en cache et après calcul, ils sont mappés à l'arbre dom réel par comparaison
3. L'algorithme diff compare l'ancien et le nouveau dom virtuel. Si les types de nœuds sont les mêmes, comparez les données et modifiez les données ; si les nœuds sont différents, supprimez directement le nœud et tous les nœuds enfants, et insérez un nouveau nœud si une clé unique est définie pour chaque nœud, vous pouvez avec précision ; trouvez ce qui doit être changé, sinon il y aura une situation où la modification d'un endroit entraînera des changements à d'autres endroits. Par exemple, A-B-C-D, si je veux insérer un nouveau nœud A-B-M-C-D, C et D seront en fait modifiés. Mais après avoir défini la clé, vous pouvez trouver avec précision B C et l'insérer
1. Il présente des avantages multiplateformes
2. Il est lent à faire fonctionner le DOM, mais js fonctionne efficacement. Nous pouvons placer l'opération de comparaison DOM sur la couche JS pour améliorer l'efficacité.
3. Améliorer les performances de rendu
Utilisez des filtres dans Vue pour filtrer (formater) les données, mais filtrer (formater) les données et les modifier. l'utilisateur (attributs calculés, méthodes, etc.) traite tous l'affichage de sortie du format de données en modifiant les données
Scénarios d'utilisation : par exemple, les formats d'affichage qui doivent traiter l'heure, les nombres, etc. ; . Modificateurs d'événements courants et leurs fonctions
.stop
: équivalent à event.stopPropagation() en JavaScript, empêchant les événements de bouillonner ; 2).prevent
: Équivalent à event.preventDefault() en JavaScript, empêchant l'exécution d'un comportement prédéfini (si l'événement peut être annulé, annulez l'événement sans arrêter la propagation ultérieure de l'événement .capture
; : Lorsqu'un élément fait des bulles, l'élément avec ce modificateur est déclenché en premier. S'il y a plusieurs modificateurs, ils seront déclenchés de l'extérieur vers l'intérieur. Par exemple, si p1 est imbriqué dans p2, p3 est imbriqué dans p4.capture est imbriqué dans p4, alors l'ordre d'exécution est : p3=》p4=》p2=》p14).self
: ne déclenchera que sa propre portée. Les événements à l'intérieur n'incluent pas d'éléments enfants ;5)
.once
: il ne sera déclenché qu'une seule fois..stop
:等同于 JavaScript 中的 event.stopPropagation() ,防止事件冒泡;
2).prevent
:等同于 JavaScript 中的 event.preventDefault() ,防止执行预设的行为(如果事件可取消,则取消该事件,而不停止事件的进一步传播);
3).capture
:当元素发生冒泡时,先触发带有该修饰符的元素。若有多个该修饰符,则由外而内触发。如 p1中嵌套p2中嵌套p3.capture中嵌套p4,那么执行顺序为:p3=》p4=》p2=》p1
4).self
:只会触发自己范围内的事件,不包含子元素;
5).once
:只会触发一次。
v-show 仅仅控制元素的显示方式,将 display 属性在 block 和 none 来回切换;而v-if会控制这个 DOM 节点的存在与否。当我们需要经常切换某个元素的显示/隐藏时,使用v-show会更加节省性能上的开销;当只需要一次显示或隐藏时,使用v-if更加合理。
作用在表单元素上v-model="message"等同于v-bind:value=“message” v-on:input="message=e v e n t . t a r g e t . v a l u e " 作 用 在 组 件 上 , 本 质 是 一 个 父 子 组 件 通 信 的 语 法 糖 ,通过prop和.emit实现, 等同于:value="message" @input=" $emit('input', $event.target.value)"
tandis que v-if contrôlera l'existence de cev-show
block et none
contrôle uniquement le mode d'affichage de l'élément
, en basculant l'attribut d'affichage entre
1.14. Comment le v-model est-il implémenté ? Qu'est-ce que le sucre syntaxique
agit sur les éléments du formulaire ? input ="message=e v e n t . t a r g e t . va l u e " agit sur les composants. Il s'agit essentiellement d'un sucre syntaxique pour la communication entre composants parent-enfant, implémenté via prop et .emit, qui équivaut à :value="message" @input =" $emit( 'input', $event.target.value)"
Les objets en JavaScript sont des données de type référence lorsqu'il y a plusieurs instances. faites référence au même objet, tant qu'une instance opère sur cet objet, les données des autres instances changeront également.
🎜🎜🎜1.16. Le processus du modèle Vue au rendu🎜🎜🎜🎜1. Appelez la méthode d'analyse pour convertir le modèle en ast (arbre de syntaxe abstraite) 🎜 2. Optimisez les nœuds statiques. S'il s'agit de nœuds statiques, le DOM qu'ils génèrent ne changera jamais, ce qui optimise grandement les mises à jour des modèles d'exécution. 🎜 3. Générer une fonction de rendu. La valeur de retour du rendu est VNode est le nœud DOM virtuel de Vue, qui contient (nom de l'étiquette, nœud enfant, texte, etc.) 🎜🎜🎜🎜1.17. 🎜🎜 🎜Appelez la méthode parse pour convertir le modèle en ast (arbre de syntaxe abstraite) 🎜 Optimisez les nœuds statiques. S'il s'agit de nœuds statiques, le DOM qu'ils génèrent ne changera jamais, ce qui optimise grandement les mises à jour des modèles d'exécution. 🎜 Générez une fonction de rendu. La valeur de retour du rendu est VNode. VNode est le nœud DOM virtuel de Vue, qui contient (nom de l'étiquette, nœud enfant, texte, etc.) 🎜
Dans Vue, nous souhaitons réutiliser davantage les composants, chaque composant doit donc avoir ses propres données afin que les composants n'interfèrent pas les uns avec les autres.
Par conséquent, les données du composant ne peuvent pas être écrites sous forme d'objets, mais doivent être écrites sous forme de fonctions. Les données sont définies sous la forme de valeurs de retour de fonction, de sorte que chaque fois que nous réutilisons un composant, une nouvelle donnée sera renvoyée, c'est-à-dire que chaque composant a son propre espace de données privé, et chacun conserve ses propres données. interférer avec le fonctionnement normal des autres composants.
易用、简洁且高效的http库, 支持node端和浏览器端,支持Promise,支持拦截器等高级配置。
sass是一种CSS预编译语言安装和使用步骤如下。
1.用npm安装加载程序( sass-loader、 css-loader等加载程序)。
2.在 webpack.config.js中配置sass加载程序。
Vue. js提供了一个v-cloak
指令,该指令一直保持在元素上,直到关联实例结束编译。当和CSS一起使用时,这个指令可以隐藏未编译的标签,直到实例编译结束。用法如下
在开发业务时,经常会岀现异步获取数据的情况,有时数据层次比较深,如以下代码: , 可以使用vm.$set手动定义一层数据:
vm.$set("demo",a.b.c.d)
config/ index.js内对 proxyTable项配置代理。
Vue 在修改数据后,视图不会立刻更新,而是等同一事件循环中的所有数据变化完成之后,再统一进行视图更新。
换句话说,只要观察到数据变化,就会自动开启一个队列,并缓冲在同一个事件循环中发生的所以数据改变。在缓冲时会去除重复数据,从而避免不必要的计算和 DOM 操作。
1.vue 用异步队列的方式来控制 DOM 更新和 nextTick 回调先后执行
2.microtask 因为其高优先级特性,能确保队列中的微任务在一次事件循环前被执行完毕
因为组件是可以复用的,JS 里对象是引用关系,如果组件 data 是一个对象,那么子组件中的 data 属性值会互相污染。
所以一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝。
由于v-for的优先级比v-if高,所以导致每循环一次就会去v-if一次,而v-if是通过创建和销毁dom元素来控制元素的显示与隐藏,所以就会不停的去创建和销毁元素,造成页面卡顿,性能下降。
解决办法:
1.在v-for的外层或内层包裹一个元素来使用v-if
2.用computed处理
1.v-model 多用于表单元素实现双向数据绑定(同angular中的ng-model)
2.v-bind 动态绑定 作用: 及时对页面的数据进行更改
3.v-on:click 给标签绑定函数,可以缩写为@,例如绑定一个点击函数 函数必须写在methods里面
4.v-for 格式: v-for=“字段名 in(of) 数组json” 循环数组或json(同angular中的ng-repeat)
5.v-show 显示内容 (同angular中的ng-show)
6.v-hide 隐藏内容(同angular中的ng-hide)
7.v-if 显示与隐藏 (dom元素的删除添加 同angular中的ng-if 默认值为false)
8.v-else-if 必须和v-if连用
9.v-else 必须和v-if连用 不能单独使用 否则报错 模板编译错误
10.v-text 解析文本
11.v-html 解析html标签
12.v-bind:class 三种绑定方法 1、对象型 ‘{red:isred}’ 2、三元型 ‘isred?“red”:“blue”’ 3、数组型 ‘[{red:“isred”},{blue:“isblue”}]’
13.v-once 进入页面时 只渲染一次 不在进行渲染
14.v-cloak 防止闪烁
15.v-pre 把标签内部的元素原位输出
1.父传子:子组件通过props[‘xx’] 来接收父组件传递的属性 xx 的值
2.子传父:子组件通过 this.$emit(‘fnName’,value) 来传递,父组件通过接收 fnName 事件方法来接收回调
3.其他方式:通过创建一个bus,进行传值
4.使用Vuex
当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。key的作用主要是为了高效的更新虚拟DOM
Object.defineProperty
本身有一定的监控到数组下标变化的能力,但是在 Vue 中,从性能/体验的性价比考虑,尤大大就弃用了这个特性(Vue 为什么不能检测数组变动 )。为了解决这个问题,经过 vue 内部处理后可以使用以下几种方法来监听数组
push();
pop();
shift();
unshift();
splice();
sort();
reverse();
由于只针对了以上 7 种方法进行了 hack 处理,所以其他数组的属性也是检测不到的,还是具有一定的局限性。
Object.defineProperty 只能劫持对象的属性,因此我们需要对每个对象的每个属性进行遍历。Vue 2.x 里,是通过 递归 + 遍历 data 对象来实现对数据的监控的,如果属性值也是对象那么需要深度遍历,显然如果能劫持一个完整的对象是才是更好的选择。
Proxy 可以劫持整个对象,并返回一个新的对象。Proxy 不仅可以代理对象,还可以代理数组。还可以代理动态增加的属性。
JS 运行机制
JS 执行是单线程的,它是基于事件循环的。事件循环大致分为以下几个步骤:
所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
主线程不断重复上面的第三步。
主线程的执行过程就是一个 tick,而所有的异步结果都是通过 “任务队列” 来调度。 消息队列中存放的是一个个的任务(task)。 规范中规定 task 分为两大类,分别是 macro task 和 micro task,并且每个 macro task 结束后,都要清空所有的 micro task。
for (macroTask of macroTaskQueue) { // 1. Handle current MACRO-TASK handleMacroTask(); // 2. Handle all MICRO-TASK for (microTask of microTaskQueue) { handleMicroTask(microTask); }}
在浏览器环境中 :
常见的 macro task 有 setTimeout、MessageChannel、postMessage、setImmediate
常见的 micro task 有 MutationObsever 和 Promise.then
异步更新队列
可能你还没有注意到,Vue 在更新 DOM 时是异步执行的。只要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。
如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。
然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。
Vue 在内部对异步队列尝试使用原生的 Promise.then、MutationObserver 和 setImmediate,如果执行环境不支持,则会采用 setTimeout(fn, 0) 代替。
在 vue2.5 的源码中,macrotask 降级的方案依次是:setImmediate、MessageChannel、setTimeout
vue 的 nextTick 方法的实现原理:
vue 用异步队列的方式来控制 DOM 更新和 nextTick 回调先后执行
microtask 因为其高优先级特性,能确保队列中的微任务在一次事件循环前被执行完毕
考虑兼容问题,vue 做了 microtask 向 macrotask 的降级方案
Vue 事件机制 本质上就是 一个 发布-订阅 模式的实现。
class Vue { constructor() { // 事件通道调度中心 this._events = Object.create(null); } $on(event, fn) { if (Array.isArray(event)) { event.map(item => { this.$on(item, fn); }); } else { (this._events[event] || (this._events[event] = [])).push(fn); } return this; } $once(event, fn) { function on() { this.$off(event, on); fn.apply(this, arguments); } on.fn = fn; this.$on(event, on); return this; } $off(event, fn) { if (!arguments.length) { this._events = Object.create(null); return this; } if (Array.isArray(event)) { event.map(item => { this.$off(item, fn); }); return this; } const cbs = this._events[event]; if (!cbs) { return this; } if (!fn) { this._events[event] = null; return this; } let cb; let i = cbs.length; while (i--) { cb = cbs[i]; if (cb === fn || cb.fn === fn) { cbs.splice(i, 1); break; } } return this; } $emit(event) { let cbs = this._events[event]; if (cbs) { const args = [].slice.call(arguments, 1); cbs.map(item => { args ? item.apply(this, args) : item.call(this); }); } return this; }}
三种:
一种是全局导航钩子:router.beforeEach(to,from,next),作用:跳转前进行判断拦截。第二种:组件内的钩子;第三种:单独路由独享组件
vue框架中状态管理。在main.js引入store,注入。新建了一个目录store,…… export 。
场景有:单页应用中,组件之间的状态。音乐播放、登录状态、加入购物车
MVVM et MVC sont tous deux des idées de conception. L'essentiel est que le contrôleur dans MVC évolue vers un ViewModel qui affiche principalement la couche de vue via les données au lieu des nœuds d'exploitation, ce qui résout le problème d'un grand nombre d'opérations DOM. dans MVC et améliore les performances de rendu des pages. Vitesse de chargement réduite et lente, affectant l'expérience utilisateur. Principalement utilisé dans des scénarios comportant de nombreuses opérations de données.
Scénarios : Scénarios avec beaucoup d'opérations de données, plus pratiques
En bref, il est d'abord converti en arbre AST, puis obtenu La fonction de rendu renvoie VNODE (le nœud DOM virtuel de la société Vue)
Étapes détaillées :
Tout d'abord, compilez le modèle dans un arbre de syntaxe AST (l'arbre de syntaxe abstraite est une représentation arborescente de la structure syntaxique abstraite du code source) via le compilateur est la valeur de retour de createCompiler, qui est utilisée pour créer un compilateur. Responsable de la fusion des options.
Ensuite, l'AST sera généré (le processus de conversion de l'arbre de syntaxe AST en une chaîne de fonction de rendu) pour obtenir la fonction de rendu. La valeur de retour du rendu est VNode est le nœud DOM virtuel de Vue, qui contient (. nom de l'étiquette, nœud enfant, texte, etc.)
Réponse : lors de l'encapsulation de composants dynamiques, les instances de composants inactifs seront mises en cache, principalement utilisées pour conserver l'état du composant ou éviter un nouveau rendu
Utilisation : pages simples
Cache :
不缓存:
相同点:都鼓励组件化,都有’props’的概念,都有自己的构建工具,Reat与Vue只有框架的骨架,其他的功能如路由、状态管理等是框架分离的组件。
不同点:React:数据流单向,语法—JSX,在React中你需要使用setState()方法去更新状态。Vue:数据双向绑定,语法–HTML,state对象并不是必须的,数据由data属性在Vue对象中进行管理。适用于小型应用,但对于对于大型应用而言不太适合。
参照大神文章:vue笔记 - 生命周期第二次学习与理解
beforeCreate
是new Vue()之后触发的第一个钩子,在当前阶段data、methods、computed以及watch上的数据和方法都不能被访问。
created
在实例创建完成后发生,当前阶段已经完成了数据观测,也就是可以使用数据,更改数据,在这里更改数据不会触发updated函数。可以做一些初始数据的获取,在当前阶段无法与Dom进行交互,如果非要想,可以通过vm.$nextTick来访问Dom。
beforeMount
发生在挂载之前,在这之前template模板已导入渲染函数编译。而当前阶段虚拟Dom已经创建完成,即将开始渲染。在此时也可以对数据进行更改,不会触发updated。
mounted
在挂载完成后发生,在当前阶段,真实的Dom挂载完毕,数据完成双向绑定,可以访问到Dom节点,使用$refs属性对Dom进行操作。
beforeUpdate发生在更新之前,也就是响应式数据发生更新,虚拟dom重新渲染之前被触发,你可以在当前阶段进行更改数据,不会造成重渲染。
updated
发生在更新完成之后,当前阶段组件Dom已完成更新。要注意的是避免在此期间更改数据,因为这可能会导致无限循环的更新。
beforeDestroy
发生在实例销毁之前,在当前阶段实例完全可以被使用,我们可以在这时进行善后收尾工作,比如清除计时器。
destroyed
Ne pas mettre en cache :
Mêmes points : les deux encouragent la composantisation, les deux ont le concept de "props", et tous deux ont leurs propres outils de construction. Reat et Vue n'ont que le squelette du framework, et d'autres fonctions telles que le routage. , la gestion de l'état, etc. sont des cadres Composants distincts.
Différences : React : flux de données unidirectionnel, syntaxe - JSX, dans React, vous devez utiliser la méthode setState() pour mettre à jour l'état. Vue : liaison de données bidirectionnelle, syntaxe – HTML, l'objet d'état n'est pas requis, les données sont gérées dans l'objet Vue par l'attribut data. Convient aux petites applications, mais ne convient pas aux grandes applications.🎜Référez-vous à l'excellent article : notes de vue - deuxième apprentissage et compréhension du cycle de vie🎜🎜🎜
1.40. Comprendre le cycle de vie des vues ?beforeCreate
est le premier hook déclenché après new Vue(). Dans l'étape actuelle, les données et les méthodes sur les données, les méthodes, calculées et surveillées sont tous inaccessibles. 🎜🎜created
se produit après la création de l'instance. L'observation des données est terminée à l'étape actuelle, c'est-à-dire que les données peuvent être utilisées et modifiées ici ne déclencheront pas la fonction mise à jour. Vous pouvez effectuer une acquisition de données initiale. Vous ne pouvez pas interagir avec le Dom au stade actuel. Si vous le devez, vous pouvez accéder au Dom via vm.$nextTick. 🎜🎜beforeMount
se produit avant le montage, avant lequel le modèle de modèle a été importé et compilé avec des fonctions de rendu. Au stade actuel, le Dom virtuel a été créé et est sur le point de commencer le rendu. Des modifications aux données peuvent également être apportées à ce moment-là, et la mise à jour ne sera pas déclenchée. 🎜🎜Mounted
se produit une fois le montage terminé. À l'étape actuelle, le vrai Dom est monté, les données sont liées dans les deux sens, le nœud Dom est accessible et l'attribut $refs est utilisé. pour faire fonctionner le Dom. 🎜🎜beforeUpdate se produit avant la mise à jour, c'est-à-dire que les données réactives sont mises à jour et que le dom virtuel est déclenché avant le nouveau rendu. Vous pouvez modifier les données dans l'étape en cours sans provoquer de nouveau rendu. 🎜🎜mis à jour
se produit une fois la mise à jour terminée et le composant de scène actuel Dom a été mis à jour. Veillez à éviter de modifier les données pendant cette période, car cela pourrait entraîner une boucle infinie de mises à jour. 🎜🎜beforeDestroy
se produit avant que l'instance ne soit détruite. L'instance peut être entièrement utilisée à l'étape actuelle. Nous pouvons effectuer un travail de finition de post-traitement à ce moment-là, comme effacer la minuterie. 🎜🎜destroyed
se produit après la destruction de l'instance. À ce stade, il ne reste que le shell dom. Le composant a été désassemblé, la liaison de données a été supprimée, l'écouteur a été supprimé et toutes les instances enfants ont été détruites. 🎜🎜🎜1.41. Parlons respectivement des algorithmes de comparaison des moteurs de rendu Vue2.x et Vue3.x🎜🎜🎜En termes simples, l'algorithme de comparaison a le processus suivant🎜🎜🎜1. Comparez les pairs, puis comparez les nœuds enfants🎜 2. Jugez. d'abord La situation dans laquelle une partie a des nœuds enfants et l'autre pas (si les nouveaux enfants n'ont pas de nœuds enfants, supprimez les anciens nœuds enfants) 🎜 3. Comparez la situation où les deux enfants ont des nœuds enfants (diff de base) 🎜 3. De manière récursive comparer les nœuds enfants 🎜
La complexité temporelle du Diff normal entre deux arbres est O(n^3)
, mais dans les situations réelles, nous déplaçons rarement le DOM d'un niveau à l'autre, donc Vue optimise le Diff à partir de O(n^3 ) -> O(n)
, uniquement lorsque les anciens et les nouveaux enfants sont plusieurs nœuds enfants, l'algorithme Diff de base doit être utilisé pour une comparaison de même niveau. O(n^3)
,但实际情况下我们很少会进行跨层级的移动DOM,所以Vue将Diff进行了优化,从O(n^3) -> O(n)
,只有当新旧children都为多个子节点时才需要用核心的Diff算法进行同层级比较。
Vue2的核心Diff算法采用了双端比较的算法,同时从新旧children的两端开始进行比较,借助key值找到可复用的节点,再进行相关操作。相比React的Diff算法,同样情况下可以减少移动节点次数,减少不必要的性能损耗,更加的优雅。
Vue3.x借鉴了
ivi算法和 inferno算法
在创建VNode时就确定其类型,以及在 mount/patch 的过程中采用位运算来判断一个VNode的类型,在这个基础之上再配合核心的Diff算法,使得性能上较Vue2.x有了提升。(实际的实现可以结合Vue3.x源码看。)
该算法中还运用了动态规划的思想求解最长递归子序列。
编码阶段
1.尽量减少data中的数据,data中的数据都会增加getter和setter,会收集对应的2.watcher
3.v-if和v-for不能连用
4.如果需要使用v-for给每项元素绑定事件时使用事件代理
5.SPA 页面采用keep-alive缓存组件
6.在更多的情况下,使用v-if替代v-show
7.key保证唯一
8.使用路由懒加载、异步组件
9.防抖、节流
10.第三方模块按需导入
11.长列表滚动到可视区域动态加载
12.图片懒加载
SEO优化
1.预渲染
2.服务端渲染SSR
打包优化
1.压缩代码
2.Tree Shaking/Scope Hoisting
3.使用cdn加载第三方模块
4.多线程打包happypack
5.splitChunks抽离公共文件
6.sourceMap优化
用户体验
1.骨架屏
2.PWA
还可以使用缓存(客户端缓存、服务端缓存)优化、服务端开启gzip压缩等。
location.hash
的值实际就是URL中#后面的东西。
history
实际采用了HTML5中提供的API来实现,主要有history.pushState()
和history.replaceState()
。
SPA( single-page application )仅在 Web 页面初始化时加载相应的 HTML、JavaScript 和 CSS
一旦页面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转
取而代之的是利用路由机制实现 HTML 内容的变换, UI 与用户的交互,避免页面的重新加载
优点:
1、用户体验好、快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染
2、基于上面一点,SPA 相对对服务器压力小
3、前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理
缺点:
1、初次加载耗时多:为实现单页 Web 应用功能及显示效果,
需要在加载页面的时候将 JavaScript、CSS 统一加载,部分页面按需加载
2、前进后退路由管理:由于单页应用在一个页面中显示所有的内容,
所以不能使用浏览器的前进后退功能,所有的页面切换需要自己建立堆栈管理
3、SEO 难度较大:由于所有的内容都在一个页面中动态替换显示,所以在 SEO 上其有着天然的弱势
第一步:在components目录新建你的组件文件(indexPage.vue),script一定要
export default {}
第二步:在需要用的页面(组件)中导入:import indexPage from ‘@/components/indexPage.vue’
第三步:注入到vue的子组件的components属性上面,components:{indexPage}
第四步:在template视图view中使用,
例如有indexPage命名,使用的时候则index-page
webpack中提供了
L'algorithme Diff de base de Vue2 adopte un algorithme de comparaison à double extrémité. En même temps, il commence à comparer les anciens et les nouveaux enfants aux deux extrémités, utilise la valeur clé pour trouver le nœud réutilisable, puis effectue les opérations associées. . Par rapport à l'algorithme Diff de React, dans les mêmes circonstances, il peut réduire le nombre de nœuds mobiles, réduire les pertes de performances inutiles et est plus élégant. 🎜🎜Vue3.x s'appuie sur l'algorithme ivi et l'algorithme inferno🎜🎜Le type de VNode est déterminé lors de sa création, et des opérations binaires sont utilisées pour déterminer le type d'un VNode pendant le processus de montage/patch. Sur cette base, couplées avec le. algorithme de base Diff, les performances ont été améliorées par rapport à Vue2.x. (L'implémentation réelle peut être consultée en conjonction avec le code source de Vue3.x.) 🎜🎜Cet algorithme utilise également l'idée de programmation dynamique pour résoudre la sous-séquence récursive la plus longue. 🎜require.ensure()
来实现按需加载。以前引入路由是通过import 这样的方式引入,改为const定义的方式进行引入。
不进行页面按需加载引入方式:import home from '../../common/home.vue'
进行页面按需加载的引入方式:const home = r => require.ensure( [], () => r (require('../../common/home.vue')))
1.42. Quelles optimisations de performances avez-vous effectuées pour Vue ?
🎜Phase d'encodage🎜🎜1. Essayez de réduire les données dans data Les données dans data ajouteront des getters et des setters, et le 2.watcher correspondant
3.v-. if et v-for ne peuvent pas être utilisés ensemble
4. Si vous devez utiliser v-for pour lier des événements à chaque élément, utilisez un proxy d'événement
5. La page SPA utilise le composant de cache keep-alive
6. Dans la plupart des cas, utilisez v-if au lieu de v-show
7. La clé est garantie unique
8. Utilisez le chargement paresseux de routage et les composants asynchrones
9. Anti-shake, throttling
/> 10. Importez des modules tiers à la demande
11. Faites défiler les longues listes vers la zone visible et chargez-les dynamiquement
12. Chargement paresseux des images🎜🎜🎜SEO optimisation🎜🎜1. Pré-rendu
2. Rendu côté serveur SSR🎜🎜🎜Optimisation de l'emballage🎜🎜1. Code compressé
2.Tree Shaking/Scope Hoisting3. Utilisez Cdn pour charger des modules tiers
4. Happypack d'emballage multithread
5.splitChunks extrait les fichiers publics
6. Optimisation de sourceMap🎜🎜🎜Expérience utilisateur🎜🎜1. Écran squelette
2.PWA🎜🎜🎜Très bien Utiliser l'optimisation du cache (cache client, cache serveur), activer la compression gzip sur le serveur, etc. 🎜1.43. Parlons des principes d'implémentation du routage de hachage et du routage historique
🎜La valeur delocation.hash
est en fait la chose après # in l'URL. 🎜🎜history
est en fait implémenté à l'aide de l'API fournie en HTML5, principalementhistory.pushState()
ethistory.replaceState()
. 🎜1.44. Comprendre la page unique SPA, quels sont ses avantages et ses inconvénients
🎜SPA (application monopage) ne charge le HTML et le JavaScript correspondants que lorsque la page Web est initialisée et CSS
Une fois la page chargée, SPA ne rechargera pas ou ne sautera pas la page en raison des opérations de l'utilisateur
Au lieu de cela, il utilise le mécanisme de routage pour réaliser la transformation du contenu HTML et l'interaction entre l'interface utilisateur et les utilisateurs pour éviter Rechargement de page
Avantages : 🎜🎜1. L'expérience utilisateur est bonne et rapide. Les modifications de contenu ne nécessitent pas de recharger la page entière, évitant ainsi les sauts inutiles et les rendus répétés
2. Basé sur ce qui précède. Le fait est que SPA exerce relativement peu de pression sur le serveur
3. Les responsabilités du front-end et du back-end sont séparées et la structure est claire. Le front-end exécute une logique interactive et le back-end est responsable des données. Inconvénients : 🎜🎜1. Le chargement initial prend beaucoup de temps : Afin de réaliser les fonctions et les effets d'affichage des applications Web d'une seule page,
JavaScript et CSS doivent être chargés uniformément lors du chargement. la page, et certaines pages sont chargées à la demande
2. Gestion du routage aller et retour : les applications monopage étant tout le contenu est affiché sur une seule page,
vous ne pouvez donc pas utiliser les fonctions avant et arrière du navigateur . Tous les changements de page nécessitent votre propre gestion de pile
3. Le référencement est difficile : puisque tout le contenu est sur une seule page, il remplace dynamiquement l'affichage, il a donc une faiblesse naturelle en référencement🎜🎜1.45. Comment utiliser des composants personnalisés dans vue.cli ? Avez-vous rencontré des problèmes ?
🎜Première étape : Créez un nouveau fichier de composant (indexPage.vue) dans le répertoire des composants. Le script doit êtreexport default {}
Deuxièmement. Étape : Importez dans la page (composant) dont vous avez besoin :importez indexPage depuis '@/components/indexPage.vue'
Étape 3 : Injectez-le dans l'attribut composants du sous-composant de vue ,components :{indexPage}
Étape 4 : Utilisez-le dans la vue modèle,
Par exemple, s'il est nommé indexPage, lors de son utilisation, il sera index- page🎜🎜1.46. Comment vue implémente le chargement à la demande avec les paramètres du webpack
🎜webpack fournitrequire.ensure()
pour réaliser -chargement à la demande. Dans le passé, les itinéraires étaient introduits via l'importation, mais ils le sont désormais via la définition const.
La méthode d'introduction sans chargement à la demande des pages :import home from '../../common/home.vue'
La méthode d'introduction avec chargement à la demande de pages : const home = r => require.ensure( [], () => r (require('../../common/home.vue')))🎜二、组件 Component
2.1.vue中如何编写可复用的组件 (编写组件的原则)
以组件功能命名
只负责ui的展示和交互动画,不要在组件里与服务器打交道(获取异步数据等)
可复用组件不会因组件使用的位置、场景而变化。尽量减少对外部条件的依赖。2.2.如何让CSS只在当前组件中起作用?
在每一个Vue.js组件中都可以定义各自的CSS、 JavaScript代码。如果希望组件内写的CSS只对当前组件起作用,只需要在Style标签添加Scoped属性即可
2.3.keep-alive是什么?
如果需要在组件切换的时候,保存一些组件的状态防止多次渲染,就可以使用 keep-alive 组件包裹需要保存的组件。
两个重要属性,include 缓存组件名称,exclude 不需要缓存的组件名称。
2.4.如何在 Vue. js动态插入图片
对“src”属性插值将导致404请求错误。应使用 v-bind:src (简写:src)格式代替。
2.5.父子组件的生命周期顺序(可参照上方图解)
加载渲染过程:
父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
子组件更新过程:父beforeUpdate->子beforeUpdate->子updated->父updated
父组件更新过程:父beforeUpdate->父updated
销毁过程:父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
三、Vuex
3.1.vuex的核心概念
1.state => 基本数据
2.getters => 从基本数据派生的数据
3.mutations => 修改数据,同步
4.actions => 修改数据,异步 (Action 提交的是 mutation,而不是直接变更状态)
5.modules => 模块化Vuex3.2.vuex是什么?怎么使用?哪种功能场景使用它?
Vuex 是一个专为 Vue.js 应用程序开发的状态管理器,采用集中式存储管理应用的所有组件的状态,主要是为了多页面、多组件之间的通信。
Vuex有5个重要的属性,分别是 State、Getter、Mutation、Action、Module,由 view 层发起一个 Action 给 Mutation,在 Mutation 中修改状态,返回新的状态,通过 Getter暴露给 view层的组件或者页面,页面监测到状态改变于是更新页面。如果你的项目很简单,最好不要使用 Vuex,对于大型项目,Vuex 能够更好的帮助我们管理组件外部的状态,一般可以运用在购物车、登录状态、播放等场景中。3.3.多个组件之间如何拆分各自的state,每块小的组件有自己的状态,它们之间还有一些公共的状态需要维护,如何思考这块
1.公共的数据部分可以提升至和他们最近的父组件,由父组件派发
2.公共数据可以放到vuex中统一管理,各组件分别获取3.4.Vue.js中ajax请求代码应该写在组件的methods中还是vuex的actions中?
1.如果请求来的数据是不是要被其他组件公用,仅仅在请求的组件内使用,就不需要放入vuex 的state里。
2.如果被其他地方复用,这个很大几率上是需要的,如果需要,请将请求放入action里,方便复用,并包装成promise返回,在调用处用async await处理返回的数据。如果不要复用这个请求,那么直接写在vue文件里很方便
3.5.Vuex中如何异步修改状态
actions与mutations作用类似,都是可以对状态进行修改。不同的是actions是异步操作的。
actions是可以调用Mutations里的方法的。
const actions={ addActions(context){ context.commit('add',10);//调用mutations中的方法 setTimeout(()=>{context.commit('reduce')},5000) // setTimeOut(()=>{context.commit('reduce')},3000); console.log('我比reduce提前执行'); }, reduceActions({commit}){ commit('reduce'); }}Copier après la connexion3.6.Vuex中actions和mutations的区别
Mutation 更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数
const store = new Vuex.Store({ state: { count: 1 }, mutations: { increment (state) { // 变更状态 state.count++ } }})Copier après la connexionAction Action 类似于 mutation,不同在于:
Action 提交的是 mutation,而不是直接变更状态。
Action 可以包含任意异步操作const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } }, actions: { increment (context) { context.commit('increment') } }})Copier après la connexion3.7.怎么在组件中批量使用Vuex的state状态?
使用
mapState
辅助函数, 利用对象展开运算符将state混入computed对象中import {mapState} from 'vuex' export default{ computed:{ ...mapState(['price','number']) } }Copier après la connexion3.8.Vuex中状态是对象时,使用时要注意什么?
对象是引用类型,复制后改变属性还是会影响原始数据,这样会改变state里面的状态,是不允许,所以先用深度克隆复制对象,再修改。
四、Router
4.1.vue-router 路由模式有几种
1.Hash: 使用 URL 的 hash 值来作为路由。支持所有浏览器。 带#。如:http://localhost:8080/#/pageA。改变hash,浏览器本身不会有任何请求服务器动作的,但是页面状态和url已经关联起来了。
2.History: 以来 HTML5 History API 和服务器配置。参考官网中 HTML5 History 模式,不带#, 如:http://localhost:8080/ 正常的而路径,并没有#。基于HTML5的 pushState、replaceState实现
3.Abstract: 支持所有 javascript 运行模式。如果发现没有浏览器的 API,路由会自动强制进入这个模式。4.2.vue-router如何定义嵌套路由
通过children 数组:
const router = new VueRouter({ routes: [ { path: "/parentPage", component: testPage, children: [ { path: "/childrenA", component: childrenComponentA, }, { path: "/childrenB", component: childrenComponentB, }, ], }, { // 其他和parentPage平级的路由 }, ],});Copier après la connexion4.3.vue-router有哪几种导航钩子?
1.全局导航钩子:
router.beforeEach(to,from,next)
2.组件内的钩子beforeRouteEnter (to, from, next) beforeRouteUpdate (to, from, next) beforeRouteLeave (to, from, next)
3.单独路由独享组件beforeEnter: (to, from, next)
参数:有to(去的那个路由)、from(离开的路由)、next(一定要用这个函数才能去到下一个路由,如果不用就拦截)最常用就这几种
4.4. $ route和$ router的区别
1、
$route
是“路由信息对象”,包括path,params,hash,query,fullPath,matched,name
等路由信息参数。1.
$route.path
字符串,对应当前路由的路径,总是解析为绝对路径如"/foo/bar"。
2.$route.params
一个 key/value 对象,包含了 动态片段 和 全匹配片段, 如果没有路由参数,就是一个空对象。
3.$route.query
一个 key/value 对象,表示 URL 查询参数。 例如,对于路径/foo?user=1
,则有$route.query.user == 1
, 如果没有查询参数,则是个空对象
4.$route.hash
当前路由的hash值 (不带#) ,如果没有 hash 值,则为空字符串
5.$route.fullPath
完成解析后的 URL,包含查询参数和hash的完整路径。
6.$route.matched
数组,包含当前匹配的路径中所包含的所有片段所对应的配置参数对象。
7.$route.name
当前路径名字
8.$ route.meta
路由元信息2、
$router
是“路由实例”对象包括了路由的跳转方法,钩子函数等实例方法:
1)、push
1.字符串
this.$router.push('home')
2. 对象this.$router.push({path:'home'})
3. 命名的路由this.$router.push({name:'user',params:{userId:123}})
4.带查询参数,变成/register?plan=123this.$router.push({path:'register',query:{plan:'123'}})
push方法其实和是等同的。
注意:push方法的跳转会向 history 栈添加一个新的记录,当我们点击浏览器的返回按钮时可以看到之前的页面。2)、go
页面路由跳转
前进或者后退this.$router.go(-1)
// 后退3)、replace
push方法会向 history 栈添加一个新的记录,而replace方法是替换当前的页面,
不会向 history 栈添加一个新的记录4.5.路由之间跳转的方式
1.声明式(标签跳转)
2.编程式( js跳转)4.6.active-class是哪个组件的属性
vue-router 模块 的router-link组件
4.7.vue-router实现路由懒加载(动态加载路由)
把不同路由对应的组件分割成不同的代码块,然后当路由被访问时才加载对应的组件即为路由的懒加载,可以加快项目的加载速度,提高效率
const router = new VueRouter({ routes: [ { path: '/home', name: 'Home', component:() = import('../views/home') } ]})Copier après la connexion4.8.怎么定义vue-router的动态路由以及如何获取传过来的动态参数?
在router目录下的index.js文件中,对path属性加上/:id
使用router对象的params id面试官:我难道问不倒这小子了?(面试官持续懵逼中) 对大家有帮助的话三连呀~ 持续更新
【Tutoriels vidéo associés recommandés : Tutoriel d'introduction à vuejs, démarrage avec le front-end Web】
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!