Une exploration approfondie du mécanisme réactif de Vue3
Qu'est-ce que la réactivité ? Comment Vue parvient-il à être réactif ? L'article suivant vous donnera une compréhension approfondie du principe de réactivité de Vue3. J'espère qu'il vous sera utile !
Je pense que tout le monde connaît le framework Vue. En ce qui concerne Vue, je pense que l'une des premières questions que l'intervieweur se posera est de savoir comment le principe de réactivité de Vue est mis en œuvre. la réactivité de Vue2 avant l'article Principe, puis parlons aujourd'hui du mécanisme réactif de Vue3. [Recommandations associées : tutoriel vidéo vuejs, développement web front-end]
1. Qu'est-ce que la réactivité ?
Les variables en JavaScript n'ont pas la notion de réactivité. La logique d'exécution du code est descendante. Dans le framework Vue, la réactivité est l'une des fonctionnalités proposées. Regardons d'abord un exemple
let num = 1; let double = num * 2; console.log(double); // 2 num = 2; console.log(double); // 2
On voit clairement que la relation entre la variable double et la variable num n'est pas réactive Si nous encapsulons la logique de calcul du double dans une fonction, lorsque la valeur de la variable num change, nous exécutons à nouveau cette fonction, de sorte que la valeur de double change à mesure que num change, ce que nous appelons communément réactif.
let num = 1; // 将计算过程封装成一个函数 let getDouble = (n) => n * 2; let double = getDouble(num); console.log(double); // 2 num = 2; // 重新计算double,这里当然也没有实现响应式,只是说明响应式实现的时候这个函数应该再执行一次 double = getDouble(num); console.log(double); // 4
Bien que le processus de développement réel soit beaucoup plus compliqué que la situation simple actuelle, il peut être encapsulé dans une fonction à implémenter. Le problème maintenant est de savoir comment recalculer la valeur de double en fonction du changement de la variable num. ?
Si la valeur de la variable num est modifiée à chaque fois, la fonction getDouble peut la connaître et l'exécuter. Selon le changement de la variable num, le double changera également en conséquence.
2. Principe réactif
Trois solutions réactives ont été utilisées dans Vue, à savoir defineProperty, Proxy et value setter. L'API defineProperty est utilisée dans Vue2. Elle a été décrite en détail dans l'article précédent. Si vous souhaitez en savoir plus sur la réactivité de Vue2, cliquez ici --->Principe de réactivité de Vue2 | API
La partie centrale de Vue2 est l'API de piratage de données DefinProperty. Lorsque nous définissons un objet obj, utilisons DéfinirProperty pour proxy l'attribut num, la fonction get est exécutée et lorsque l'attribut num est modifié. , la fonction set est exécutée, il nous suffit d'écrire la logique de calcul du double dans la fonction set, de sorte que chaque fois que num change, le double sera attribué en conséquence, ce qui est réactif. let num = 1;
let detDouble = (n) => n * 2;
let obj = {}
let double = getDouble(num)
Object.defineProperty(obj,'num',{
get() {
return num;
}
set(val){
num = val;
double = getDouble(val)
}
})
console.log(double); // 2
obj.num = 2;
console.log(double); // 4
Copier après la connexion
défaut definePropertylet num = 1; let detDouble = (n) => n * 2; let obj = {} let double = getDouble(num) Object.defineProperty(obj,'num',{ get() { return num; } set(val){ num = val; double = getDouble(val) } }) console.log(double); // 2 obj.num = 2; console.log(double); // 4
: Lorsque nous supprimons l'attribut obj.num, la fonction set ne sera pas exécutée, donc dans Vue2 nous avons besoin d'une
une fonction spécialisée pour supprimer des données. Et les attributs qui n'existent pas dans l'objet obj ne peuvent pas être détournés, et la modification de l'attribut length sur le tableau n'est pas non plus valide.Proxy$delete
D'après le nom de Proxy, nous pouvons voir que cela signifie proxy, et l'importance importante de Proxy est de résoudre les défauts de réactivité de Vue2. Utilisation du proxy :
var proxy = new Proxy(target, handler);
Toutes les utilisations des objets Proxy sont sous la forme ci-dessus, la seule différence est la manière d'écrire les paramètres
handler. Parmi eux,
new Proxy() signifie générer une instance Proxy, le paramètre target représente l'objet cible à intercepter et le paramètre handler est également un objet utilisé pour personnaliser le comportement d'interception. 在ES6中官方新定义了 Reflect 对象,在ES6之前对象上的所有的方法都是直接挂载在对象这个构造函数的原型身上,而未来对象可能还会有很多方法,如果全部挂载在原型上会显得比较臃肿,而 Reflect 对象就是为了分担 Object的压力。 (1) 将 (2) 修改某些 (3) 让 (4) 所以我们在这里会使用到 Proxy 和 Reflect 对象的方与 Proxy 一一对应这一特性,来实现Vue3的响应式原理。 在Vue3中响应式的核心方法是 根据我们前面所做的铺垫,所以我们会使用 判断是否为对象(方法不唯一,有多种方法) 尽可能采用函数式编程,让每一个函数只做一件事,逻辑更加清晰。 但是这样会有一个问题,如果我需要代理的对象是深层嵌套的对象呢?我们先看看效果 当我们深层代理时,我们直接修改深层对象中的属性并不会触发 Proxy 对象中的 set 方法,那为什么我们可以修改呢?其实就是直接访问原对象中深层对象的值并修改了,那我们如何优化这个问题呢? 那也需要用到递归操作,判断深层对象是否被代理了,如果没有再执行reactive将内部未被代理的对象代理。 那么我们在 get 方法内部就不能直接将映射之后的 res 返回出去了 这样我们就实现了对象的深层代理,并且只有当我们访问到内部嵌套的对象时我们才
会去递归调用reactive ,这样不仅可以实现深层代理,并且节约了性能,但是其实我们还没有彻底完善,我们来看看下面这段代码 这样是不是合法的,当然是合法的,但是没有必要也没有意义,所以为了避免被代理过的对象,再次被代理,太浪费性能,所以我们需要将被代理的对象打上标记,这样当带被代理过的对象访问到时,直接将被代理过的对象返回,不需要再次代理。 在 Vue3 中,使用了hash表做映射,来记录是否已经被代理了。 与 Vue2 的数据劫持相比,Vue3 中的 Proxy 可以直接修改数组的长度,但是这样我们需要在 set 方法中判断我们是要在代理对象身上添加属性还是修改属性。 因为更新视图的函数会在set函数中调用,我们向数组中进行操作会触发两次更新视图,所以我们需要做一些优化。 避免多次更新视图,比如修改的值与原来一致就不更新视图,在上面两个判断条件中添加更新视图的函数,就不会多次更新视图。 在IE11以下的浏览器都不兼容,所以如果使用 Vue3 开发一个单页应用的项目,需要考虑到兼容性问题,需要我们做额外的很多操作,才能使得IE11 以下的版本能够兼容。 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!var proxy = new Proxy({}, {
get: function(target, propKey) {
return 35;
}
});
proxy.time // 35
proxy.name // 35
proxy.title // 35
proxy.foo
和proxy['foo']
。proxy.foo = v
或proxy['foo'] = v
,返回一个布尔值。propKey in proxy
的操作,返回一个布尔值。delete proxy[propKey]
的操作,返回一个布尔值。Object.getOwnPropertyNames(proxy)
、Object.getOwnPropertySymbols(proxy)
、Object.keys(proxy)
、for...in
循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()
的返回结果仅包括目标对象自身的可遍历属性。Object.getOwnPropertyDescriptor(proxy, propKey)
,返回属性的描述对象。Object.defineProperty(proxy, propKey, propDesc)
、Object.defineProperties(proxy, propDescs)
,返回一个布尔值。Object.preventExtensions(proxy)
,返回一个布尔值。Object.getPrototypeOf(proxy)
,返回一个对象。Object.isExtensible(proxy)
,返回一个布尔值。Object.setPrototypeOf(proxy, proto)
,返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。proxy(...args)
、proxy.call(object, ...args)
、proxy.apply(...)
。new proxy(...args)
。Reflect
Object
对象的一
些明显属于语言内部的方法(比如Object.defineProperty
),放到Reflect
对象上现阶段,某些方法同时在Object
和Reflect
对象上部署,未来的新方法将只部署在Reflect
对象上。也就是说,从Reflect
对象上可以拿到语言内部的方法。Object
方法的返回结果,让其变得更合理。比如,Object.defineProperty(obj, name, desc)
在无法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj, name, desc)
则会返回false
。// 老写法
try {
Object.defineProperty(target, property, attributes);
// success
} catch (e) {
// failure
}
// 新写法
if (Reflect.defineProperty(target, property, attributes)) {
// success
} else {
// failure
}
Object
操作都变成函数行为。某些Object
操作是命令式,比如name in obj
和delete obj[name]
,而Reflect.has(obj, name)
和Reflect.deleteProperty(obj, name)
让它们变成了函数行为。// 老写法
'assign' in Object // true
// 新写法
Reflect.has(Object, 'assign') // true
Reflect
对象的方法与Proxy
对象的方法一一对应,只要是Proxy
对象的方法,就能在Reflect
对象上找到对应的方法。这就让Proxy
对象可以方便地调用对应的Reflect
方法,完成默认行为,作为修改行为的基础。也就是说,不管Proxy
怎么修改默认行为,你总可以在Reflect
上获取默认行为。Proxy(target, {
set: function(target, name, value, receiver) {
var success = Reflect.set(target, name, value, receiver);
if (success) {
console.log('property ' + name + ' on ' + target + ' set to ' + value);
}
return success;
}
});
三、Vue3响应式原理的实现
function reactive (target){
// 返回一个响应式对象
return createReactiveObject(target);
}
Proxy
代理我们所需要的相应的对象,同时使用 Reflect
对象来映射。所以我们先初步实现一下,再慢慢优化,尽可能全面。function isObject(val){
return typeof val === 'object' && val !== null
}
初步实现
function createReactiveObject (target) {
// 首先由于Proxy所代理的是对象,所以我们需要判断target,若是原始值直接返回
if(!isObject(target)) {
return target;
}
let handler = {
get(target, key, receiver) {
let res = Reflect.get(target, key, receiver); // 使用Reflect对象做映射,不修改原对象
console.log('获取');
return res;
},
set(target, key, value, receiver) {
let res = Reflect.set(target, key, value, receiver);
console.log('修改');
return res
},
deleteProperty(target, key) {
let res = Reflect.deleteProperty(target, key)
console.log('删除');
return res;
}
}
let ProxyObj = new Proxy(target,handler); // 被代理过的对象
return ProxyObj;
}
解决代理对象内部有嵌套对象
get(target, key, receiver) {
let res = Reflect.get(target, key, receiver); // 使用Reflect对象做映射,不修改原对象
console.log('获取');
// 判断代理之后的对象是否内部含有对象,如果有的话就递归一次
return isObject(res) ? reactive(res) : res;
}
解决对象重复代理(多次代理、多层代理)
let proxy = reactive({name: '寒月十九', message: { like: 'coding' }});
reactive(proxy);
reactive(proxy);
reactive(proxy);
// WeakMap-弱引用对象,一旦弱引用对象未被使用,会被垃圾回收机制回收
let toProxy = new WeakMap(); // 存放形式 { 原对象(key): 代理过的对象(value)}
let toRow = new WeakMap(); // 存放形式 { 代理过的对象(key): 原对象(value)}
let ProxyObj = new Proxy(target,handler); // 被代理过的对象
toProxy.set(target,ProxyObj);
toRow.set(ProxyObj.target);
return ProxyObj;
let ByProxy = toProxy.get(target);
// 防止多次代理
if(ByProxy) { // 如果在WeakMap中可以取到值,则说明已经被代理过了,直接返回被代理过的对象
return ByProxy;
}
// 防止多层代理
if(toRow.get(target)) {
return target
}
// 为了防止下面这种写法(多层代理)
// let proxy2 = reactive(proxy);
// let proxy3 = reactive(proxy2);
// 其实本质上与下面这种写法没有区别(多次代理)
// reactive(proxy);
// reactive(proxy);
// reactive(proxy);
数组相应问题
let arr = [1 ,2 ,3 ,4];
let proxy = reactive(arr);
proxy.push(5);
// 在set内部其实会干两件事,首先会将5这个值添加到数组下标4的地方,并且会修改length的值
// 判断属性是否原本存在
function hasOwn(target,key) {
return target.hasOwnProperty(key);
}
set(target, key, value, receiver) {
let res = Reflect.set(target, key, value, receiver);
// 判断是新增属性还是修改属性
let hadKey = hasOwn(target,key);
let oldValue = target[key];
if(!hadKey) { // 新增属性
console.log('新增属性');
}else if(oldValue !== value){
console.log('修改属性');
}
return res
},
完整版代码
function isObject(val) {
return typeof val === 'object' && val !== null
}
function reactive(target) {
// 返回一个响应式对象
return createReactiveObject(target);
}
// 判断属性是否原本存在
function hasOwn(target, key) {
return target.hasOwnProperty(key);
}
// WeakMap-弱引用对象,一旦弱引用对象未被使用,会被垃圾回收机制回收
let toProxy = new WeakMap(); // 存放形式 { 原对象(key): 代理过的对象(value)}
let toRow = new WeakMap(); // 存放形式 { 代理过的对象(key): 原对象(value)}
function createReactiveObject(target) {
// 首先由于Proxy所代理的是对象,所以我们需要判断target,若是原始值直接返回
if (!isObject(target)) {
return target;
}
let ByProxy = toProxy.get(target);
// 防止多次代理
if (ByProxy) { // 如果在WeakMap中可以取到值,则说明已经被代理过了,直接返回被代理过的对象
return ByProxy;
}
// 防止多层代理
if (toRow.get(target)) {
return target
}
let handler = {
get(target, key, receiver) {
let res = Reflect.get(target, key, receiver); // 使用Reflect对象做映射,不修改原对象
console.log('获取');
return isObject(res) ? reactive(res) : res;
},
set(target, key, value, receiver) {
let res = Reflect.set(target, key, value, receiver);
// 判断是新增属性还是修改属性
let hadKey = hasOwn(target, key);
let oldValue = target[key];
if (!hadKey) { // 新增属性
console.log('新增属性');
} else if (oldValue !== value) {
console.log('修改属性');
}
return res
},
deleteProperty(target, key) {
let res = Reflect.deleteProperty(target, key)
console.log('删除');
return res;
}
}
let ProxyObj = new Proxy(target, handler); // 被代理过的对象
return ProxyObj;
}
// let proxy = reactive({name: '寒月十九'});
// proxy.name = '十九';
// console.log(proxy.name);
// delete proxy.name;
// console.log(proxy.name);
// let proxy = reactive({name: '寒月十九', message: { like: 'coding' }});
// proxy.message.like = 'writing';
// console.log('====================================');
// console.log(proxy.message.like);
// console.log('====================================');
let arr = [1, 2, 3, 4];
let proxy = reactive(arr);
proxy.push(5)
Proxy的缺陷

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Avec la popularité des appareils mobiles, la conception Web doit prendre en compte des facteurs tels que la résolution de l'appareil et la taille de l'écran des différents terminaux pour offrir une bonne expérience utilisateur. Lors de la mise en œuvre d'un design réactif d'un site Web, il est souvent nécessaire d'utiliser l'effet carrousel d'images pour afficher le contenu de plusieurs images dans une fenêtre visuelle limitée, et en même temps, cela peut également améliorer l'effet visuel du site Web. Cet article expliquera comment utiliser CSS pour obtenir un effet de carrousel automatique d'image réactif, et fournira des exemples de code et une analyse. Idées d'implémentation L'implémentation d'un carrousel d'images réactif peut être réalisée grâce à la mise en page flexible CSS. exister

