复习vue19、渲染函数

21 篇文章 0 订阅

复习vue19、渲染函数

Vue推荐在绝大数情况下使用模板来创建你的HTML。然后在一些场景中,你真的需要JavaScript的完全编程的能力,也就是使用javaScript来创建HTML,这时你可以用渲染函数,它比模板更接近编译器。

这里我们先来做一个基本的了解,为后期的深入学习打好一个基础。

下面先看一下render函数的基本结构。

render:function(createElement){
    //createElement函数返回的结果为VNode. VNode就是虚拟dom,用js对象来模拟真实的DOM.
    retrun createElement(
      tag, //标签名称
       data,// 传递数据
       children //子节点数组 
    )
    
}

下面我们在用户管理这个案例中,使用render函数来创建一个组件。

具体的代码如下:

 // heading组件
      //<heading :level="1">{{title}}</heading> //这时要创建的组件
      // <h2 title=""></h2> //这时上面的组件最终渲染的结果
      Vue.component("heading", {
        props: {
          level: {
            type: String,
            required: true,
          },
        },
        render(h) { //h 就是createElement函数
          return h(
            "h" + this.level, //参数1,表示要创建的元素
            this.$slots.default //参数3,子节点VNode数组。(这里没有使用参数2,{{tile}}就是一个子元素)
          );
        },
      });

接下来就可以使用heading组件了。

  <!-- 使用render函数创建的头部组件 -->
      <heading level="1">
        {{title}}
      </heading>

当然,这里需要在data中定义title属性

data: {
          num: 100,
          totalCount: 0,
          users: [],
          height: 0,
          userInfo: "abc",
          title: "用户管理",
          // isShow: false,
          // showWarn: false, // 控制警告窗口的显示与隐藏
        },

