【Vue】徹底理解Vue中render函數與template的區別

2021-12-26 IT狗的成長日記
一、render函數與template對比

VUE一般使用template來創建HTML,然後在有的時候,我們需要使用javascript來創建html,這時候我們需要使用render函數。


以下我們來做一個需求跟根據level等級來編寫對應等級的標題

template解析

<body>
   <divid="app">
       <h-titlelevel=1>
           <p>Alley</p>
       </h-title>
       <h-titlelevel=2>
           <p>Alley</p>
       </h-title>
   </div>
</body>

</html>
<scriptsrc="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>

   Vue.component("h-title", {
       template: `<div>
           <h1 v-if="level==1"><slot></slot></h1>
           <h2 v-else-if="level==2"><slot></slot></h2>
       </div>`,
       props: {
           level: {
               type: Number,
               required: true
          }
      }
  })

   letvm=newVue({
       el: "#app"
  })
</script>


render解析


<body>
   <divid="app">
       <h-titlelevel=1>
           <p>Alley</p>
       </h-title>
       <h-titlelevel=2>
           <p>Alley</p>
       </h-title>
   </div>
</body>

</html>
<scriptsrc="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
   Vue.component("h-title", {
       render:function(createElement){
           returncreateElement(
               "h"+this.level,
               this.$slots.default
          )
      },
       props: {
           level: {
               type: Number,
               required: true
          }
      }
  })

   letvm=newVue({
       el: "#app"
  })
</script>

二者對比我們不難看出render函數創建組件的方式更加的靈活,同時也能讓我們最大的發揮出JavaScript的編程能力


二、render函數詳解

Vue中的Render函數中有一個參數,這個參數是一個函數通常我們叫做h。其實這個h叫做createElement。Render函數將createElement的返回值放到了HTML中

createElement這個函數中有3個參數

第一個參數(必要參數):主要用於提供DOM的html內容,類型可以是字符串、對象或函數

第二個參數(類型是對象,可選):用於設置這個DOM的一些樣式、屬性、傳的組件的參數、綁定事件之類

第三個參數(類型是數組,數組元素類型是VNode,可選):主要是指該結點下還有其他結點,用於設置分發的內容,包括新增的其他組件。注意,組件樹中的所有VNode必須是唯一的


createElement(
 
 
 'div',

 
 
{
     attrs: {
        name: headingId,
        href: '#'+headingId
    },
     style: {
        color: 'red',
        fontSize: '20px'
    },
     'class': {
        foo: true,
        bar: false
      },
      
      domProps: {
         innerHTML: 'baz'
      },
      
       props: {
          myProp: 'bar'
      },
       
       
       
       on: {
           click: function(event) {
                event.preventDefault();
                console.log(111);
          }
        }
  }

 
 
 
[
   'xxxx',
   createElement('h1', '一則頭條'),
   createElement(MyComponent, {
     props: {
       someProp: 'xxx'
    }
  }),
   this.$slots.default
]
)

三、什麼時候用render函數?

假設我們要封裝一套按鈕組件,按鈕有四個樣式(success、error、warning、default)。首先,你可能會想到如下實現

<template>
<divclass="btn btn-success"v-if="type === 'success'">{{ text }}</div>
<divclass="btn btn-danger"v-else-if="type === 'danger'">{{ text }}</div>
<divclass="btn btn-warning"v-else-if="type === 'warning'">{{ text }}</div>
</template>

雖然我們這樣實現沒有問題,但是如果現在有十幾個樣式的情況下我們就需要寫N多個判斷,如果遇到了這種情況我們就可以選擇使用render函數。

其實簡單的來說就是template適合簡單的組件封裝,然後render函數適合複雜的組件封裝

<script>
Vue.component("alley-button", {
       props: {
           type: {
               type: String,
               default: 'default'
          },
           text: {
               type: String,
               default: '按鈕'
          }
      },
       computed: {
           tag() {
               switch(this.type) {
                   case'success':
                       return1;
                   case'danger':
                       return2;
                   case'warning':
                       return3;
                   default:
                       return1;
              }
          }
      },
       render(h) {
           returnh('div', {
               class: {
                   btn: true,
                   'btn-success': this.type==='success',
                   'btn-danger': this.type==='danger',
                   'btn-warning': this.type==='warning'
              },
               domProps: {
                   
              },
               on: {
                   click: this.handleClick
              }
          },
           this.$slots.default
          );
      },
       methods: {
           handleClick() {
               console.log('---');
               console.log('alley');
          }
      }
  })

   letvm=newVue({
       el: "#app"
  })
</script>

四、template與render函數對比

相同之處:

render 函數 跟 template 一樣都是創建 html 模板

不同之處:

如果你喜歡本文,請分享到朋友圈,想要獲得更多信息,請關注我。

相關焦點

  • 來聊聊Vue中使用Render函數和JSX
    Render函數render函數是組件渲染的重要核心,它跟template模板開發一樣,只不過這種形式開發,它(render)更接近底層,這樣能讓Vue編譯時少轉換一次。讓我們來看一下哪裡能用到render函數。
  • Vue 中 render 函數有點意思
    但是,有一些用例,如基於輸入或插槽值創建動態組件方式,render 函數會比模板完成的更好也更出色。用過 React 開發的人對 render 函數應該非常熟悉,因為React組件通過 JSX和 render 函數來構建的。儘管Vue render 函數也可以用JSX編寫,但在這裡我們使用原生 JS方式,因為這樣,我們可以更輕鬆地了解Vue組件系統的一些基礎。
  • vue中ast生成render
    我們先使用 vue 的模板編譯庫 vue-template-compiler 驗證一下輸出結果。
  • 解讀vue-template-compiler
    導讀在寫Vue 單文件組件的時候,我們需要知道是是使用vue-loader和vue-template-compiler 對vue文件進行的處理。Vue-loader是webpack的插件,因為Vue2 版本是基於webpack打包的。準備的說,vue-cli底層使用的是webpack。
  • 深入理解 Vue 模板渲染:Vue 模板反編譯
    vue 文件的構成熟悉 vue 的同學應該都知道,vue 單文件模板中一般含有三個部分,template,script,style。但是在編譯後的 js 文件中,我們卻沒法在代碼中直接找到這三部分,如果我們想從編譯後的 js 中獲取原始模板,應該怎麼做?
  • JS每日一題: 簡述一下Vue.js的template編譯過程?
    >    "attribs": {      "class": "name"    },    "children": [      {        "data": "JS每日一題",        "type": "text",        "next": null,
  • Vue中的Class Component使用指南
    /App'new Vue({ el: '#app', render: h => h(App)})在註冊完這些鉤子後,在類組件中,可以把它們當成類的原型方法來使用:import Vue from 'vue'import Component from 'vue-class-component
  • 面試官:聊聊對Vue.js框架的理解
    實際上,我們組件中的 template 語法是無法被瀏覽器解析的,因為它不是正確的 HTML 語法,而模板編譯,就是將組件的 template 編譯成可執行的 JavaScript 代碼,即將 template 轉化為真正的渲染函數。模板編譯分三個階段,parse、optimize、generate,最終生成render函數。
  • 全面了解 Vue.js 函數式組件
    首先嘗試的是把原本 template 中日期列的部分「平移」到一個函數式組件 DateCol.vue 中:<template functional>  <div>    <i class="el-icon-time"></i
  • vue中的生命周期
    簡單來說,vue生命周期就是我們在瀏覽器中打開和關閉頁面的過程中,vue實例的創建和銷毀的全過程。vue裡提供了一些生命周期鉤子函數,使得開發者可以在實例創建的某個階段上插入自定義代碼,從而實現響應的功能處理。
  • Vue3.0:Lifecycle Hooks & Template Refs in Composition API 個人翻譯
    下面的表格展示了setup()中如何調用生命周期鉤子函數Options APIHook inside setupbeforeCreateNot needed*createdNot needed*beforeMountonBeforeMountmountedonMountedbeforeUpdateonBeforeUpdateupdatedonUpdatedbeforeUnmountonBeforeUnmountunmountedonUnmountederrorCapturedonErrorCapturedrenderTrackedonRenderTrackedrenderTriggeredonRenderTriggered
  • Vue隱藏技能:運行時渲染用戶寫入的組件代碼!
    其實主要是為了服務於 template 模板語法,當你在 template 中寫了 <compA propA='value'/>,有了這個註冊聲明才能在編譯時找到compA。如果不使用 template,那麼這個註冊就可以省了。不使用 template 怎麼渲染呢,使用render 函數[6]呀!
  • Vue3.0七大亮點
    render階段的靜態提升(render階段指生成虛擬dom樹的階段)在vue2中,一旦檢查到數據變化,就會re-render組件,所有的vnode都會重新創建一遍,形成新的vdom樹。在vue3中,對於不參與更新的vnode,會做靜態提升,只會被創建一次,在re-render時直接復用。靜態提升可以理解為第一次render不參與更新的vnode節點的時候,保存它們的引用。re-render新vdom樹時,直接拿它們的引用過來即可,無需重新創建。
  • @vue/composition-api 與 Vue3 的前生今世
    ></template><script> import { reactive, computed } from '@vue/composition-api' export default { // 注意:在使用 composition-api 時,要記得使用新的 setup option
  • Vue中directive自定義指令
    指令是帶有前綴v-以表示它們是vue提供的特殊的屬性。指令的作用,可以理解是寫在DOM元素上的屬性,而這個屬性具有它特定的職責。當表達式的值改變的時候,會產生一定的響應行為,而這些響應行為會作用在綁定的DOM元素上。
  • 重學Vue源碼【Vue實例掛載的實現】
    接著開始進行編譯階段,判斷有沒有 template,大致就是拿到一個 complieToFunctions 的render 函數,和一個 staticRenderFns 函數,並且賦值。即 Vue 只認 render 函數,如果有 render 函數,就直接 return mount.call(this, el, hyrating),return出去,如果沒有 render 函數,就通過一系列操作,把 template 轉化編譯成 render 函數。
  • vue-router 實現分析
    var router = new VueRouter({  routes: [   {path: '/foo', component: {template: 'FOO<code>'}},   {path: '/bar', component: {template: '</code>BAR<code>'}}
  • 和女朋友爭論了1個小時,在Vue裡用Throttle居然這麼黑盒?
    至此,我們已經清楚了關於 vue 中的黑魔法了,vue 給我們帶來便利的同時,我們運用的不好,或者說不理解它的一些思想原理,就會發生一些神奇的事情。最佳所以上述說了這麼多,我們需要有個最佳的實踐方案。因為在我們模板中寫的方法,必須是 methods 中的方法,否則就會找不到。也許這樣我們直接像在模板中寫 throttle 就必須將這個函數定義在 methods 中,這樣是非常不友好的,因為會反直覺,對於太久沒寫的我(T T忘記了)。
  • Webpack 案例 ——vue-loader 原理分析
    配置,注入 vue-loader 專用的 rules內容處理階段:normal loader 配合 pitcher loader 完成文件內容轉換插件預處理階段vue-loader 插件會在 apply 函數中擴展 webpack 配置信息核心代碼如下:class VueLoaderPlugin
  • 2021全新 最火Vue面試題(一)(附源碼)
    Vue中模板編譯原理?核心答案:如何將template轉換成render函數(這裡要注意的是我們在開發時儘量不要使用template,因為將template轉化成render方法需要在運行時進行編譯操作會有性能損耗,同時引用帶有compiler包的vue體積也會變大。