Maison > interface Web > js tutoriel > Explication détaillée de l'utilisation du modèle éditeur-abonné js

Explication détaillée de l'utilisation du modèle éditeur-abonné js

php中世界最好的语言
Libérer: 2018-04-18 15:21:17
original
2981 Les gens l'ont consulté

Cette fois, je vais vous apporter une explication détaillée de l'utilisation du modèle éditeur-abonné js. Quelles sont les précautions lors de l'utilisation du modèle éditeur-abonné js. Ce qui suit est un cas pratique, allons-y. jetez un oeil.

Le modèle éditeur-abonné est un modèle très courant, tel que :

1. Acheter et vendre une maison

Lors de l'achat ou de la vente d'une maison en viager, les intermédiaires forment un modèle de publication-abonné. Les personnes qui achètent une maison ont généralement besoin d'informations telles que la disponibilité du logement, le prix, la surface utilisable, etc. Il joue le rôle d'un abonné

L'intermédiaire obtient les informations sur la maison du vendeur et en informe l'acheteur en fonction des coordonnées client qu'il a en main (le numéro de téléphone portable de la personne qui achète la maison). Il agit en tant qu'éditeur

. Si le vendeur souhaite vendre sa maison, il doit en informer l'agent et lui remettre les informations pour qu'il les libère

2. Les utilisateurs qui s'abonnent aux informations du site

Rôle d'abonné : Internautes qui ont besoin de s'abonner à certains types d'informations, comme par exemple des articles de type javascript

sur un site internet Rôle d'éditeur : serveur de boîtes aux lettres, informe les utilisateurs en fonction des boîtes aux lettres d'abonnement des utilisateurs collectées par le site Web

. Si le propriétaire du site Web souhaite informer les abonnés, il doit indiquer au serveur de messagerie le contenu pertinent de l'article à envoyer

Il y a tellement d’exemples, je ne vais pas tous les énumérer

Cet article utilise l'abonnement au site Web pour dériver le cadre éditeur-abonné, puis utilise le cadre éditeur-abonné pour reconstruire un simple panier d'achat