PHP et Vue : une combinaison parfaite d'outils de développement front-end À l'ère actuelle de développement rapide d'Internet, le développement front-end est devenu de plus en plus important. Alors que les utilisateurs ont des exigences de plus en plus élevées en matière d’expérience des sites Web et des applications, les développeurs front-end doivent utiliser des outils plus efficaces et plus flexibles pour créer des interfaces réactives et interactives. En tant que deux technologies importantes dans le domaine du développement front-end, PHP et Vue.js peuvent être considérés comme une arme parfaite lorsqu'ils sont associés. Cet article explorera la combinaison de PHP et Vue, ainsi que des exemples de code détaillés pour aider les lecteurs à mieux comprendre et appliquer ces deux éléments.

Un didacticiel sur l'utilisation de CSS pour implémenter un menu coulissant réactif nécessite des exemples de code spécifiques. Dans la conception Web moderne, la conception réactive est devenue une compétence essentielle. Pour s'adapter à différents appareils et tailles d'écran, nous devons ajouter un menu réactif au site Web. Aujourd'hui, nous utiliserons CSS pour implémenter un menu coulissant réactif et vous fournirons des exemples de code spécifiques. Jetons d’abord un coup d’œil à la mise en œuvre. Nous allons créer une barre de navigation qui se réduit automatiquement lorsque la largeur de l'écran est inférieure à un certain seuil et s'agrandit en cliquant sur le bouton de menu.

Lors des entretiens de développement front-end, les questions courantes couvrent un large éventail de sujets, notamment les bases HTML/CSS, les bases JavaScript, les frameworks et les bibliothèques, l'expérience du projet, les algorithmes et les structures de données, l'optimisation des performances, les requêtes inter-domaines, l'ingénierie front-end, les modèles de conception et les nouvelles technologies et tendances. Les questions de l'intervieweur sont conçues pour évaluer les compétences techniques du candidat, son expérience en matière de projet et sa compréhension des tendances du secteur. Par conséquent, les candidats doivent être parfaitement préparés dans ces domaines pour démontrer leurs capacités et leur expertise.

En tant que développeur C#, notre travail de développement comprend généralement le développement front-end et back-end. À mesure que la technologie se développe et que la complexité des projets augmente, le développement collaboratif du front-end et du back-end est devenu de plus en plus important et complexe. Cet article partagera quelques techniques de développement collaboratif front-end et back-end pour aider les développeurs C# à effectuer leur travail de développement plus efficacement. Après avoir déterminé les spécifications de l’interface, le développement collaboratif du front-end et du back-end est indissociable de l’interaction des interfaces API. Pour assurer le bon déroulement du développement collaboratif front-end et back-end, le plus important est de définir de bonnes spécifications d’interface. La spécification de l'interface implique le nom de l'interface

