Sunny-117 / js-challenges

✨✨✨ Challenge your JavaScript programming limits step by step

Home Page:https://juejin.cn/column/7244788137410560055

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

手写简易版 v-bind

jlx2002 opened this issue · comments

commented

好久之前写的练习代码,后续会更新一份优化后的代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <!--
        简要思路: 
        1. 首先确定的是v-bind 是单向绑定,不需要对绑定的元素进行监视
        2. v-bind 渲染的话,是对整个dom树上的有效元素中进行渲染
        3. v-bind:src ="" 等价于 :src ="" 
        黑名单指["head", "body", "script", "html"] 这些无效元素
        效果步骤实现:
        0. 通过字典来mock数据,比如 {"msg":"hello"}
        1. 获取整个dom树中所有元素,并且筛出非黑名单里面的元素,将这些元素存入tagList
        2. 检查每个元素的属性名 是否以 : 开头或者 v-bind: 开头,如果是为合法bind属性
        3. 如果合法bind属性,提取出 :后的属性名称 或 v-bind:后的属性名称
        4. 遍历tagList数组,通过setAttribute(attributeName, dic[attributeValue])
        实现数据单向绑定

        特例:
        style和class属性,绑定增强
        对于 数组和对象 也能进行绑定
     -->
    <img :src="img1" />
    <img v-bind:src="img2" />
    <div :style="sty1">11</div>
    <p :class="list"></p>
  </body>

  <script>
    // mock数据对应的映射关系, key-value , value可以是值,也可以是数组,也可以是对象
    let dic = {
      img1: "https://cdn.zutjlx.site/image/1672844542112.png",
      img2: "https://cdn.zutjlx.site/image/202210281154371.png",
      object1: {
        class1: "1",
        class2: "2",
      },
      list: ["title", "active"],
      sty1: {
        color: "red",
        width: "800px",
        height: "400px",
      },
    };
    // console.log(typeof dic["object1"])
    // console.log(typeof dic["img1"])
    let tags = document.getElementsByTagName("*");
    // 黑名单
    let tagsDict = ["head", "body", "script", "html"];
    // 存放有效dom元素的数组
    let tagList = [];
    for (let i = 0; i < tags.length; i++) {
      const element = tags[i];
      // 如果不在特定标签黑名单里面再添加元素
      let flag = true;
      for (let j = 0; j < tagsDict.length; j++) {
        // 字符串转小写
        if (element.tagName.toLowerCase() == tagsDict[j]) {
          flag = false;
          break;
        }
      }
      // 如果不在黑名单里面,追加元素
      if (flag) {
        tagList.push(element);
      }
    }

    // 检验属性名是否以 :开头或者以v-bind:开头
    function check(str) {
      if (str[0] == ":" || str.substring(0, 7) == "v-bind:") {
        return 1;
      }
      return 0;
    }
    // 检验属性合法后 , 提取有效属性和属性值
    function getAttributes(str) {
      if (check(str)) {
        if (str[0] == ":") {
          return str.substring(1);
        } else {
          return str.substring(7);
        }
      }
      return "";
    }
    // 判断是否需要绑定加强
    // 如果是style和class 需要绑定加强
    function checkSpe(str) {
      if (str == "style" || str == "class") {
        return true;
      }
      return false;
    }
    // 遍历tagList,获取每个元素
    for (let i = 0; i < tagList.length; i++) {
      const element = tagList[i];
      let attributes = element.attributes;
      // 遍历元素的每一个属性
      for (let j = 0; j < attributes.length; j++) {
        let attributeName = attributes[j].name;
        let attributeValue = attributes[j].value;
        attributeName = getAttributes(attributeName);
        if (
          typeof attributeName == "undefined" ||
          attributeName.length == 0 ||
          attributeName == null
        ) {
          continue;
        }
        // 区分 key-value中的value是不是对象或数组
        if (typeof dic[attributeValue] == "object") {
          // 如果不是 数组,而是对象的形式
          if (!Array.isArray(dic[attributeValue])) {
            if (!checkSpe(attributeName)) {
              element.setAttribute(attributeName, dic[attributeValue]);
            } else {
              // style和class绑定加强
              let styList = [];
              // 对象解构 一个个对key-value配对,并绑定属性和值
              for (const key in dic[attributeValue]) {
                if (Object.hasOwnProperty.call(dic[attributeValue], key)) {
                  styList.push([key, dic[attributeValue][key]]);
                }
              }
              styList.toString = function () {
                return this.join(";").replaceAll(",", ":");
              };
              element.setAttribute(attributeName, styList.toString());
            }
          } else {
            dic[attributeValue].toString = function () {
              return this.join(" ");
            };
            // [1,2,3] 转成 "1,2,3"
            element.setAttribute(attributeName, dic[attributeValue].toString());
          }
        }
        // 不是对象或数组 直接绑定
        else {
          // 关键一步 更改属性
          element.setAttribute(attributeName, dic[attributeValue]);
        }
      }
    }
  </script>
</html>