var Site = {};
    Site.userList = [];
    Site.subscribe = function( fn ){
      this.userList.push( fn );
    }
    Site.publish = function(){
      for( var i = 0, len = this.userList.length; i < len; i++ ){
        this.userList[i].apply( this, arguments );
      } 
    }
    Site.subscribe( function( type ){
      console.log( "网站发布了" + type + "内容" );
    });
    Site.subscribe( function( type ){
      console.log( "网站发布了" + type + "内容" );
    });
    Site.publish( &#39;javascript&#39; );
    Site.publish( &#39;html5&#39; );
Copier après la connexion

Site.userList est utilisé pour enregistrer les abonnés

Site.subscribe est un abonné spécifique. Les informations spécifiques souscrites par chaque abonné sont enregistrées dans Site.userList

. Site.publish est l'éditeur : selon la liste d'utilisateurs enregistrée, parcourez (notifiez) un par un et exécutez la logique métier à l'intérieur de

Mais ce modèle d'abonné publié a un problème. Il ne peut pas s'abonner au type souhaité. Dans l'exemple ci-dessus, j'ai ajouté 2 abonnés (ligne 11, ligne 14). Tant que le site Web envoie des informations, tous les messages peuvent être reçus. mais certains utilisateurs peuvent vouloir uniquement recevoir du javascript ou du html5, donc ensuite, nous devons continuer à nous améliorer, en espérant recevoir des informations spécifiques si ce n'est pas le type d'abonnement de quelqu'un, nous ne les recevrons pas

var Site = {};
    Site.userList = {};
    Site.subscribe = function (key, fn) {
      if (!this.userList[key]) {
        this.userList[key] = [];
      }
      this.userList[key].push(fn);
    }
    Site.publish = function () {
      var key = Array.prototype.shift.apply(arguments),
        fns = this.userList[key];
      if ( !fns || fns.length === 0) {
        console.log( &#39;没有人订阅&#39; + key + "这个分类的文章" );
        return false;
      }
      for (var i = 0, len = fns.length; i < len; i++) {
        fns[i].apply(this, arguments);
      }
    }
    Site.subscribe( "javascript", function( title ){
      console.log( title );
    });
    Site.subscribe( "es6", function( title ){
      console.log( title );
    });
    Site.publish( "javascript", "[js高手之路]寄生组合式继承的优势" );
    Site.publish( "es6", "[js高手之路]es6系列教程 - var, let, const详解" );
    Site.publish( "html5", "html5新的语义化标签" );
Copier après la connexion
<. 🎜> Résultat de sortie :

[La route vers un maître JS] Avantages de l'héritage combinatoire parasitaire

[JS master's road] Tutoriels de la série es6 - explication détaillée de var, let, const

Personne n'est abonné aux articles de la catégorie html5

On voit que seuls ceux qui s'abonnent à l'article de type JavaScript peuvent recevoir l'article "Avantages de l'héritage combinatoire parasitaire". Lorsque le type HTML5 sera publié, personne ne le recevra

. type es6, seuls ceux qui sont abonnés à es6 peuvent recevoir

Nous disposons déjà d'un cadre de base éditeur-abonné. Ensuite, nous l'améliorerons en un cadre afin que d'autres fonctions ou les mêmes fonctions d'autres systèmes de sites Web puissent le réutiliser

var Event = {
      userList : {},
      subscribe : function (key, fn) {
        if (!this.userList[key]) {
          this.userList[key] = [];
        }
        this.userList[key].push(fn);
      },
      publish : function () {
        var key = Array.prototype.shift.apply(arguments),
          fns = this.userList[key];
        if (!fns || fns.length === 0) {
          console.log(&#39;没有人订阅&#39; + key + "这个分类的文章");
          return false;
        }
        for (var i = 0, len = fns.length; i < len; i++) {
          fns[i].apply(this, arguments);
        }
      }
    };
    var extend = function( dstObj, srcObj ){
      for( var key in srcObj ){
        dstObj[key] = srcObj[key];
      }
    }
    var Site = {};
    extend( Site, Event );
     Site.subscribe( "javascript", function( title ){
      console.log( title );
    });
    Site.subscribe( "es6", function( title ){
      console.log( title );
    });
    Site.publish( "javascript", "寄生组合式继承的优势" );
    Site.publish( "es6", "es6系列教程 - var, let, const详解" );
    Site.publish( "html5", "html5新的语义化标签" );
Copier après la connexion
Ensuite, refactorisons une instance de panier d'achat. Avant la refactorisation, mon panier d'achat était orienté processus :

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <script src="js/cart.js"></script>
</head>
<body>
<p id="box">
  <ul>
    <li>
      <input type="button" value="-">
      <span class="num">0</span>
      <input type="button" value="+">
      <span>单价:</span>
      <span class="unit">15元;</span>
      <span class="label">小计:</span>
      <span class="subtotal">0</span>元
    </li>
    <li>
      <input type="button" value="-">
      <span class="num">0</span>
      <input type="button" value="+">
      <span>单价:</span>
      <span class="unit">10元;</span>
      <span class="label">小计:</span>
      <span class="subtotal">0</span>元
    </li>
    <li>
      <input type="button" value="-">
      <span class="num">0</span>
      <input type="button" value="+">
      <span>单价:</span>
      <span class="unit">5元;</span>
      <span class="label">小计:</span>
      <span class="subtotal">0</span>元
    </li>
    <li>
      <input type="button" value="-">
      <span class="num">0</span>
      <input type="button" value="+">
      <span>单价:</span>
      <span class="unit">2元;</span>
      <span class="label">小计:</span>
      <span class="subtotal">0</span>元
    </li>
    <li>
      <input type="button" value="-">
      <span class="num">0</span>
      <input type="button" value="+">
      <span>单价:</span>
      <span class="unit">1元;</span>
      <span class="label">小计:</span>
      <span class="subtotal">0</span>元
    </li>
  </ul>
  <p class="total-box">
    商品一共
    <span id="goods-num">0</span>
    件;
    一共花费
    <span id="total-price">0</span>
    元;
    其中最贵的商品单价是<span id="unit-price">0</span>元
  </p>
</p>
</body>
</html>
Copier après la connexion
. Fichier cart.js :

function getByClass(cName, obj) {
  var o = null;
  if (arguments.length == 2) {
    o = obj;
  } else {
    o = document;
  }
  var allNode = o.getElementsByTagName("*");
  var aNode = [];
  for( var i = 0 ; i < allNode.length; i++ ){
    if( allNode[i].className == cName ){
     aNode.push( allNode[i] );
    }
  }
  return aNode;
}
function getSubTotal( unitPrice, goodsNum ){
  return unitPrice * goodsNum;
}
function getSum(){ //计算总花费
  var aSubtotal = getByClass("subtotal");
  var res = 0;
  for( var i = 0; i < aSubtotal.length; i++ ){
    res += parseInt(aSubtotal[i].innerHTML);
  }
  return res;
}
function compareUnit() { //比单价,找出最高的单价
  var aNum = getByClass( "num");
  var aUnit = getByClass( "unit");
  var temp = 0;
  for( var i = 0; i < aNum.length; i++ ){
    if( parseInt(aNum[i].innerHTML) != 0 ){
      if( temp < parseInt(aUnit[i].innerHTML) ) {
        temp = parseInt(aUnit[i].innerHTML);
      }
    }
  }
  return temp;
}
window.onload = function () {
  var aInput = document.getElementsByTagName("input");
  var total = 0;
  var oGoodsNum = document.getElementById("goods-num");
  var oTotalPrice = document.getElementById("total-price");
  var oUnitPrice = document.getElementById("unit-price");
  for (var i = 0; i < aInput.length; i++) {
    if (i % 2 != 0) { //加号
      aInput[i].onclick = function () {
        //当前加号所在行的数量
        var aNum = getByClass( "num", this.parentNode );
        var n = parseInt( aNum[0].innerHTML );
        n++;
        aNum[0].innerHTML = n;
        //获取单价
        var aUnit = getByClass( "unit", this.parentNode );
        var unitPrice = parseInt(aUnit[0].innerHTML);
        var subtotal = getSubTotal( unitPrice, n );
        var aSubtotal = getByClass( "subtotal", this.parentNode );
        aSubtotal[0].innerHTML = subtotal;
        total++; //商品总数
        oGoodsNum.innerHTML = total;
        oTotalPrice.innerHTML = getSum();
        oUnitPrice.innerHTML = compareUnit();
      }
    }else {
      aInput[i].onclick = function(){
        var aNum = getByClass( "num", this.parentNode );
        if ( parseInt( aNum[0].innerHTML ) != 0 ){
          var n = parseInt( aNum[0].innerHTML );
          n--;
          aNum[0].innerHTML = n;
          //获取单价
          var aUnit = getByClass( "unit", this.parentNode );
          var unitPrice = parseInt(aUnit[0].innerHTML);
          var subtotal = getSubTotal( unitPrice, n );
          var aSubtotal = getByClass( "subtotal", this.parentNode );
          aSubtotal[0].innerHTML = subtotal;
          total--; //商品总数
          oGoodsNum.innerHTML = total;
          oTotalPrice.innerHTML = getSum();
          oUnitPrice.innerHTML = compareUnit();
        }
      }
    }
  }
}
Copier après la connexion
Le degré de couplage est trop élevé et la maintenabilité est très mauvaise.

Panier après reconstruction :

window.onload = function () {
  var Event = {
    userList: {},
    subscribe: function (key, fn) {
      if (!this.userList[key]) {
        this.userList[key] = [];
      }
      this.userList[key].push(fn);
    },
    publish: function () {
      var key = Array.prototype.shift.apply(arguments),
        fns = this.userList[key];
      if (!fns || fns.length === 0) {
        return false;
      }
      for (var i = 0, len = fns.length; i < len; i++) {
        fns[i].apply(this, arguments);
      }
    }
  };
  (function(){
    var aBtnMinus = document.querySelectorAll( "#box li>input:first-child"),
      aBtnPlus = document.querySelectorAll( "#box li>input:nth-of-type(2)"),
      curNum = 0, curUnitPrice = 0;
    for( var i = 0, len = aBtnMinus.length; i < len; i++ ){
      aBtnMinus[i].index = aBtnPlus[i].index = i;
      aBtnMinus[i].onclick = function(){
        (this.parentNode.children[1].innerHTML > 0) && Event.publish( "total-goods-num-minus" );
        --this.parentNode.children[1].innerHTML < 0 && (this.parentNode.children[1].innerHTML = 0);
        curUnitPrice = this.parentNode.children[4].innerHTML;
        Event.publish( "minus-num" + this.index, 
          parseInt( curUnitPrice ),
          parseInt( this.parentNode.children[1].innerHTML )
        );
      };
      aBtnPlus[i].onclick = function(){
        (this.parentNode.children[1].innerHTML >= 0) && Event.publish( "total-goods-num-plus" );
        this.parentNode.children[1].innerHTML++;
        curUnitPrice = this.parentNode.children[4].innerHTML;
        Event.publish( "plus-num" + this.index, 
          parseInt( curUnitPrice ),
          parseInt( this.parentNode.children[1].innerHTML )
        );
      }
    }
  })();
  (function(){
    var aSubtotal = document.querySelectorAll("#box .subtotal"),
      oGoodsNum = document.querySelector("#goods-num"),
      oTotalPrice = document.querySelector("#total-price");
      Event.subscribe( 'total-goods-num-plus', function(){
        ++oGoodsNum.innerHTML;
      });
      Event.subscribe( 'total-goods-num-minus', function(){
        --oGoodsNum.innerHTML;
      });
    for( let i = 0, len = aSubtotal.length; i < len; i++ ){
      Event.subscribe( 'minus-num' + i, function( unitPrice, num ){
        aSubtotal[i].innerHTML = unitPrice * num;
      });
      Event.subscribe( 'plus-num' + i, function( unitPrice, num ){
        aSubtotal[i].innerHTML = unitPrice * num;
      });
    }
  })();
  console.log( Event.userList );
}
Copier après la connexion
Je pense que vous maîtrisez la méthode après avoir lu le cas dans cet article. Pour des informations plus intéressantes, veuillez prêter attention aux autres articles connexes sur le site Web chinois de PHP !

Lecture recommandée :

Quelles sont les méthodes de déconstruction es6

Fonctionnement du système de fichiers Node.js

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!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal