vue render函數

Vue中的Render渲染函數

VUE一般使用template來創建HTML,然后在有的時候,我們需要使用javascript來創建html,這時候我們需要使用render函數。
比如如下我想要實現如下html:

<div id="container"><h1><a href="#">Hello world!</a></h1>
</div>

  我們會如下使用:

<!DOCTYPE html>
<html><head><title>演示Vue</title><style></style></head><body><div id="container"><tb-heading :level="1"><a href="#">Hello world!</a></tb-heading></div></body><script src="./vue.js"></script><script type="text/x-template" id="templateId"><h1 v-if="level === 1"><slot></slot></h1><h2 v-else-if="level === 2"><slot></slot></h2></script><script>Vue.component('tb-heading', {template: '#templateId',props: {level: {type: Number,required: true}}});new Vue({el: '#container'});</script>
</html>

  

如上代碼是根據參數 :level來顯示不同級別的標題中插入錨點元素,我們需要重復的使用 <slot></slot>.

下面我們來嘗試使用 render函數重寫上面的demo;如下代碼:

<!DOCTYPE html>
<html><head><title>演示Vue</title><style></style></head><body><div id="container"><tb-heading :level="2"><a href="#">Hello world!</a></tb-heading></div></body><script src="./vue.js"></script><script>Vue.component('tb-heading', {render: function(createElement) {return createElement('h' + this.level,    // tag name 標簽名稱this.$slots.default  // 組件的子元素)},props: {level: {type: Number,required: true}}});new Vue({el: '#container'});</script>
</html>

  如上 render函數代碼看起來非常簡單就實現了,組件中的子元素存儲在組件實列中 $slots.default 中。

理解createElement
Vue通過建立一個虛擬DOM對真實的DOM發生變化保存追蹤,如下代碼:
return createElement('h1', this.title);
createElement返回的是包含的信息會告訴VUE頁面上需要渲染什么樣的節點及其子節點。我們稱這樣的節點為虛擬DOM,可以簡寫為VNode,

createElement 參數// @return {VNode}
createElement(// {String | Object | Function}// 一個HTML標簽字符串,組件選項對象,或者一個返回值類型為String/Object的函數。該參數是必須的'div',// {Object}// 一個包含模板相關屬性的數據對象,這樣我們可以在template中使用這些屬性,該參數是可選的。{},// {String | Array}// 子節點(VNodes)由 createElement() 構建而成。可選參數// 或簡單的使用字符串來生成的 "文本節點"。['xxxx',createElement('h1', '一則頭條'),createElement(MyComponent, {props: {someProp: 'xxx'}})]
)

  理解深入data對象。

在模板語法中,我們可以使用 v-bind:class 和 v-bind:style 來綁定屬性,在VNode數據對象中,下面的屬性名的字段級別是最高的。
該對象允許我們綁定普通的html特性,就像DOM屬性一樣。如下:

{// 和`v-bind:class`一樣的 API'class': {foo: true,bar: false},// 和`v-bind:style`一樣的 APIstyle: {color: 'red',fontSize: '14px'},// 正常的 HTML 特性attrs: {id: 'foo'},// 組件 propsprops: {myProp: 'bar'},// DOM 屬性domProps: {innerHTML: 'baz'},// 事件監聽器基于 `on`// 所以不再支持如 `v-on:keyup.enter` 修飾器// 需要手動匹配 keyCode。on: {click: this.clickHandler},// 僅對于組件,用于監聽原生事件,而不是組件內部使用 `vm.$emit` 觸發的事件。nativeOn: {click: this.nativeClickHandler},// 自定義指令。注意事項:不能對綁定的舊值設值// Vue 會為您持續追蹤directives: [{name: 'my-custom-directive',value: '2',expression: '1 + 1',arg: 'foo',modifiers: {bar: true}}],// Scoped slots in the form of// { name: props => VNode | Array<VNode> }scopedSlots: {default: props => createElement('span', props.text)},// 如果組件是其他組件的子組件,需為插槽指定名稱slot: 'name-of-slot',// 其他特殊頂層屬性key: 'myKey',ref: 'myRef'
}

  上面的data數據可能不太好理解,我們來看一個demo,就知道它是如何使用的了,如下代碼:

<!DOCTYPE html>
<html><head><title>演示Vue</title><style></style></head><body><div id="container"><tb-heading :level="2">Hello world!</tb-heading></div></body><script src="./vue.js"></script><script>var getChildrenTextContent = function(children) {return children.map(function(node) {return node.children ? getChildrenTextContent(node.children) : node.text}).join('')};Vue.component('tb-heading', {render: function(createElement) {var headingId = getChildrenTextContent(this.$slots.default).toLowerCase().replace(/\W+/g, '-').replace(/(^\-|\-$)/g, '')return createElement('h' + this.level,[createElement('a', {attrs: {name: headingId,href: '#' + headingId},style: {color: 'red',fontSize: '20px'},'class': {foo: true,bar: false},// DOM屬性domProps: {innerHTML: 'baz'},// 組件propsprops: {myProp: 'bar'},// 事件監聽基于 'on'// 所以不再支持如 'v-on:keyup.enter' 修飾語// 需要手動匹配 KeyCode  on: {click: function(event) {event.preventDefault();console.log(111);}}}, this.$slots.default)])},props: {level: {type: Number,required: true}}});new Vue({el: '#container'});</script>
</html>

  對應的屬性使用方法和上面一樣既可以了,我們可以打開頁面查看下效果也是可以的。如下

VNodes 不一定必須唯一 (文檔中說要唯一)
文檔中說 VNode必須唯一;說 下面的 render function 是無效的:
但是我通過測試時可以的,如下代碼:

<!DOCTYPE html>
<html><head><title>演示Vue</title><style></style></head><body><div id="container"><tb-heading :level="2">Hello world!</tb-heading></div></body><script src="./vue.js"></script><script>Vue.component('tb-heading', {render: function(createElement) {var pElem = createElement('p', 'hello world');return createElement('div', [pElem, pElem])},props: {level: {type: Number,required: true}}});new Vue({el: '#container'});</script>
</html>

使用Javascript代替模板功能
?v-if 和 v-for
template 中有 v-if 和 v-for, 但是vue中的render函數沒有提供專用的API。
比如如下:

<ul v-if="items.length"><li v-for="item in items">{{ item.name }}</li>
</ul>
<p v-else>No item found.</p>

  在render函數中會被javascript的 if/else 和map重新實現。如下代碼:

<!DOCTYPE html>
<html><head><title>演示Vue</title><style></style></head><body><div id="container"><tb-heading>Hello world!</tb-heading></div></body><script src="./vue.js"></script><script>Vue.component('tb-heading', {render: function(createElement) {console.log(this)if (this.items.length) {return createElement('ul', this.items.map(function(item){return createElement('li', item.name);}))} else {return createElement('p', 'No items found.');}},props: {items: {type: Array,default: function() {return [{name: 'kongzhi1'},{name: 'kongzhi2'}]}}}});new Vue({el: '#container'});</script>
</html>

v-model

render函數中沒有 與 v-model相應的api,我們必須自己來實現相應的邏輯。如下代碼可以實現:

<!DOCTYPE html>
<html><head><title>演示Vue</title><style></style></head><body><div id="container"><tb-heading @input="inputFunc">Hello world!</tb-heading></div></body><script src="./vue.js"></script><script>Vue.component('tb-heading', {render: function(createElement) {var self = this;return createElement('input', {domProps: {value: '11'},on: {input: function(event) {self.value = event.target.value;self.$emit('input', self.value);}}})},props: {}});new Vue({el: '#container',methods: {inputFunc: function(value) {console.log(value)}}});</script>
</html>

  

理解插槽

可以從 this.$slots 獲取VNodes列表中的靜態內容:如下代碼:

<!DOCTYPE html>
<html><head><title>演示Vue</title><style></style></head><body><div id="container"><tb-heading :level="2"><a href="#">Hello world!</a></tb-heading></div></body><script src="./vue.js"></script><script>Vue.component('tb-heading', {render: function(createElement) {return createElement('h' + this.level,    // tag name 標簽名稱this.$slots.default  // 子組件)},props: {level: {type: Number,required: true}}});new Vue({el: '#container'});</script>
</html>

  

理解函數式組件

函數式組件我們標記組件為 functional, 意味著它無狀態(沒有data), 無實列(沒有this上下文)。
一個函數式組件像下面這樣的:

Vue.component('my-component', {functional: true,// 為了彌補缺少的實列// 提供第二個參數作為上下文render: function(createElement, context) {},// Props 可選props: {}
})

  

組件需要的一切通過上下文傳遞,包括如下:
props:?提供props對象
children:?VNode子節點的數組
slots:?slots對象
data:?傳遞給組件的data對象
parent:?對父組件的引用
listeners: (2.3.0+)?一個包含了組件上所注冊的 v-on 偵聽器的對象。這只是一個指向 data.on 的別名。
injections: (2.3.0+)?如果使用了 inject 選項,則該對象包含了應當被注入的屬性。

在添加 functional: true 之后,組件的 render 函數之間簡單更新增加 context 參數,this.$slots.default 更新為 context.children,之后this.level 更新為 context.props.level。
如下代碼演示:

<!DOCTYPE html>
<html><head><title>演示Vue</title><style></style></head><body><div id="container">{{msg}}<choice><item value="1">test</item></choice></div></body><script src="./vue.js"></script><script>Vue.component('choice', {template: '<div><ul><slot></slot></ul></div>'});Vue.component('item', {functional: true,render: function(h, context) {return h('li', {on: {click: function() {console.log(context);console.log(context.parent);console.log(context.props)}}}, context.children)},props: ['value']})new Vue({el: '#container',data: {msg: 'hello'}});</script>
</html>

  

?https://www.zhihu.com/question/54217073

轉載于:https://www.cnblogs.com/smzd/p/8868759.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/249898.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/249898.shtml
英文地址,請注明出處:http://en.pswp.cn/news/249898.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Nexus介紹

轉自&#xff1a;https://www.cnblogs.com/wincai/p/5599282.html 開始在使用Maven時&#xff0c;總是會聽到nexus這個詞&#xff0c;一會兒maven&#xff0c;一會兒nexus&#xff0c;當時很是困惑&#xff0c;nexus是什么呢&#xff0c;為什么它總是和maven一起被提到呢&#…

vue-cli 打包

一項目打包 1 打包的配置在 build/webpack.base.conf.js文件下 常量config在vue/config/index.js 文件下配置&#xff0c;__dirname是定義在項目的全局變量&#xff0c;是當前文件所在項目的文件夾的絕對路徑。 2 需要修改vue/config/index.js 文件下的將build對象下的assets…

乘風破浪:LeetCode真題_010_Regular Expression Matching

乘風破浪&#xff1a;LeetCode真題_010_Regular Expression Matching 一、前言 關于正則表達式我們使用得非常多&#xff0c;但是如果讓我們自己寫一個&#xff0c;卻是有非常大的困難的&#xff0c;我們可能想到狀態機&#xff0c;確定&#xff0c;非確定狀態機確實是一種解決…

python——獲取數據類型

在python中&#xff0c;可使用type()和isinstance()內置函數獲取數據類型 如&#xff1a; &#xff08;1&#xff09;type()的使用方法&#xff1a;    >>> a 230 >>> type(a) <class str> >>> a 230 …

vue項目工程中npm run dev 到底做了什么

npm install 安裝了webpack框架中package.json中所需要的依賴 2.安裝完成之后&#xff0c;需要啟動整個項目運行&#xff0c;npm run 其實執行了package.json中的script腳本&#xff0c;npm run dev的執行如下 3.底層相當執行webpack-dev-server --inline --progress --confi…

JavaScript回顧與學習——條件語句

一、if...else // if elsevar age 16;if(0 < age && age < 6){console.log("兒童");}else if(6 < age && age < 14){console.log("少年");}else if(14 < age && age < 35){console.log("青年");}els…

bat等大公司常考java多線程面試題

1、說說進程,線程,協程之間的區別 簡而言之,進程是程序運行和資源分配的基本單位,一個程序至少有一個進程,一個進程至少有一個線程.進程在執行過程中擁有獨立的內存單元,而多個線程共享內存資源,減少切換次數,從而效率更高.線程是進程的一個實體,是cpu調度和分派的基本單位,是比…

webpack.config.js和package.json

webpack.config.js 是webpakc的配置文件&#xff0c;webpack是當今很火的一個打包工具 使用webpack.config.js在你的項目里 可以對你的項目進行模塊化打包&#xff0c;并且也可使組件按需加載&#xff0c;還可將圖片變成base64格式減少網絡請求。 而package.json 是指你項目的…

七牛云圖片加載優化

?imageView2/2/w/80https://developer.qiniu.com/dora/manual/1279/basic-processing-images-imageview2 ?imageView2/1/w/80/h/80會裁剪 ?imageView2/3/w/80/h/80不會裁剪 轉載于:https://www.cnblogs.com/smzd/p/9025393.html

org.apache.maven.archiver.mavenarchiver.getmanifest怎么解決

原因就是你的maven的配置文件不是最新的 1.help ->Install New Software -> add ->https://otto.takari.io/content/sites/m2e.extras/m2eclipse-mavenarchiver/0.17.2/N/LATEST 或者&#xff08;更新于2018年4月18日17:07:53&#xff09; http://repo1.maven.org/mav…

npm中package.json詳解

通常我們使用npm init命令來創建一個npm程序時&#xff0c;會自動生成一個package.json文件。package.json文件會描述這個NPM包的所有相關信息&#xff0c;包括作者、簡介、包依賴、構建等信息&#xff0c;格式是嚴格的JSON格式。 常用命令 npm i --save packageName 安裝依賴…

offset系列,client系列,scroll系列回顧

一 scroll系列屬性 ——滾動1 scrollHeight/scrollWidth 標簽內部實際內容的高度/寬度ele.scrollHeight 有兩種情況&#xff0c;當內容超出盒子范圍后&#xff0c;返回的是內容的高度&#xff0c;包括padding&#xff0c;從頂部內側到內容的最外部分。當內容不超出盒子范圍…

項目開發中的自我總結

最近忙的要死,因為新開發了兩個項目.現在已經測試完畢了,準備部署到線上了. 然后不能白忙活吧,忙活完也得寫點總結和經驗吧,以后也有個記錄. 1.一個bootstrapjquerylayuilaravel 5.4開發的一個后臺系統 比較樸素 2.一個前后端分離的vuelaravel 5.4 開發的商家系統 我只負責后端…

webpack.config.js 參數詳解

webpack.config.js文件通常放在項目的根目錄中&#xff0c;它本身也是一個標準的Commonjs規范的模塊。 var webpack require(webpack); module.exports {entry: [webpack/hot/only-dev-server,./js/app.js],output: {path: ./build,filename: bundle.js},module: {loaders: …

數組黑科技(偏性能方面)未完待更新...

數組去重最優解&#xff1a;Array.prototype.unique function () {var tmp new Map();return this.filter(item > {return !tmp.has(item) && tmp.set(item,1);})}搭配使用 Array.from(foo); // ["f", "o", "o"]let s new Set([f…

控制臺添加log4net

1.添加nuget包 log4net 2.app.config配置 <?xml version"1.0" encoding"utf-8"?> <configuration> <configSections><section name"log4net" type"log4net.Config.Log4NetConfigurationSectionHandler, log4net&quo…

記一次vue 普通異步請求微信二進制二維碼 亂碼 問題解決然后渲染

后端壓力大&#xff0c;前端分憂。 /*用微信小程序token拿二維碼*/ async fetchMINIQRcode({commit,state},params){var instance axios.create({responseType: blob, //返回數據的格式&#xff0c;可選值為arraybuffer,blob,document,json,text,stream&#xff0c;默認值為js…

vue-cli項目中.postcssrc.js

module.exports {"plugins": {"postcss-import": {}, //用于import導入css文件"postcss-url": {}, //路徑引入css文件或node_modules文件"postcss-aspect-ratio-mini": {}, //用來處理元素容器寬高比"postcss-…

本地存儲cookie和localStorage區別特點

一、cookie cookie算是比較早的技術&#xff0c;最初是為了記錄http的狀態&#xff0c;提高訪問速度。cookie是服務器"種植"在客戶端的key-value形式文本文件。但同時客戶端也能操作cookie。特點&#xff1a; 大小&#xff1a;cookie的大小限制在4k。每個域名下cooki…

VUE 中 使用 iview Form組件 enter鍵防止頁面刷新

<Form :label-width"100" inline label-positionleft keydown.native.enter.prevent "()>{}">或者使用官方的 submit.native.prevent轉載于:https://www.cnblogs.com/smzd/p/9197915.html