Vue.js-组件系统

vue.js 组件

组件是一个Vue可复用的实例

全局组件

全局注册的组件可以用在其被注册之后的任何 (通过 new Vue) 新创建的 Vue 根实例,也包括其组件树中的所有子组件的模板中。

组件是可复用的 Vue 实例,且带有一个名字:在这个例子中是 <button-counter>。我们可以在一个通过 new Vue 创建的 Vue 根实例中,把这个组件作为自定义元素来使用:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./static/vue.js"></script>
</head>
<body>
<div id="app">
    <button-counter></button-counter>
    <button-counter></button-counter>
    <button-counter></button-counter>
</div>

<script>

    // 全局组件的注册,使用component实例化一个vue实例
    // 因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。
    Vue.component('button-counter', {
        // 一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝
        data: function () {
            return {
                count: 0
            }
        },
        template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
    });
    // 实例化vue放下面
    new Vue({
        el: '#app',

    });
</script>
</body>
</html>

因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 datacomputedwatchmethods 以及生命周期钩子等。仅有的例外是像 el这样根实例特有的选项。

局部组件

全局注册往往是不够理想的。比如,如果你使用一个像 webpack 这样的构建系统,全局注册所有的组件意味着即便你已经不再使用一个组件了,它仍然会被包含在你最终的构建结果中。这造成了用户下载的 JavaScript 的无谓的增加。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./static/vue.js"></script>
</head>
<body>
<div id="app">
    <component-a></component-a>
    <component-b></component-b>
    <component-c></component-c>
    <component-d></component-d>
</div>

<script>
    let ComponentA = {
        template: '<button >ComponentA</button>',
    };
    let ComponentB = {
        template: '<button >ComponentB</button>',
    };
    let ComponentC = {
        template: '<button >ComponentC</button>',
    };
    // 如果想在ComponentD用ComponentA需按照以下定义
    let ComponentD = {
        template: '<button >ComponentD</button>',
        components: {
            'component-a': ComponentA,
            'component-b': ComponentB,
            'component-c': ComponentC,
        },
    };
    new Vue({
        el: '#app',

        // 注册局部组件, key是自定义的名称,value是定义的局部组件
        components: {
            // 'component-a': ComponentA,
            // 'component-b': ComponentB,
            // 'component-c': ComponentC,
            'component-d': ComponentD,
            'component-a': ComponentD.components["component-a"],
            'component-b': ComponentD.components["component-b"],
            'component-c': ComponentD.components["component-c"],
        },
    });

</script>
</body>
</html>

组件的注意事项

  1. is标识 ==》 table里面只认识tr标签不认识你写的组件
  2. 组件中的data必须是函数!!!保证每个组件内部的数据都是独立的!

vue首页导航栏超简易版

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./static/vue.js"></script>
    <style>
        .default {
            display: none;
        }

        .active {
            display: block;
        }
    </style>
</head>
<body>
<div id="app">
    <pg-header></pg-header>
</div>
<script>
    let pgHeader = {

        data: function () {
            return {
                books: [
                    {
                        title: "学习",
                        bookSrc: [
                            {bookName: "教程", bookAddr: "https://cn.vuejs.org/v2/guide/",},
                            {bookName: "API", bookAddr: "https://cn.vuejs.org/v2/api/"},
                            {bookName: "风格指南", bookAddr: "https://cn.vuejs.org/v2/style-guide/"},
                        ]
                    },
                    {
                        title: "支持Vue",
                        bookSrc: [
                            {bookName: "一次性赞助", bookAddr: "https://cn.vuejs.org/support-vuejs/#One-time-Donations",},
                            {bookName: "周期性赞助", bookAddr: "https://cn.vuejs.org/support-vuejs/#Recurring-Pledges"},
                        ]
                    }
                ],
                isDefault: true,
                curIndex: 0,
            }
        },
        template: `
        <div><div v-for="(val,index) in books" style="float: left " @mouseenter="mouseEnter(index)" >{{val['title']}}
        <ul :class="{default:isDefault, active:index===curIndex} " >
        <li v-for="(book,index2) in val['bookSrc']"><a :href="book['bookAddr']">{{book['bookName']}}</a></li>
</ul>
</div></div>
        `,
        methods: {
            mouseEnter: function (index) {
                this.curIndex = index;
            }
        },

    };

    new Vue({
        el: '#app',
        components: {
            'pg-header': pgHeader,

        },
    });
</script>
</body>
</html>

父子组件之间的数据传递

父向子传递数据

  1. 在子组件中通过 props 声明需要被传递的参数
  2. 在父组件中通过v-bind:变量名='变量' 传递数据
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./static/vue.js"></script>
</head>
<body>
<div id="app">
    <father></father>
</div>
<script>
    // 2. 在子组件中使用props接收这个数据
    let child = {
        template: `<div>{{fatherDate}}</div>`,
        props: ['fatherDate']
    };

    // 1. 在父组件里面的子组件中绑定一个自定义属性l
    let father = {
        template: `<div><child v-bind:fatherDate="msg"></child></div>`,
        data: function () {
            return {
                msg: 'hahahahahahaha',
            }
        },
        components: {
            'child': child,
        }
    };

    new Vue({
        el: '#app',
        components: {
            'father': father,
        },
    });
</script>
</body>
</html>

子向父传递数据

  1. 子组件中通过 $emit('自定义事件名')向外抛出自定义事件
  2. 父组件中用过 v-on:自定义事件名=动作函数监听子组件抛出的事件
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./static/vue.js"></script>
</head>
<body>
<div id="app">
    <father></father>