完整代码如下(24、render函数.html):

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>列表渲染</title>
    <style>
      .actived {
        background-color: #dddddd;
      }
      .message-box {
        padding: 10px 20px;
      }
      .success {
        background-color: #4fc;
        border: 1px solid #42b;
      }
      .warning {
        background-color: red;
        border: 1px solid #42b;
      }
      .message-box-close {
        float: right;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <!-- 弹窗组件 -->
      <message ref="msgSuccess" class="success">
        <!-- titile的插槽 -->
        <template v-slot:title>
          <h2>恭喜</h2>
        </template>
        <!-- 默认插槽 -->
        <template>
          添加用户成功
        </template>
      </message>

      <!-- 警告 -->
      <message ref="msgWaring" class="warning">
        <!-- titile的插槽 -->
        <template v-slot:title>
          <h2>警告</h2>
        </template>
        <!-- 默认插槽 -->
        <template>
          请输入用户名
        </template>
      </message>

      <!-- 使用render函数创建的头部组件 -->
      <heading level="1">
        {{title}}
      </heading>
      <!-- 清空提示栏 -->
      <div class="toolbar">
        <button @click="$bus.$emit('message-close')">
          清空提示栏
        </button>
      </div>
      <!-- 批量更新身高 -->
      <p>
        <input type="text" v-model.number="height" />
        <button @click="batchUpdate">批量更新用户身高</button>
      </p>
      <!-- 新增用户 -->
      <user-add @add-user="addUser" v-model="userInfo"></user-add>
      <!-- 用户列表组件 -->
      <user-list :users="users"></user-list>

      <p>
        总人数:{{totalCount}}
      </p>
    </div>
    <script src="vue.js"></script>
    <script>
      //创建事件总线
      Vue.prototype.$bus = new Vue();

      // heading组件
      //<heading :level="1">{{title}}</heading> //这时要创建的组件
      // <h2 title=""></h2> //这时上面的组件最终渲染的结果
      Vue.component("heading", {
        props: {
          level: {
            type: String,
            required: true,
          },
        },
        render(h) {
          return h(
            "h" + this.level, //参数1,表示要创建的元素
            this.$slots.default //参数3,子节点VNode数组。(这里没有使用参数2,{{tile}}就是一个子元素)
          );
        },
      });

      //创建弹出的组件
      Vue.component("message", {
        //show表示的含义,控制弹出窗口的显示与隐藏。
        //slot:表示占坑。也就是窗口中的内容,是通过外部组件传递过来的。
        // props: ["show"],
        data() {
          return {
            show: false,
          };
        },

        template: `<div class='message-box' v-if="show">
               <!--具名插槽-->
               <slot name="title">默认标题</slot>
              <slot></slot>
              <span class="message-box-close" @click='toggle'>关闭</span>
            </div>`,
        mounted() {
          //给总线绑定`message-close`事件
          //也就是监听是否有`message-close`事件被触发。
          this.$bus.$on("message-close", () => {
            // this.$emit("close", false);
            //当警告窗口和提示信息的窗口,展示出来了才关闭。
            if (this.show) {
              this.toggle();
            }
          });
        },
        methods: {
          toggle() {
            this.show = !this.show;
          },
        },
      });

      //新增用户组件
      Vue.component("user-add", {
        // data() {
        //   return {
        //     userInfo: "",
        //   };
        // },
        props: ["value"],
        template: `
              <div>
               <p>
                  <input type="text" :value="value" @input="onInput" v-on:keydown.enter="addUser" ref="inp" />
               </p>
               <button @click="addUser">新增用户</button>
                </div>
              `,

        methods: {
          addUser() {
            //将输入的用户数据通知给父组件,来完成新增用户操作.
            // this.$emit("add-user", this.userInfo);
            this.$emit("add-user");
            // this.userInfo = "";
          },
          onInput(e) {
            this.$emit("input", e.target.value);
          },
        },
        mounted() {
          this.$refs.inp.focus();
        },
      });

      // 用户列表
      Vue.component("user-list", {
        data() {
          return {
            selectItem: "",
          };
        },
        props: {
          users: {
            type: Array,
            default: [],
          },
        },
        template: `
          <div>
                  <p v-if="users.length===0">没有任何用户数据</p>
              <ul v-else>
                  <li
                  v-for="(item,index) in users"
                  :key="item.id"
                  :style="{backgroundColor:selectItem===item?'#dddddd':'transparent'}"
                  @mousemove="selectItem=item"
                  >
                  编号:{{item.id}} 姓名:{{item.name}}---身高:{{item.height}}
                  </li>
              </ul>
        </div>
          `,
      });
      new Vue({
        el: "#app",
        data: {
          num: 100,
          totalCount: 0,
          users: [],
          height: 0,
          userInfo: "abc",
          title: "用户管理",
          // isShow: false,
          // showWarn: false, // 控制警告窗口的显示与隐藏
        },

        //组件实例已创建时
        async created() {
          const users = await this.getUserList();
          this.users = users;
          //批量更新用户身高
          this.batchUpdate();
        },
        methods: {
          //关闭窗口
          closeWindow(data) {
            this.isShow = data;
            this.showWarn = data;
          },
          //添加用户的信息
          addUser() {
            if (this.userInfo) {
              if (this.users.length > 0) {
                this.users.push({
                  id: this.users[this.users.length - 1].id + 1,
                  name: this.userInfo,
                });
                this.userInfo = "";
                //完成用户添加后,给出相应的提示信息
                // this.isShow = true;
                this.$refs.msgSuccess.toggle();
              }
            } else {
              // 显示错误警告信息
              // this.showWarn = true;
              this.$refs.msgWaring.toggle();
            }
          },

          //批量更新身高,动态的给users中添加身高属性
          batchUpdate() {
            this.users.forEach((c) => {
              //   c.height = this.height;
              //   Vue.set(c, "height", this.height);
              this.$set(c, "height", this.height);
            });
          },

          getTotal: function () {
            console.log("methods");
            return this.users.length + "个";
          },
          getUserList: function () {
            return new Promise((resolve) => {
              setTimeout(() => {
                resolve([
                  {
                    id: 1,
                    name: "张三",
                  },
                  {
                    id: 2,
                    name: "李四",
                  },
                  {
                    id: 3,
                    name: "老王",
                  },
                ]);
              }, 2000);
            });
          },
        },
        watch: {
          users: {
            immediate: true, //立即执行
            handler(newValue, oldValue) {
              this.totalCount = newValue.length + "个人";
            },
          },
        },
      });
    </script>
  </body>
</html>

虚拟DOM
Vue通过建立一个虚拟DOM来追踪自己要如何改变真实DOM.

createElement参数

前面说过,createElement函数有三个参数。

createElement(
  //{string |Object|Function}
    //第一个参数,可以是字符串,也可以是对象或者是函数
    ‘div’
    ,
    // 第二个参数是对象,表示的是一个与模板中属性对应的数据对象。该参数可选
    {
        
    },
    //第三个参数是一个数组,表示的是子节点数组
    [
        
    ]
)
    

下面,给heading组件添加第一个属性。

  <!-- 使用render函数创建的头部组件 -->
      <heading level="1" :title="title">
        {{title}}
      </heading>

在上面的代码中,我们给heading组件动态添加了一个title属性。而我们知道heading组件,最终渲染成的是h1的元素,最终效果为:<h1 title='aaa'>的形式。

 // heading组件
      //<heading :level="1">{{title}}</heading> //这时要创建的组件
      // <h2 title=""></h2> //这时上面的组件最终渲染的结果
      Vue.component("heading", {
        props: {
          level: {
            type: String,
            required: true,
          },
          title: {
            type: String,
            default: "",
          },
        },
        render(h) {
          return h(
            "h" + this.level, //参数1,表示要创建的元素
            { attrs: { title: this.title } }, //参数2
            this.$slots.default //参数3,子节点VNode数组。(这里没有使用参数2,{{tile}}就是一个子元素)
          );
        },
      });

在上面的代码中,我们在render函数中给h函数添加了第二个参数,给最终生成的元素添加了attrs属性。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值