Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

手写简易版 v-bind #396

Open
jlx2002 opened this issue Jan 16, 2023 · 0 comments
Open

手写简易版 v-bind #396

jlx2002 opened this issue Jan 16, 2023 · 0 comments

Comments

@jlx2002
Copy link
Contributor

jlx2002 commented Jan 16, 2023

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

<!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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant