[Day13] - 利用 Button 范例 - 解说 render 函式

昨天我们解说了 , Jquery 跟 Vue 两种处理 Dom 的模式

在文末 , 提到了 Web Component 中没有 Vue 可用 ,

不过我们可以建立 _render 函式 , 来达到资料的单向绑定

今天我们来建立 _render 函式 , 并利用 day-11 提到的 Proxy 来触发 _render 函式

达成资料的单向绑定


one 将昨天的 button 范例转换成 Web Component

将昨天的 my-button.vue 中的 style . script . template 三个区块放到相对应的位置

  • style 区块 , 在 class 上建立 style 属性 , 并将 this.styles 设定成 style 区块的内容
  • template 区块 , 建立一个 _render() 函式 , 将 template 区块的内容放这 , 并覆盖 rootDiv 的 innerHTML
  • methods 区块 , 直接放入 class 的内部 , 当成 class 的函式
  • computed 区块 , 直接放入 class 的内部 , 当成 class 的函式

// my-button.js
class MyButton01 extends HTMLElement {

  // style 的内容放这
  styles = `
    <style>
      button.btn {
        padding: 10px 20px;
        border-radius: 8px;
        font-size: 16px;
        color: white;
      }

      button:disabled {
        cursor: not-allowed;
      }
    </style>
  `

  connectedCallback() {

    this.attachShadow({mode: 'open'}).innerHTML = this.styles + `<div></div>`;
    this._render()
  }

  _render() {

    const rootDiv = this.shadowRoot.querySelector('div')

    // template 的内容放这
    rootDiv.innerHTML = `
        <div>
          <h2>目前有 <span class="left">{{left}}</span> 点数</h2>
          <h2>预计花费 <span class="cost">{{cost}}</span> 点数</h2>
          <button class="btn" :style="{backgroundColor:bgColor}" :disabled="disabled" @click="buy">
            购买
          </button>
          <h2></h2>
          <button @click="login">登入</button>
          <button @click="logout">登出</button>
          <h2></h2>
          <button @click="addCost(100)">加买法帐( 100 点 )</button>
          <button @click="minusCost(100)" :disabled="cost === 0">减买法帐( 100 点 )</button>
        </div>
    `
  }

  // computed . methods 的内容放在这里

}

window.customElements.define('my-button-01', MyButton01);

two 将昨天学到的 Proxy 建立

this.data = new Proxy

  data = new Proxy(
    // 将预设设定到 target 中
    {
      cost: 0,
      left: 500,
      isLogin: false
    },
    // handler set 资料後 , 执行 render 函式
    {
      get: (target, property) => target[property],
      set: (target, property, value) => {
        target[property] = value;
        this._render()
        return true
      },
    })

three 将 :XXX 的属性改成 ${} 的区块

  _render() {
  
    const rootDiv = this.shadowRoot.querySelector('div')
  
    // template 的内容放这
    rootDiv.innerHTML = `
        <h2>目前有 <span class="left">${this.data.left}</span> 点数</h2>
        <h2>预计花费 <span class="cost">${this.data.cost}</span> 点数</h2>
        <button class="btn" style="background-color: ${this.bgColor()};" ${this.disabled() ? 'disabled':'' } @click="buy">
          购买
        </button>
        <h2></h2>
        <button @click="login">登入</button>
        <button @click="logout">登出</button>
        <h2></h2>
        <button @click="addCost(100)">加买法帐( 100 点 )</button>
        <button @click="minusCost(100)" ${this.data.cost === 0 ? 'disabled':'' }>减买法帐( 100 点 )</button>
    `
  }

four 将 @click 的事件绑定到 dom 上

建立 vOn 函式

// the :params resolve
  vOn() {

    // 特殊字元 ( @ : ) 在 querySelector 的处理 - https://stackoverflow.com/questions/45110893/select-elements-by-attributes-with-colon
    const onClickEls = this.shadowRoot.querySelectorAll('button[\\@click]')

    onClickEls.forEach(el => {

      const onclickStr = el.getAttribute('@click')

      if (onclickStr.indexOf('(') > -1) {

        const fn = this[onclickStr.split('(')[0]]

        // 取得 () 中的参数设定

        const paramStrs = onclickStr.split('(')[1].replace(')', '').split(',')
        const param = paramStrs.map(param => {

          const numberReg = /^[\+\-]?\d*\.?\d+(?:[Ee][\+\-]?\d+)?$/

          if (param === 'true') return true
          else if (param === 'false') return false
          else if (param === 'false') return false
          else if (numberReg.test(param)) return parseFloat(param)
          else if (this.data[param]) return this.data[param]
          else return param
        })

        el.addEventListener('click', e => fn.call(this, ...param))

      } else {

        const fn = this[onclickStr]
        el.addEventListener('click', e => fn.call(this, e))
      }

    })
  }

每次 _render 时 , 呼叫 vOn() , 绑定 @click 事件

 _render() {

    // ...之前的 Code

    this.vOn()
  }

大功告成 ~~~~~

成果

如果想直接体验成果 , 请到 web-component-render.html 查看

参考资料 :


<<:  Re: 新手让网页 act 起来: Day02 - 永远的起点 Hello world!

>>:  17.unity显示/隐藏物件(SetActive)

【Day10】AddInvitationFragment(下) X DatePickerDialog

接下上集!!,我们已经完成layout,还有上传照片了。那麽接下来我们要做的就是把选取时间的日历叫...

Day 22 Context

第 22 天 ! 当我们资料项下传递的时候, 会发现, component 的阶层越深, 传递资讯会...

Day10 - 除噪模型

在 Day01 的时候我们有提到过资料可能会有杂讯、噪音,因此所使用的模型架构可以分为两个阶段:除噪...

儿童程序教学

儿童程序教学 https://wolkesau.medium.com/73094f76b216 儿童...

GoDaddy 设定 DNS 转址到 IIS 上指定网站

当我们在 GoDaddy 上申请好网域之後,就接着要把 GoDaddy 上的 DNS 转址到我们的服...