</div>
<script>
    let child = {
        template: `<div><button v-on:click="changeSize">点击修改父组件的字体大小</button></div>`,
        methods: {
            changeSize: function () {
                this.$emit("change-size");
            }
        }
    };
    // 1. 在父组件的子组件中绑定一个自定义事件
    let father = {
        template: `<div><child v-on:change-size="fontSize++"></child>
                        <span :style="{fontSize: fontSize + 'px'}">233</span></div>`,
        data: function () {
            return {
                fontSize: 20,
            }
        },
        components: {
            'child': child,
        }

    };
    new Vue({
        el: '#app',
        components: {
            'father': father,
        }
    });
</script>
</body>
</html>

组件间传值

借助一个独立的Vue对象实现组件间通信

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="./static/vue.js"></script>
</head>
<body>
<div id="app">
    <my-component-a></my-component-a>
    <hr>
    <my-component-b></my-component-b>
</div>
<script>
    /*
    * 简介
    * 两个独立的组件,A,B(data),B中修改数据data,A中实时获取B中修改的数据data
    *
    * */

    // 借助一个空的Vue对象实现组件间通信
    let bus = new Vue();    // 大项目用这个VueX
    let A = {
        template: `
            <div>
                <h1>这是子组件:my-component-a</h1>
                <p>my-component-a被选中的次数:{{num}}</p>
            </div>
            `,
        data() {
            return {
                num: 0,
            }
        },
        mounted() {
            // 在文档准备就绪之后就要开始监听bus是否触发了 dianwo 的事件
            /*
            bus.$on('dianwo', function (val) {
                console.log(val);
                // this.num++; // 这个 this 是谁?
                console.log(this);  // this 并不是组件A
            })
            */
            bus.$on('dianwo', (val) => {
                this.num++; // 这个 this 是谁?
                console.log(this);  // this 是组件A
            })

        },

    };
    let B = {
        template: `
            <div>
                <h1>这是子组件:my-component-b</h1>
                <button v-on:click="add">点我</button>
            </div>
            `,
        data() {
            return {
                num: 0,
            }
        },
        methods: {
            add() {
                this.num++;
                // 利用bus对象抛出一个自定义事件
                bus.$emit('dianwo', this.num);
            }
        }
    };
    let app = new Vue({
        el: '#app',
        data: {
            totalNum: 0,
        },
        components: {
            'my-component-a': A,
            'my-component-b': B,
        }

    });
</script>
</body>
</html>

混入

提高代码重用性

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./static/vue.js"></script>
</head>
<body>
<div id="app">
    <aaa></aaa>
    <bbb></bbb>
</div>
<script>
    let xxx = {
        methods: {
            show: function (name) {
                console.log(`${name}`)
            },
            hide: function (name) {
                console.log(`${name}`)
            }
        }
    };
    let aaa = {
        template: `<div>
                <button v-on:click="show('233')">233</button>
                <button v-on:click="hide('233')">233</button>
                </div>`,
        mixins: [xxx]
    };
    let bbb = {
        template: `<div>
                <button v-on:click="show('666')">666</button>
                <button v-on:click="hide('666')">666</button>
                </div>`,
        mixins: [xxx]

    };
    new Vue({
        el: '#app',
        components: {
            'aaa': aaa,
            'bbb': bbb,
        }
    })
</script>
</body>
</html>

插槽

元素作为承载分发内容的出口,可以实现组件的复用。简单的说就是《定制模板》,一个template由多个插槽组成,分发不同的内容,产生各种形态的组件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./static/vue.js"></script>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        .box {
            height: 200px;
            width: 200px;
            background-color: red;
            float: left;
            margin-left: 20px;
            text-align: center;
            line-height: 100px;
        }
    </style>
</head>
<body>
<div id="app">
    <global-component>
        <template slot="header">这里是header</template>
        <template slot="body">哈哈哈哈</template>
    </global-component>
    <!--如果没有值将会采用默认值-->
    <global-component></global-component>
</div>
<script>
    Vue.component('global-component', {
        // <slot></slot>  可以使上面插入233,也就是说可以在html中插入数据
        // <slot name="body">666</slot>  具名插槽
        template: `<div><div class="box">
                        <strong><slot name="header">header</slot></strong>
                        <br>
                        <slot name="body">body</slot>
                    </div></div>`
    });

    new Vue({
        el: '#app',
    })
</script>
</body>
</html>

element-ui

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="./static/vue.js"></script>
    <!-- 引入样式 -->
    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
    <!-- 引入组件库 -->
    <script src="https://unpkg.com/element-ui/lib/index.js"></script>
    <style>
        .el-carousel__item h3 {
            color: #475669;
            font-size: 14px;
            opacity: 0.75;
            line-height: 150px;
            margin: 0;
        }

        .el-carousel__item:nth-child(2n) {
            background-color: #99a9bf;
        }

        .el-carousel__item:nth-child(2n+1) {
            background-color: #d3dce6;
        }
    </style>
</head>
<body>
<div id="app">
    <template>
        <div class="block">
            <el-carousel height="">
                <el-carousel-item v-for="(val,index) in images" :key="index">
                    <img :src="val" alt="" style="width: 100%">
                </el-carousel-item>
            </el-carousel>
        </div>
    </template>

</div>
<script>
    new Vue({
        el: '#app',
        data: {
            images: ['./images/1.png', './images/2.png', './images/3.png', './images/4.png', './images/5.png'],
        }
    })
</script>
</body>
</html>
posted @ 2019-08-16 16:06  写bug的日子  阅读(118)  评论(0编辑  收藏  举报