render函數


當template內部的結構代碼在編譯的時候發生了什么?

比如我們下面的代碼

1 <template>
2 <div>
3     <h1>123456789</h1>
4 </div>
5 </template>

我們平常寫template里面所使用的模板是HTML語法組件的頁面,其實在vue中都會被編譯為render函數,因為vue中采用的是虛擬dom進行頁面組件,這樣的優點是優化頁面的加載重繪性能

render函數的基本使用

我們在views文件夾中新建一個Render.vue組件,注意如果要使用render函數編譯模板,一定不要有<template></template>,否則就回加載template中的內容

render.vue

 1 <script>
 2     export default {
 3         render(createElement){
 4             return createElement('h1',{},123456789)
 5         }
 6     }
 7 </script>
 8 
 9 <style lang="scss" scoped>
10 </style>

App.vue

 1 <template>
 2     <div>
 3         <render></render>
 4     </div>
 5 </template>
 6 <script>
 7 import render from "./views/render.vue"
 8     export default {
 9         components:{
10             render
11         }
12     }
13 </script>
14 <style lang="less" scoped>
15 </style>

 

 

 

我們設置一個小案例,通過render函數動態的修改當前組件的節點渲染

 1 <script>
 2     export default {
 3         props:{
 4             tag:{
 5                 type:String,
 6                 required:true,
 7             },
 8             data:{
 9                 type:String
10             }
11         },
12         render(createElement){
13             return createElement(this.tag,{},this.data)
14         }
15     }
16 </script>
17 
18 <style lang="scss" scoped>
19 </style>

props有兩個值,第一個值為tag,指的是傳入的節點名稱,第二個值data,就是要渲染的節點內容

App.vue

1 <template>
2     <div>
3         <render :tag="'p'" :data="'123456789'"></render>
4     </div>
5 </template>

 

 

此時要注意,如果沒有設置的元素節點,render函數也會加載

1         <render :tag="'aaaaa'" :data="'123456789'"></render>

 

 

 

這樣做有一個好處,就是如果我們的節點是一個ui元素名稱,或者是自定義組件,都會被識別

比如我們引入的是element-ui

1         <render :tag="'el-button'" :data="'我是button'"></render>

 

 

 

也可以設置組件內容

 1 <script>
 2 import son from "./son.vue"
 3     export default {
 4         props:{
 5             tag:{
 6                 type:String,
 7                 required:true,
 8             },
 9             data:{
10                 type:String
11             }
12         },
13         render(createElement){
14             return createElement(son,{},this.data)
15         }
16     }
17 </script>
18 <style lang="scss" scoped>
19 </style>

 

 

 

createdElement函數一共有三個參數,第一個參數我們已經知道如何使用,第二個參數其實就是對當前的節點(組件)的屬性描述

 1 <script>
 2     export default {
 3         props:{
 4             tag:{
 5                 type:String,
 6                 required:true,
 7             },
 8             data:{
 9                 type:String
10             }
11         },
12         render(createElement){
13             return createElement(this.tag,{
14                 class:'color_red'
15             },this.data)
16         }
17     }
18 </script>
19 <style scoped>
20 .color_red{
21 color: red;
22 }
23 </style>

我們設置class顏色為red

 

 

 還可以用domProps設置

 1  render(createElement){
 2             return createElement(this.tag,{
 3                 // class:'color_red'
 4                 //Dom的prototype
 5                 domProps:{
 6                     className:'color-red',
 7                     innerHTML:'123456789'
 8                 }
 9             },this.data)
10         }

 

 

最重要的是第三個參數,第三個參數如果不是數組,則表示渲染內容,否則,如果設置了數組,內部必須是createElement函數,代表的是當前的元素再進行嵌套

 1  render(createElement){
 2             return createElement(this.tag,{
 3                 // class:'color_red'
 4                 //Dom的prototype
 5                 domProps:{
 6                     className:'color-red',
 7                     
 8                 }
 9             },[createElement('p', [createElement('span', '我是p元素內部的span元素')]), createElement('p', '我是p元素')])
10         }

 

 

createElement方法的核心其實就是第三個參數,因為這個參數最大的魔力就是能夠嵌套,由於之前能夠通過第二個參數設置當前元素的相關屬性,所以如果一旦第三個參數實現了嵌套元素的功能,此時就可以實現通過js設置HTML模板

 

render函數還有一個最大的功能就是解析模板

此時我們的render函數,並沒有通過字符串設置模板內容,而是直接設置了對應的元素

 1   render(){
 2             return (
 3              <div>
 4                    <h2>四大名著</h2>
 5                 <ul>
 6                      <li>西游記</li>
 7                      <li>水滸傳</li>
 8                      <li>三國演義</li>
 9                      <li>紅樓夢</li>
10                 </ul>
11              </div>
12             )
13         }

 

 

頁面中進行了識別和解析

 

createElement源碼解析

我們先創建一個類似於createElement的結構

1    var vDom=createElement('div',{class:'container'},[
2         createElement('p',{class:'item',style:'color:red'},'我是p節點1'),
3         createElement('p',{class:'item',style:'background:blue'},'我是p節點2'),
4         createElement('p',{class:'item'},'我是p節點3'),
5         createElement('input',{value:'我是value'},'我是input'),
6     ])

創建Element構造函數

1 function Element(type,props,children){
2         this.type=type;
3         this.props=props;
4         this.children=children;
5 
6     }
7     function createElement(type,props,children){
8         return new Element(type,props,children)
9     }

創建節點和屬性

 1 function render(obj){
 2         //創建節點
 3         let el=document.createElement(obj.type);
 4         //給相關的節點設置對應的屬性
 5         for(let key in obj.props){
 6           el.setAttribute(key,obj.props[key])
 7         };
 8         if(Array.isArray(obj.children)){
 9             //遍歷創建子元素
10             obj.children.forEach((child)=>{
11                // console.log(child)
12                 //遞歸操作,如果當前的child不是文本節點,就繼續進行遞歸操作,否則渲染文本節點
13                 child=child instanceof Element?render(child):document.createTextNode(child);
14                 //節點上樹
15                 el.appendChild(child)
16             })
17             //當前obj.children如果不是數組而是字符串,就當做文本進行渲染
18         }else if (typeof obj.children==='string'){
19             el.appendChild(document.createTextNode(obj.children))
20         }
21         return el
22     }

渲染頁面

1 function renderDom(el,target){
2         target.appendChild(el)
3     }

調用

1     renderDom(render(vDom),document.getElementById("app"))

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM