以前建立的組件是比較簡單,沒有管理或者監放任何傳遞給他的狀態,也沒有生命週期方法。它只是一個接收參數的函數。
在下面這個例子中,咱們標記組件爲 functional,這意味它是無狀態 (沒有響應式數據),無實例 (沒有 this 上下文)。javascript
一個 函數式組件 就像這樣:css
Vue.component('my-component', { functional: true, // Props 可選 props: { // ... }, // 爲了彌補缺乏的實例 // 提供第二個參數做爲上下文 render: function (createElement, context) { // ... } })
注意:在 2.3.0 以前的版本中,若是一個函數式組件想要接受 props,則 props
選項是必須的。在 2.3.0 或以上的版本中,你能夠省略 props
選項,全部組件上的屬性都會被自動解析爲 props。html
在 2.5.0 及以上版本中,若是你使用了單文件組件,那麼基於模板的函數式組件能夠這樣聲明:vue
<template functional> </template>
組件須要的一切都是經過上下文傳遞,包括:java
props
:提供全部 prop 的對象children
: VNode 子節點的數組slots
: 返回全部插槽的對象的函數data
:傳遞給組件的數據對象,做爲 createElement
的第二個參數傳入組件parent
:對父組件的引用listeners
: (2.3.0+) 一個包含了全部在父組件上註冊的事件偵聽器的對象。這只是一個指向 data.on
的別名。injections
: (2.3.0+) 若是使用了 inject
選項,則該對象包含了應當被注入的屬性。在添加 functional: true
以後,錨點標題組件的 render 函數之間簡單更新增長 context
參數,this.$slots.default
更新爲 context.children
,以後this.level
更新爲 context.props.level
。 git
由於函數式組件只是一個函數,因此渲染開銷也低不少。然而,對持久化實例的缺少也意味着函數式組件不會出如今 Vue devtools 的組件樹裏。github
在上面多個context的屬性中,其中context.props、context.data、context.children這3個用的比較多。 context.props用來傳遞數據,context.data傳遞屬性如class、id等,context.children指插槽的默認值this.$slots.default。
api
例一數組
<body> <div id="app"> <my-function-button v-bind:class="className" id="btn1">button</my-function-button> </div> <script src="js/vue.js"></script> <script> Vue.component("my-function-button",{ functional:true, render:function(createElement,context){ return createElement("button",context.data,context.children) } }) new Vue({ el: '#app', data: { className:"btnname" }, }); //context.data 是用來傳遞屬性的,傳遞數據是context.props </script> </body>
渲染成 :<button id="btn1" class="btnname">button</button>app
例二
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>AdminLTE 2 | Morris.js Charts</title> <!-- Tell the browser to be responsive to screen width --> <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport"> <!-- Morris charts --> </head> <body> <div id="app"> <smart-list :items="items" v-bind:number="1" class="specialColor">hi</smart-list> </div> <script src="js/vue.js"></script> <script> // 組件1 var EmptyList = { template: "<p>Empty list</p>" } // 組件2 var Tablist ={ props:["chuandiData"], template:` <ul> <li v-for="item in chuandiData">{{item.name}}</li> </ul> ` } // 組件3 var component3 = { template:` <div> this is component3 </div> ` } Vue.component("smart-list", { functional: true, props: { items: { type: Array, required: true } }, render: function(createElement, context) { console.log(context) function appropriateListComponent() { var items = context.props.items if (items.length === 0) { return EmptyList } if (items.length == 3) return Tablist } return createElement( appropriateListComponent(), { props:{ chuandiData:context.props.items } } ) } }) new Vue({ el: '#app', data: { items: [{ name: 'a', id: 0 }, { name: 'b', id: 1 }, { name: 'c', id: 2 } ] }, }); //context.data 是用來傳遞屬性的,傳遞數據是context.props </script> </body> </html>
渲染成:
<ul> <li>a</li> <li>b</li> <li>c</li> </ul>
例三
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>AdminLTE 2 | Morris.js Charts</title> <!-- Tell the browser to be responsive to screen width --> <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport"> <!-- Morris charts --> </head> <body> <div id="app"> <smart-list :items="items" v-bind:number="1" class="specialColor">hi</smart-list> </div> <script src="js/vue.js"></script> <script> // 組件1 var EmptyList = { template: "<p>Empty list</p>" } // 組件2 var Tablist = { template: ` <ul> <li><slot></slot></li> </ul> ` } Vue.component("smart-list", { functional: true, props: { items: { type: Array, required: true } }, render: function(createElement, context) { console.log(context) function appropriateListComponent() { var items = context.props.items if (items.length === 0) { return EmptyList } if (items.length == 3) return Tablist } return createElement( appropriateListComponent(), context.children ) } }) new Vue({ el: '#app', data: { items: [{ name: 'a', id: 0 }, { name: 'b', id: 1 }, { name: 'c', id: 2 } ] }, }); //context.data 是用來傳遞屬性的,傳遞數據是context.props </script> </body> </html>
渲染成:<ul><li>hi</li></ul>
例四
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>AdminLTE 2 | Morris.js Charts</title> <!-- Tell the browser to be responsive to screen width --> <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport"> <!-- Morris charts --> <link rel="stylesheet" href="../../dist/css/Basic.css"> <link rel="stylesheet" href="../../dist/css/lanrenzhijia.css"> </head> <body> <div id="app"> <smart-item :data1="data">hi</smart-item> <button @click="change('img')">切換爲圖片爲組件</button> <button @click="change('video')">切換爲視頻爲組件</button> <button @click="change('text')">切換爲文本組件</button> </div> <script src="js/vue.js"></script> <script> // 圖片組件選項 var ImgItem = { props: ['data2'], render: function(createElement) { return createElement('div', [ createElement('p', '圖片組件'), createElement('img', { attrs: { src: this.data2.url } }) ]); } } // 視頻組件 var VideoItem = { props: ['data2'], render: function(createElement) { return createElement('div', [ createElement('p', '視頻組件'), createElement('video', { attrs: { src: this.data2.url, controls: 'controls', autoplay: 'autoplay' } }) ]); } }; /*純文本組件*/ var TextItem = { props: ['data2'],//二、接收1傳過來的props對象 render: function(createElement) { return createElement('div', [ createElement('p', '純文本組件'), createElement('p', this.data2.content) ]); } }; Vue.component('smart-item', { functional: true, render: function(createElement, context) { function getComponent() { var data = context.props.data1; if (data.type === 'img') return ImgItem; if (data.type === 'video') return VideoItem; return TextItem; } return createElement( getComponent(), { props: { data2: context.props.data1 //getComponent()返回的是組件,props是用來傳遞數據給返回的組件,如:TextItem組件 } } ,context.children //能夠不須要 ) }, props: { data1: { type: Object, required: true } } }); new Vue({ el: '#app', data: { data: {} }, methods: { change: function(type) { if (type === 'img') { this.data = { type: 'img', url: 'https://raw.githubusercontent.com/iview/iview/master/assets/logo.png' } } else if (type === 'video') { this.data = { type: 'video', url: 'http://vjs.zencdn.net/v/oceans.mp4' } } else if (type === 'text') { this.data = { type: 'text', content: '這是一段純文本' } } } }, created: function() { this.change('text'); } }); // </script> </body> </html>