• 【Vue组件系统】


    "vue.js既然是框架,那就不能只是简单的完成数据模板引擎的任务,它还提供了页面布局的功能。本文将详细介绍使用vue.js进行页面布局的强大工具——vue.js组件系统。

    每一个新技术的诞生,都是为了解决特定的问题。
    组件的出现就是为了解决页面布局等等一系列的问题。
    Vue中的组件分为两种:全局组件与局部组件.
    @



    全局组件


    注册

    方式一:

    <body>
    <div id="app"></div>
    <script>
    	// 下面的'global-component'是自定义的组件名,也是自定义的标签名
        Vue.component('global-component', {
            // 错误写法:(网页中不会显示)
            // template: `<h1>{{ zyk }}</h1><h1>{{ zyk }}</h1>`,
    
            // 正确写法:(要在外面套一层标签)
            template: `
                <div>
                    <h1>{{ zyk01 }}</h1>
                    <h1>{{ zyk02 }}</h1>
                </div>
            `,
            // data必须是函数,固定写法
            data() {
                return {
                    zyk01: 'Hello zyk01',
                    zyk02: 'Hello zyk02',
                };
            },
        });
        new Vue({
            el: '#app',
            template: '<global-component></global-component>',
        });
    </script>
    </body>
    

    方式二:

    <body>
    <div id="app">
        <!--调用自定义的标签名 可重复调用 -->
        <global-component></global-component>
        <global-component></global-component>
    </div>
    <script>
        // 下面的'global-component'是自定义的组件名,也是自定义的标签名
        Vue.component('global-component', {
            // 错误写法:(网页中不会显示)
            // template: `<h1>{{ zyk }}</h1><h1>{{ zyk }}</h1>`,
    
            // 正确写法:(要在外面套一层标签)
            template: `
                <div>
                    <h1>{{ zyk }}</h1>
                </div>
            `,
            // data必须是函数,固定写法
            data() {
                return {
                    zyk: 'Hello zyk',
                };
            },
        });
        new Vue({
            el: '#app',
        });
    </script>
    </body>
    


    局部组件

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

    全局组件适中是存在的,除非程序结束,如果组件越来越大,那么程序所占用的空间和消耗的性能就会更大。

    所以我们需要使用局部组件。不用的时候,被垃圾回收。


    注册

    方式一:

    <body>
    <div id="app">
        <!--第三步:在根元素中使用-->
        <!--会将当前div渲染进DOM(也就是这里id为app的div)-->
        <my-header></my-header>
    </div>
    <script>
    	// 第一步:创建局部组件
        let Header = {
            template: `
                <div>
                    <button @click='count++'>{{ count }}</button>
                    <button @click='count++'>{{ count }}</button>
                </div>
            `,
            data() {
                return {
                    count: 0,
                };
            },
        };
        new Vue({
            el: '#app',
            // 第二步:在根实例中调用它
            components: {
                'my-header': Header,
            },
        });
    </script>
    </body>
    

    方式二:

    <body>
    <div id="app"></div>
    <script>
        let Header = {
            template: `
                <div>
                    <button @click="count++">{{ count }}</button>
                    <button @click="count++">{{ count }}</button>
                </div>
            `,
            data() {
                return {
                    count: 0,
                };
            },
        };
        new Vue({
            el: '#app',
            // 这种方法不会将div渲染进DOM,以template为根元素
            template: `<my-header></my-header>`,
            // template: `<my-header/>`,
            components: {
                'my-header': Header,
            },
        });
    </script>
    </body>
    

    对于components 对象中的每个属性来说,其属性名就是自定义元素的名字,其属性值就是这个组件的选项对象。


    子组件的用法

    <body>
    <div id="app"></div>
    <script>
        // 第一步:创建一个局部组件(作为子组件)
        let Header01 = {
            template: `
                <div style='color: green;'>
                    <h1>{{ greeting }}</h1>
                </div>
            `,
            data () {
                return {
                    greeting: "我是子组件:Header01",
                };
            },
        };
    
        // 再创建一个吧(子组件)
        let Header02 = {
            template: `
                <div style='color: blue;'>
                    <h1>{{ greeting }}</h1>
                </div>
            `,
            data () {
                return {
                    greeting: "我是子组件:Header02",
                };
            },
        };
    
        // 下面的这个作为父组件
        let App = {
            // 第二步:在父组件中调用子组件
            template: `
                <div style='background-color: black;'>
                    <app-header01></app-header01>
                    <app-header02></app-header02>
                </div>
            `,
            // 第三步:在父组件中注册子组件
            components: {
                'app-header01': Header01,
                'app-header02': Header02,
            },
        };
    
        new Vue({
            el: '#app',
            template: `<App></App>`,
            components: {
                App,
            },
        });
    </script>
    </body>
    

    父子组件的通讯

    <body>
    <div id="app"></div>
    <script>
        // 子组件
        let Header = {
            // ==== 第四步:调用提取后的数据 ====
            template: `
                <div>
                    <h1>{{ greeting }} {{ fatherData }} </h1>
                </div>
            `,
            // ==== 第三步:提取传入的数据====
            props: ['fatherData'],
            // props:["传入时指定的关键字", "..."]  -> 固定写法,可传入多个值
            data() {
                return {
                    greeting: 'Hello',
                };
            },
        };
    
        // 父组件
        let App = {
            // ==== 第一步:将数据传入子组件 ====
            // 下面的:fatherData="name"为传入子组件中数据,前者为传入关键字,后者为data中返回的数据
            template: `
                <div>
                    <app-header :fatherData="name"></app-header>
                </div>
            `,
            components: {
                'app-header': Header,
            },
            data() {
                return {
                    // ==== 第一步:先定义一个数据 ====
                    name: 'zyk',
                };
            },
        };
    
        new Vue({
            el: '#app',
            template: `<App></App>`,
            components: {
                App,
            },
        });
    </script>
    </body>
    

    子父组件的通讯

    下面示例的基本思路:
    ·
    子组件与父组件各定义一个事件,且子组件事件函数中可触发父组件的事件.

    1. 先触发子组件中的事件——执行子组件事件函数;
    2. 在子组件的事件函数中触发父组件的事件,同时向父组件传入数据;
    3. 父组件事件被触发,同时接收传入的数据,执行事件,ok.
    <body>
    <div id="app"></div>
    <script>
        // 子组件
        let Header = {
            template: `
                <div>
                    <button @click="somClick">点我让BaBa变大</button>
                </div>
            `,
            methods: {
                somClick: function () {
                    // Vue中给我提供的触发自定义事件的方式:
                    this.$emit('change-size', 0.1);
                    // this.$emit("父组件事件名", "参数(即传入父组件的数据)")
                },
            },
        };
    
        // 父组件
        let App = {
            // 下面的change-size是自定义的事件名,fatherClick是事件函数
            template: `
                <div>
                    <my-header @change-size="fatherClick"></my-header>
                    <span :style="{ fontSize: postFontSize + 'em' }">我是BaBa</span>
                </div>
            `,
            components: {
                'my-header': Header,
            },
            data() {
                return {
                    postFontSize: 1,
                };
            },
            methods: {
                fatherClick: function (value) {
                    // value是this.$emit('change-size', 0.1);传过来的参数(0.1)
                    this.postFontSize += value;
                },
            },
        };
    
        new Vue({
            el: '#app',
            template: `<App></App>`,
            components: {
                App,
            },
        });
    </script>
    </body>
    

    非父子组件的通讯

    <body>
    <div id="app">
        <zyk01></zyk01>
        <zyk02></zyk02>
    </div>
    <script>
        // 用作中间调度器
        let Event = new Vue();
        let zyk01 = {
            template: `
                <div>
                    <h1>zyk01</h1>
                    <button @click="click01">点击向zyk02传数据</button>
                </div>
            `,
            methods: {
                click01: function () {
                    // Event.$emit('事件函数名', "要传的数据");
                    Event.$emit('click02', "这是zyk01向zyk02发送的消息");
                },
            },
        };
        let zyk02 = {
            template: `
                <div>
                    <h1>zyk02</h1>
                    <span>{{ say }}</span>
                </div>
            `,
            data() {
                return {
                    say: '',
                };
            },
            mounted() {
                let that = this;
                // 监听中间调度器中的方法:$on("事件函数名", "要执行的函数")
                Event.$on('click02', function (data) {
                    console.log(data);
                    that.say = data;
                })
            }
        };
        const app = new Vue({
            el: '#app',
            components: {
                zyk01: zyk01,
                zyk02: zyk02,
            },
        });
    </script>
    </body>
    


    混入

    混入可提高代码的重用性.

    <body>
    <div id="app">
        <test01></test01>
        <test02></test02>
    </div>
    <script>
        let mixs = {
            methods: {
                show: function (name) {
                    console.log(name + "来了");
                },
                hide: function (name) {
                    console.log(name + "走了");
                },
            },
        };
    
        let Test01 = {
            // mouseenter:获取光标  mouseleave:失去光标
            template: `
                <div>
                    <button @mouseenter="show('鼠标01')" @mouseleave="hide('鼠标01')">鼠标01</button>
                </div>
            `,
            mixins: [mixs],  // !
        };
    
        let Test02 = {
            template: `
                <div>
                    <button @mouseenter="show('鼠标02')" @mouseleave="hide('鼠标02')">鼠标02</button>
                </div>
            `,
            mixins: [mixs],  // !
        };
    
        new Vue({
            el: '#app',
            components: {
                'test01': Test01,
                'test02': Test02,
            },
        });
    </script>
    </body>
    


    插槽

    有时候我们需要向组件传递一些数据,这时候可以使用插槽.

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
        <title>test</title>
        <style>
            .box {
                 50px;
                height: 50px;
                background-color: green;
                float: left;
                margin-left: 5px;
            }
        </style>
    </head>
    <body>
    <div id="app">
        <global-component>test01</global-component>
        <global-component>test02</global-component>
        <global-component>test03</global-component>
        <global-component>test04</global-component>
        <global-component>test05</global-component>
    </div>
    <script>
        // 下面的<slot></slot>标签,就是插槽(内容分发)
        Vue.component("global-component", {
            template: `
                <div class="box">
                    <slot></slot>
                </div>
            `,
        });
    
        new Vue({
            el: '#app',
        });
    </script>
    </body>
    </html>
    


    具名插槽

    该操作使用了组件的复用,通过使用具名插槽,我们可以在同一个组件内写入不同的页面,并且给不同的内容命名.

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
        <title>test</title>
        <style>
            .box {
                 50px;
                height: 65px;
                background-color: green;
                float: left;
                margin-left: 5px;
            }
        </style>
    </head>
    <body>
    <div id="app">
        <global-component>
            <!--定义具名插槽-->
            <div slot="test01">test01</div>
            <div slot="test02">test02</div>
            <div slot="test03">test03</div>
            <div>test04</div>
            <div>test05</div>
        </global-component>
    </div>
    <script>
        Vue.component("global-component", {
            // <slot name="指定上面定义的具名插槽"></slot>
            // 注意显示顺序,是按照调用的先后排序的
            // 最后面的<slot></slot>是默认插槽(未命名插槽),它会作为所有未匹配到插槽的内容的统一出口
            template: `
                <div class="box">
                    <slot name="test01"></slot>
                    <slot name="test03"></slot>
                    <slot name="test02"></slot>
                    <slot></slot>
                </div>
            `,
        });
    
        new Vue({
            el: '#app',
        });
    </script>
    </body>
    </html>
    


    使用组件的注意事项

    单个根元素
    当构建一个内容页面的组件时,我们的组件可能包含多个HTML标签。

    <h1>Hello World</h1>
    <h2>Hello Vue</h2>
    

    然而如果你在模板中尝试这样写,Vue 会显示一个错误,并解释道 every component must have a single root element (每个组件必须只有一个根元素)。你可以将模板的内容包裹在一个父元素内,来修复这个问题,例如:

    <div>
      <h1>Hello World</h1>
      <h2>Hello Vue</h2>
    </div>
    

    解析特殊的HTML元素

    有些HTML元素,必须< ul >、< ol >、< table >和< select >,对于哪些元素可以出现在其内部是有严格限制的,而有些元素,例如< li >、< tr >和< option >,只能出现在其它某些特定元素的内部。

    这会导致我们使用这些有约束条件的元素时遇到一些问题。例如:

    <table>
      <blog-post-row></blog-post-row>
    </table>
    

    这个自定义组件 < blog-post-row > 会被作为无效的内容提升到外部,并导致最终渲染结果出错。幸好这个特殊的 is 特性给了我们一个变通的办法:

    <table>
      <tr is="blog-post-row"></tr>
    </table>
    

    需要注意的是,如果我们从以下来源使用模板的话,这条限制是不存在的:

    字符串 (例如:template: '...')
    单文件组件 (.vue)
    <script type="text/x-template">
    


    使用组件实现导航栏

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>导航栏</title>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.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>
            body {
                margin: 0;
                padding: 0;
            }
    
            .header {
                position: fixed;
                top: 0;
                left: 0;
                 100%;
            }
    
            .el-menu {
                display: flex;
                align-items: center;
                justify-content: center;
            }
    
            .footer {
                position: fixed;
                bottom: 0;
                left: 0;
                 100%;
            }
    
            .header img {
                position: absolute;
                left: 80px;
                top: -4px;
                 118px;
                height: 70px;
                z-index: 999;
            }
    
        </style>
    </head>
    <body>
    
    <div id="app">
    
    </div>
    
    <template id="header">
        <div class="header">
            <img src="https://www.luffycity.com/static/img/head-logo.a7cedf3.svg"/>
            <el-menu :default-active="activeIndex" class="el-menu-demo" mode="horizontal">
                <el-menu-item index="1">标题01</el-menu-item>
                <el-menu-item index="2">标题02</el-menu-item>
                <el-menu-item index="3">标题03</el-menu-item>
                <el-menu-item index="4">标题04</el-menu-item>
                <el-menu-item index="5">标题05</el-menu-item>
                <el-menu-item index="6">标题06</el-menu-item>
                <el-menu-item index="7">标题07</el-menu-item>
                <el-menu-item index="8">标题08</el-menu-item>
            </el-menu>
        </div>
    
    </template>
    
    
    <template id="footer">
        <div class="footer">
    
            <el-menu class="el-menu-demo" mode="horizontal" background-color="black">
                <el-menu-item index="1">关于我们</el-menu-item>
                <el-menu-item index="2">联系我们</el-menu-item>
                <el-menu-item index="3">商业合作</el-menu-item>
                <el-menu-item index="4">帮助中心</el-menu-item>
                <el-menu-item index="5">意见反馈</el-menu-item>
                <el-menu-item index="6">新手指南</el-menu-item>
            </el-menu>
    
        </div>
    
    </template>
    
    
    <script>
    
        let pageHeader = {
            template: "#header",
            data() {
                return {
                    activeIndex: "1",
                }
            }
        };
    
        let pageFooter = {
            template: "#footer",
        };
    
        let App = {
            template: `
                    <div>
                        <div>
                            <page-header></page-header>
    
                        </div>
                        <div>
                            <page-footer></page-footer>
                        </div>
                    </div>
                `,
            components: {
                'page-header': pageHeader,
                'page-footer': pageFooter,
            }
        };
    
        new Vue({
            el: "#app",
            template: `<app></app>`,
            components: {
                'app': App,
            }
        })
    
    </script>
    </body>
    </html>
    

    "

  • 相关阅读:
    wed
    郁闷的星期三
    Mon
    烟斗信息
    10.3
    德国装甲兵之歌
    危急!开发进入瓶颈阶段
    血糯米粥
    上海:烟斗
    如果你的博客被转载?
  • 原文地址:https://www.cnblogs.com/zyk01/p/11376131.html
Copyright © 2020-2023  润新知