js手写MVC模式

效果图如下:
在这里插入图片描述
代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .personalData {
      display: none;
    }
  </style>
</head>
<body>
  <div class="dataInputArea">
    <div>
      <span>请输入个人的姓名</span>
      <input type="text" placeholder="姓名" class="nameData">
    </div>
    <div>
      <span>请输入个人的年龄</span>
      <input type="text" placeholder="年龄" class="ageData">
    </div>
    <div>
      <span>请输入个人的特长</span>
      <input type="text" placeholder="特长" class="specData">
    </div>
    <div class="personalData">
      <p>
        本人: <span class="name">王大少</span>,今年芳龄 <span class="age">0</span>,擅长 <span class="spec">吃饭</span>
      </p>
    </div>
  </div>
  <script>
	 //MVC模式
    class MVC {
      constructor (options) {
        this.model = options.model    //获取操作元素 负责事件的订阅与发布
        this.controller = options.controller  //事件绑定并订阅事件
        this.view = options.view      //更新页面数据
        this.controller.bundle(this)  //激活控制器
      }
    }
    let mvc = new MVC({
      model: {
        data: {
          vNameObj: document.querySelector('.nameData'),
          vAgeObj: document.querySelector('.ageData'),
          vSpecObj: document.querySelector('.specData'),
          oName: document.querySelector('.name'),
          oAge: document.querySelector('.age'),
          oSpec: document.querySelector('.spec'),
          oPersonal: document.querySelector('.personalData'),
          nameValue: 0,
          ageValue: 0,
          specValue: 0
        },
        observe: {
          clientList: {},
          //订阅
          listen (key, fn) {
            if (!this.clientList[key]) {
              this.clientList[key] = []
            }
            this.clientList[key].push(fn)
          },
          //发布
          trigger () {
            //获取第一个参数 发布的函数数组键名
            let key = Array.prototype.shift.call(arguments)
            let fns = this.clientList[key]
            if (!fns || fns.length === 0) {
              return false
            }
            for (let i=0, fn; fn =fns[i++];) {
              fn.apply(this,arguments)
            }
          },
          update (o, key, value) {  //(MVC的this, '发布事件名', '改变的值')
            let valueKey = '',
                targetKey = '';
            switch (key) {
              case 'vNameObj':
                valueKey = "nameValue" //数据内容变量
                targetKey = "oName"    //对应标签
                break;
              case 'vAgeObj':
                valueKey = "ageValue"
                targetKey = "oAge"
                break;
              case 'vSpecObj':
                valueKey = "specValue"
                targetKey = "oSpec"
                break;
            }
            //更改MVC的this内的nameValue,ageValue,specValue值
            o.model.data[valueKey] = value
            //发布事件oName,oAge,oSpec
            o.model.observe.trigger(targetKey, value)
          }
        }
      },
      controller: {
        bundle (o) {  //o指向MVC的this
          let that = o
          //给input标签添加监听事件
          that.model.data.vNameObj.oninput = function () {
            //通过更新事件 刷新数据(MVC的this, '发布事件名', '改变的值')
            that.model.observe.update(that, "vNameObj", this.value)
          }
          that.model.data.vAgeObj.oninput = function () {
            that.model.observe.update(that, "vAgeObj", this.value)
          }
          that.model.data.vSpecObj.oninput = function () {
            that.model.observe.update(that, "vSpecObj", this.value)
          }

          //订阅事件oName,oAge,oSpec
          that.model.observe.listen("oName", function (value) {
            that.view.update(that, "oName", value)
          })
          that.model.observe.listen("oAge", function (value) {
            that.view.update(that, "oAge", value)
          })
          that.model.observe.listen("oSpec", function (value) {
            that.view.update(that, "oSpec", value)
          })
        }
      },
      view: {
        update (o, targetKey, value) {
          let that = o
          //给页面标签设置内容
          that.model.data[targetKey].innerText = value,
          {nameValue, ageValue, specValue, oPersonal} = that.model.data;
          //监听.oPersonal标签是否显示
          if (nameValue && ageValue && specValue) {
            oPersonal.style.display = "block"
          } else {
            oPersonal.style.display = "none"
          }
        }
      }
    })
    /* MVC原理:
    controller.bundle()绑定订阅事件 ——> 输入触发oninput事件
    ——> model.observe.update发布订阅事件 ——>执行对应订阅的事件
    ——> view.update() 修改页面对应数据
    */

    /*  普通模式
    let vNameObj = document.querySelector('.nameData'),
        vAgeObj= document.querySelector('.ageData'),
        vSpecObj = document.querySelector('.specData'),
        oName = document.querySelector('.name'),
        oAge = document.querySelector('.age'),
        oSpec = document.querySelector('.spec'),
        oPersonal = document.querySelector('.personalData'),
        nameValue, ageValue, specValue;

    //   Controller控制模块
    vNameObj.onchange = function (ev) {
      nameValue = this.value
      setObjInnerText(oName, nameValue)
    }
    vAgeObj.onchange = function (ev) {
      ageValue = this.value
      setObjInnerText(oAge, ageValue)
    }
    vSpecObj.onchange = function (ev) {
      specValue = this.value
      setObjInnerText(oSpec, specValue)
    }

    //    view视图模块
    function setObjInnerText(obj, value) {
      obj.innerText = value
      if (nameValue && ageValue && specValue) {
        oPersonal.style.display = "block"
      } else {
        oPersonal.style.display = "none"
      }
    }
    */
  </script>
</body>
</html>

逻辑结构图如下:
在这里插入图片描述

发布了218 篇原创文章 · 获赞 35 · 访问量 13万+

猜你喜欢

转载自blog.csdn.net/qq_41614928/article/details/104338554