>웹 프론트엔드 >JS 튜토리얼 >js 게시자-구독자 패턴 사용에 대한 자세한 설명

js 게시자-구독자 패턴 사용에 대한 자세한 설명

php中世界最好的语言
php中世界最好的语言원래의
2018-04-18 15:21:172963검색

이번에는 js 게시자-구독자 모델 사용에 대해 자세히 설명하겠습니다. js 게시자-구독자 모델을 사용할 때 주의 사항은 무엇입니까?

게시자-구독자 모델은 다음과 같은 매우 일반적인 모델입니다.

1. 집 사고팔기

생활 속에서 주택을 사고파는 중개자는 게시-구독자 모델을 형성합니다. 주택을 구입하는 사람은 일반적으로 주택 가용성, 가격, 사용 가능 면적 등과 같은 정보가 필요합니다. 그는 구독자 역할을 합니다

에이전트는 판매자의 집 정보를 받아 구매자가 보유하고 있는 고객 연락처(집을 구입한 사람의 휴대폰 번호)를 기반으로 구매자에게 알리고 게시자의 역할을 합니다

매도인이 집을 팔고 싶다면 중개인에게 알리고 중개업자에게 정보를 주어야 합니다

2. 홈페이지 정보를 구독하는 사용자

구독자 역할: 웹사이트의 javascript 유형 기사

와 같은 특정 유형의 정보를 구독해야 하는 인터넷 사용자 게시자 역할: 메일박스 서버, 웹사이트에서 수집한 사용자 구독 메일함을 기반으로 사용자에게 알립니다.

웹사이트 소유자가 구독자 정보를 알리고 싶다면 보낼 기사의 관련 내용을 이메일 서버에 알려야 합니다

예시가 너무 많아서 다 나열하진 않겠습니다

이 기사에서는 웹사이트 구독을 사용하여 게시자-구독자 프레임워크를 파생한 다음 게시자-구독자 프레임워크를 사용하여 간단한 장바구니를 재구성합니다

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; );

Site.userList는 구독자를 저장하는 데 사용됩니다

Site.subscribe는 특정 구독자이며 각 구독자가 구독한 특정 정보를 Site.userList

에 저장합니다. Site.publish는 게시자입니다. 저장된 userList에 따라 하나씩 탐색(알림)하고 내부에서 비즈니스 로직을 실행합니다

하지만 이 게시-구독자 모델에는 원하는 유형을 구독할 수 없다는 문제가 있습니다. 위의 예에서는 2명의 구독자를 추가했습니다(11번째 줄, 14번째 줄). 웹사이트에서 정보를 보내는 한 모든 메시지를 받을 수 있습니다. , 하지만 일부 사용자는 javascript 또는 html5 만 수신하기를 원할 수 있으므로 다음에는 특정 정보를 수신하기를 바라며 계속 개선해야 합니다. 누군가가 구독하는 유형이 아닌 경우 수신되지 않습니다

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新的语义化标签" );

출력 결과:

[JS 마스터스로드] 기생 조합 상속의 장점

[JS 마스터가 되는 길] es6 튜토리얼 시리즈 - var, let, const에 대한 자세한 설명

html5

카테고리의 기사를 구독한 사람이 없습니다. JavaScript 유형의 기사를 구독하는 사람만이 "기생 조합 상속의 장점" 기사를 받을 수 있음을 알 수 있습니다. HTML5 유형을 게시하면 아무도 그것을 받을 수 없습니다.

es6형, es6 구독자만 받아보실 수 있어요

우리는 이미 기본적인 발행자-구독자 프레임워크를 가지고 있습니다. 다음에는 다른 기능이나 다른 웹사이트 시스템의 동일한 기능을 재사용할 수 있도록 프레임워크로 개선하겠습니다

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新的语义化标签" );

그런 다음 장바구니 인스턴스를 리팩토링해 보겠습니다. 리팩토링하기 전에는 장바구니가 프로세스 중심이었습니다.

<!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>

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();
        }
      }
    }
  }
}

결합도가 너무 높아 유지보수성이 매우 떨어집니다.

재구성 후 장바구니:

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 );
}

이 기사의 사례를 읽으신 후 방법을 마스터하셨다고 믿습니다. 더 흥미로운 정보를 보려면 PHP 중국어 웹사이트의 다른 관련 기사를 주목하세요!

추천 도서:

es6

Node.js 파일 시스템 작동을 분해하는 방법은 무엇입니까

위 내용은 js 게시자-구독자 패턴 사용에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.