Cet article présente principalement un résumé des trois méthodes de javascript pour réaliser une liaison de données bidirectionnelle. La couche de vue frontale et la couche de données doivent parfois implémenter deux-. liaison bidirectionnelle. Actuellement, les données sont implémentées. Il existe trois principaux types de liaison bidirectionnelle. Ceux qui sont intéressés peuvent en apprendre davantage.
Méthode de liaison bidirectionnelle des données frontales
La couche de vue et la couche de données du front-end doivent parfois implémenter une liaison bidirectionnelle (liaison bidirectionnelle), par exemple le framework mvvm, la vue basée sur les données, la machine à états de vue, etc., nous avons étudié plusieurs cadres actuels de liaison de données bidirectionnelle et les avons résumés. Actuellement, il existe trois manières principales d’implémenter la liaison de données bidirectionnelle :
1. Liaison manuelle
L'ancienne méthode d'implémentation est un peu comme le mode observateurprogrammation L'idée principale est d'utiliser. Définissez les méthodes get et set sur l'objet data (bien sûr, il existe d'autres méthodes), appelez manuellement get ou set data lors de l'appel et démarrez l'opération de rendu de la couche d'interface utilisateur après avoir modifié les données ; utilisé dans les scénarios où la vue entraîne des modifications de données. Avec input, select, textarea et d'autres éléments, lorsque la couche d'interface utilisateur change, des événements tels que le changement, la pression sur une touche, le keyup et d'autres événements du DOM sont surveillés pour déclencher des événements permettant de modifier les données du DOM. couche de données. L'ensemble du processus est complété par des appels de fonction.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>data-binding-method-set</title> </head> <body> <input q-value="value" type="text" id="input"> <p q-text="value" id="el"></p> <script> var elems = [document.getElementById('el'), document.getElementById('input')]; var data = { value: 'hello!' }; var command = { text: function(str){ this.innerHTML = str; }, value: function(str){ this.setAttribute('value', str); } }; var scan = function(){ /** * 扫描带指令的节点属性 */ for(var i = 0, len = elems.length; i < len; i++){ var elem = elems[i]; elem.command = []; for(var j = 0, len1 = elem.attributes.length; j < len1; j++){ var attr = elem.attributes[j]; if(attr.nodeName.indexOf('q-') >= 0){ /** * 调用属性指令,这里可以使用数据改变检测 */ command[attr.nodeName.slice(2)].call(elem, data[attr.nodeValue]); elem.command.push(attr.nodeName.slice(2)); } } } } /** * 设置数据后扫描 */ function mvSet(key, value){ data[key] = value; scan(); } /** * 数据绑定监听 */ elems[1].addEventListener('keyup', function(e){ mvSet('value', e.target.value); }, false); scan(); /** * 改变数据更新视图 */ setTimeout(function(){ mvSet('value', 'fuck'); },1000) </script> </body> </html>
2. Mécanisme de vérification sale
Représenté par le framework mvvm typique angularjs, angulaire détecte les données sales Effectuer des mises à jour opérationnelles sur la couche UI. Il y a quelques choses que vous devez savoir sur la détection sale d'Angular : - Le mécanisme de détection sale n'utilise pas la détection planifiée. - Le moment de la détection sale correspond au moment où les données changent. - Angular encapsule les événements DOM, les événements XHR, etc. couramment utilisés, et déclenche le processus de résumé d'entrée dans Angular. - Dans le processus de digestion, il traversera le rootscope et vérifiera tous les observateurs. (Pour la conception spécifique d'Angular, vous pouvez voir d'autres documents, ici nous discutons uniquement de la liaison de données), voyons ensuite comment effectuer une détection sale : principalement à travers les données définies pour trouver tous les éléments liés aux données, puis comparer les données change, si cela change, effectuez des opérations de commande
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>data-binding-drity-check</title> </head> <body> <input q-event="value" ng-bind="value" type="text" id="input"> <p q-event="text" ng-bind="value" id="el"></p> <script> var elems = [document.getElementById('el'), document.getElementById('input')]; var data = { value: 'hello!' }; var command = { text: function(str) { this.innerHTML = str; }, value: function(str) { this.setAttribute('value', str); } }; var scan = function(elems) { /** * 扫描带指令的节点属性 */ for (var i = 0, len = elems.length; i < len; i++) { var elem = elems[i]; elem.command = {}; for (var j = 0, len1 = elem.attributes.length; j < len1; j++) { var attr = elem.attributes[j]; if (attr.nodeName.indexOf('q-event') >= 0) { /** * 调用属性指令 */ var dataKey = elem.getAttribute('ng-bind') || undefined; /** * 进行数据初始化 */ command[attr.nodeValue].call(elem, data[dataKey]); elem.command[attr.nodeValue] = data[dataKey]; } } } } /** * 脏循环检测 * @param {[type]} elems [description] * @return {[type]} [description] */ var digest = function(elems) { /** * 扫描带指令的节点属性 */ for (var i = 0, len = elems.length; i < len; i++) { var elem = elems[i]; for (var j = 0, len1 = elem.attributes.length; j < len1; j++) { var attr = elem.attributes[j]; if (attr.nodeName.indexOf('q-event') >= 0) { /** * 调用属性指令 */ var dataKey = elem.getAttribute('ng-bind') || undefined; /** * 进行脏数据检测,如果数据改变,则重新执行指令,否则跳过 */ if(elem.command[attr.nodeValue] !== data[dataKey]){ command[attr.nodeValue].call(elem, data[dataKey]); elem.command[attr.nodeValue] = data[dataKey]; } } } } } /** * 初始化数据 */ scan(elems); /** * 可以理解为做数据劫持监听 */ function $digest(value){ var list = document.querySelectorAll('[ng-bind='+ value + ']'); digest(list); } /** * 输入框数据绑定监听 */ if(document.addEventListener){ elems[1].addEventListener('keyup', function(e) { data.value = e.target.value; $digest(e.target.getAttribute('ng-bind')); }, false); }else{ elems[1].attachEvent('onkeyup', function(e) { data.value = e.target.value; $digest(e.target.getAttribute('ng-bind')); }, false); } setTimeout(function() { data.value = 'fuck'; /** * 这里问啥还要执行$digest这里关键的是需要手动调用$digest方法来启动脏检测 */ $digest('value'); }, 2000) </script> </body> </html>
3. Détournement de données frontales (piratage)
La troisième méthode est avalon et autres. frameworks La méthode de détournement de données utilisée. L'idée de base est d'utiliser Object.defineProperty pour surveiller la propriété get et set de l'objet de données. Lorsqu'il y a des opérations de lecture et d'affectation de données, les instructions du nœud sont appelées de cette manière, l'affectation de signe = égal la plus courante peut être utilisée. . L'implémentation spécifique est la suivante :
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>data-binding-hijacking</title> </head> <body> <input q-value="value" type="text" id="input"> <p q-text="value" id="el"></p> <script> var elems = [document.getElementById('el'), document.getElementById('input')]; var data = { value: 'hello!' }; var command = { text: function(str) { this.innerHTML = str; }, value: function(str) { this.setAttribute('value', str); } }; var scan = function() { /** * 扫描带指令的节点属性 */ for (var i = 0, len = elems.length; i < len; i++) { var elem = elems[i]; elem.command = []; for (var j = 0, len1 = elem.attributes.length; j < len1; j++) { var attr = elem.attributes[j]; if (attr.nodeName.indexOf('q-') >= 0) { /** * 调用属性指令 */ command[attr.nodeName.slice(2)].call(elem, data[attr.nodeValue]); elem.command.push(attr.nodeName.slice(2)); } } } } var bValue; /** * 定义属性设置劫持 */ var defineGetAndSet = function(obj, propName) { try { Object.defineProperty(obj, propName, { get: function() { return bValue; }, set: function(newValue) { bValue = newValue; scan(); }, enumerable: true, configurable: true }); } catch (error) { console.log("browser not supported."); } } /** * 初始化数据 */ scan(); /** * 可以理解为做数据劫持监听 */ defineGetAndSet(data, 'value'); /** * 数据绑定监听 */ if(document.addEventListener){ elems[1].addEventListener('keyup', function(e) { data.value = e.target.value; }, false); }else{ elems[1].attachEvent('onkeyup', function(e) { data.value = e.target.value; }, false); } setTimeout(function() { data.value = 'fuck'; }, 2000) </script> </body> </html>
Mais il convient de noter que définirProperty prend en charge les navigateurs supérieurs à IE8. Ici, vous pouvez utiliser définirGetter et définirSetter pour des raisons de compatibilité. Cependant, en raison de la compatibilité du navigateur, utilisez simplement définirProperty directement. Quant au navigateur IE8, d'autres méthodes doivent encore être utilisées pour pirater. Le code suivant peut pirater IE8 et DefineProperty prend en charge IE8. Par exemple, utilisez simplement es5-shim.js. (Ignoré par les navigateurs inférieurs à IE8)
4. Résumé
Tout d'abord, les exemples ici ne sont que de simples implémentations. Les différences entre les trois méthodes et les cadres complexes font également boule de neige grâce à cette idée de base.
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!