Django est un framework d'application Web écrit en Python qui met l'accent sur un développement rapide et des méthodes propres. Bien que Django soit un framework Web, pour répondre à la question de savoir si Django est un front-end ou un back-end, vous devez avoir une compréhension approfondie des concepts de front-end et de back-end. Le front-end fait référence à l'interface avec laquelle les utilisateurs interagissent directement, et le back-end fait référence aux programmes côté serveur. Ils interagissent avec les données via le protocole HTTP. Lorsque le front-end et le back-end sont séparés, les programmes front-end et back-end peuvent être développés indépendamment pour mettre en œuvre respectivement la logique métier et les effets interactifs, ainsi que l'échange de données.

En tant que langage de programmation rapide et efficace, le langage Go est très populaire dans le domaine du développement back-end. Cependant, peu de gens associent le langage Go au développement front-end. En fait, l’utilisation du langage Go pour le développement front-end peut non seulement améliorer l’efficacité, mais également ouvrir de nouveaux horizons aux développeurs. Cet article explorera la possibilité d'utiliser le langage Go pour le développement front-end et fournira des exemples de code spécifiques pour aider les lecteurs à mieux comprendre ce domaine. Dans le développement front-end traditionnel, JavaScript, HTML et CSS sont souvent utilisés pour créer des interfaces utilisateur.

Django : Un framework magique capable de gérer à la fois le développement front-end et back-end ! Django est un framework d'application Web efficace et évolutif. Il est capable de prendre en charge plusieurs modèles de développement Web, notamment MVC et MTV, et peut facilement développer des applications Web de haute qualité. Django prend non seulement en charge le développement back-end, mais peut également créer rapidement des interfaces frontales et obtenir un affichage de vue flexible via un langage de modèle. Django combine le développement front-end et le développement back-end dans une intégration transparente, afin que les développeurs n'aient pas à se spécialiser dans l'apprentissage.
