函數式組件完整例子

以前建立的組件是比較簡單,沒有管理或者監放任何傳遞給他的狀態,也沒有生命週期方法。它只是一個接收參數的函數。
在下面這個例子中,咱們標記組件爲 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>
相關文章
相關標籤/搜索