zoukankan      html  css  js  c++  java
  • VUE自定义组件

    简介

    有时候有一组html结构的代码,并且这个上面可能还绑定了事件。然后这段代码可能有多个地方都被使用到了,如果都是拷贝来拷贝去,很多代码都是重复的,包括事件部分的代码都是重复的。那么这时候我们就可以把这些代码封装成一个组件,以后在使用的时候就跟使用普通的html元素一样,拿过来用就可以了。

    基本使用

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>vuedemo</title>
        <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    </head>
    <body>
    
    <div id="app">
        <button-counter></button-counter>
        <button-counter></button-counter>
        <button-counter></button-counter>
    </div>
    <script>
        Vue.component('button-counter', {
            data: function () {
                return {
                    count: 0
                }
            },
            template: '<button v-on:click="count++">点击了{{ count }}次</button>'
        });
        let vm = new Vue({
            el: "#app",
            data: {}
        });
    </script>
    </body>
    </html>
    

    以上我们创建了一个叫做button-counter的组件,这个组件实现了能够记录点击了多少次按钮的功能。后期如果我们想要使用,就直接通过button-counter使用就可以了。然后因为组件是可复用的Vue实例,所以它们与new Vue接收相同的选项,例如datacomputedwatchmethods以及生命周期钩子等。仅有的例外是像el这样根实例特有的选项。另外需要注意的是:组件中的data必须为一个函数!

    官网文档例子:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>vuedemo</title>
        <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    </head>
    <body>
    <div id="components-demo">
        <button-counter></button-counter>
    </div>
    
    <script>
    
        // 定义一个名为 button-counter 的新组件
        Vue.component('button-counter', {
            data: function () {
                return {
                    count: 0
                }
            },
            template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
        });
    
        //组件是可复用的 Vue 实例,且带有一个名字:在这个例子中是 <button-counter>。
        // 我们可以在一个通过 new Vue 创建的 Vue 根实例中,把这个组件作为自定义元素来使用:
        new Vue({
            el: '#components-demo',
    
        });
    
    </script>
    </body>
    </html>

    给组件添加属性

    像原始的html元素都有自己的一些属性,而我们自己创建的组件,也可以通过prop来添加自己的属性。这样别人在使用你创建的组件的时候就可以传递不同的参数了。示例代码如下:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>vuedemo</title>
        <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    </head>
    <body>
    
    <div id="app">
        <blog-post :title="blog.title" v-for="blog in blogs"></blog-post>
    </div>
    <script>
        Vue.component('blog-post', {
            props: ['title'],
            template: '<h3>{{ title }}</h3>'
        });
        new Vue({
            el: "#app",
            data: {
                blogs: [
                    {"title": "想想霸哥怎么做", "id": 1},
                    {"title": "霸王计划", "id": 2},
                    {"title": "如何学好Vue", "id": 3},
                ]
            }
        });
    </script>
    </body>
    </html>
    

    单一根元素:

    如果自定义的组件中,会出现很多html元素,那么根元素必须只能有一个,其余的元素必须包含在这个根元素中。比如以下是一个组件中的代码,会报错:

    <h3>{{ title }}</h3>
    <div v-html="content"></div>
    

    我们应该改成:

    <div class="blog-post">
      <h3>{{ title }}</h3>
      <div v-html="content"></div>
    </div>
    

    组件中自定义事件

    子组件中添加事件跟之前的方式是一样的,然后如果发生某个事件后想要通知父组件,那么可以使用this.$emit函数来实现。示例代码如下:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>vuedemo</title>
        <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    </head>
    <body>
    <div id='app'>
        <blog-item v-for="blog in blogs" :blog="blog" @check-changed="checkChanged"></blog-item>
        <h1>选中的博客:</h1>
        <div v-for="blog in selected_blogs">
            {{blog.title}}
        </div>
    </div>
    <script>
        Vue.component("blog-item", {
            props: ['blog'],
            template: `
            <div>
              <span>{{blog.title}}</span>
              <input type="checkbox" @click="onCheck">
            </div>
          `,
            methods: {
                onCheck() {
                    this.$emit("check-changed", this.blog)
                }
            }
        });
        new Vue({
            el: '#app',
            data: {
                blogs: [{
                    title: "如何学好Vue?",
                    id: "1"
                }, {
                    title: "前后端分离项目?",
                    id: "2"
                }],
                selected_blogs: []
            },
            methods: {
                checkChanged(blog) {
                    // indexOf:获取某个元素在数组中的位置,如果返回值为非负数,那么就是存在,就是下标
                    // 否则,代表这个元素在数组中不存在
                    let index = this.selected_blogs.indexOf(blog);
                    if (index >= 0) {
                        this.selected_blogs.splice(index, 1)
                    } else {
                        this.selected_blogs.push(blog)
                    }
                }
            }
        })
    </script>
    </body>
    </html>
    

    需要注意的是,因为html中大小写是不敏感的,所以在定义子组件传给父组件事件名称的时候,不要使用myEvent这种驼峰命名法,而是使用my-event这种规则。

    上述示例代码调用关系如下:

     运行结果于勾选后展示结果:

     

    自定义组件v-model

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>vuedemo</title>
        <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    </head>
    <body>
    <div id='app'>
        <Stepper v-model="goods_count"></Stepper>
    </div>
    <script>
        // 计步器
        Vue.component("Stepper", {
            props: ['count'],
            // model:用来配置v-model的表现形式
            model: {
                event: "count-changed",
                prop: "count"
            },
            template: `
            <div>
              <button @click="substract">-</button>
              <span>{{count}}</span>
              <button @click="add">+</button>
            </div>
          `,
            methods: {
                substract() {
                    // 这个里面不需要修改this.count的值,只要把结果传出去就可以了
                    this.$emit("count-changed", this.count - 1)
                },
                add() {
                    this.$emit("count-changed", this.count + 1)
                }
            }
        });
    
        new Vue({
            el: '#app',
            data: {
                goods_count: 0
            },
            watch: {
                goods_count: function (newValue, oldValue) {
                    console.log('==========');
                    console.log(newValue);
                    console.log(oldValue);
                    console.log('==========');
                }
            }
        })
    </script>
    </body>
    </html>
    

    插槽

    我们定义完一个组件后,可能在使用的时候还需要往这个组件中插入新的元素或者文本。这时候就可以使用插槽来实现。示例代码如下:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>vuedemo</title>
        <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    </head>
    <body>
    <div id="app">
        <navigation-link url="/profile/">
            个人中心
        </navigation-link>
    </div>
    <script>
        Vue.component('navigation-link', {
            props: ['url'],
            template: `
            <a v-bind:href="url" class="nav-link">
                <slot></slot>
            </a>
            `
        });
        new Vue({
            el: "#app"
        });
    </script>
    </body>
    </html>
    

    当组件渲染的时候,<slot></slot>将会被替换为“个人中心”。插槽内可以包含任何模板代码,包括HTML

        <navigation-link url="/profile">
            <span style="color: red">个人中心</span>
        </navigation-link>
    

    如果<navigation-link>没有包含一个<slot>元素,则该组件起始标签和结束标签之间的任何内容都会被抛弃。

    作用域

    通过外面传给组件的变量,在以后使用插槽的时候是不能使用的。比如以上url只能在navigation-link中使用,但是后面使用插槽的时候不能使用。比如

    <navigation-link url="/profile">
      Clicking here will send you to: {{ url }}
      <!--
      这里的 `url` 会是 undefined,因为 "/profile" 是
      _传递给_ <navigation-link> 的而不是
      在 <navigation-link> 组件*内部*定义的。
      -->
    </navigation-link>
    

    插槽默认值

    有时候在使用组件的时候,插槽中绝大部分情况是一种元素。那么我们就可以给插槽提供一个默认值,然后后面如果不想使用这个默认值的时候,就只需要提供自己定义的值就可以了。比如有一个叫做submit-button的组件,代码如下:

    <button type="submit">
      <slot>提交</slot>
    </button>
    

    然后在使用这个组件的时候,可以直接<submit-button></submit-button>,默认在里面就会显示“提交”文字。如果想要在使用的时候显示其他文字,那么也可以通过<submit-button>保存</submit-button>来实现。

    命名插槽:

    自定义组件中可以有多个插槽,这时候就需要通过名字来进行区分了。其实如果没有指定名字,默认是有一个名字叫做default的。比如我们有一个名叫container的自定义组件:

    <div class="container">
      <header>
        <slot name="header"></slot>
      </header>
      <main>
        <slot></slot>
      </main>
      <footer>
        <slot name="footer"></slot>
      </footer>
    </div>
    

    以后在使用这个组件的时候使用v-slot:插槽名的方式来加载不同的数据:

    <container>
        <template v-slot:header>
            这是头部信息
        </template>
        这是主要部分的信息
        <template v-slot:footer>
            这是网页尾部信息
        </template>
    </container>
    

    插槽作用域:

    默认在插槽中的代码只能使用全局Vue中的属性,如果想要使用自定义组件中的属性,那么需要在定义slot的时候使用v-bind来进行绑定。示例代码如下:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>vuedemo</title>
        <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    </head>
    <body>
    <div id="app">
        <sub-nav v-slot="slotProps">
            当前点击:{{slotProps.index}}
        </sub-nav>
    </div>
    <script>
        Vue.component('sub-nav', {
            props: ['url'],
            data: function () {
                return {
                    navs: ['网络设置', '路由设置', '设备管理'],
                    index: 0
                }
            },
            methods: {
                indexBtnClick: function (index) {
                    this.index = index;
                }
            },
            template: `
            <div class="container">
                <button v-for="(nav,index) in navs" @click="indexBtnClick(index)" v-bind:key="index">{{nav}}</button>
                <slot v-bind:index="index"></slot>
            </div>
            `
        });
        new Vue({
            el: "#app"
        });
    </script>
    </body>
    </html>
    

      

  • 相关阅读:
    C#中回滚TransactionScope的使用方法和原理
    CAS5.3服务器搭建与客户端整合SpringBoot以及踩坑笔记
    JSON对象、JSON字符串和Java对象互相转
    Java实体类如何映射到json数据(驼峰映射到json中的下划线)
    expected at least 1 bean which qualifies as autowire candidate
    IDEA target中没有class文件/target中有class没有yml文件/yml文件不显示叶子
    yml配置从nacos配置中心取数据(单个或多个),读读源码,寻找如何配置多个
    seata-server 1.3.0整合nacos,使用nacos做注册和配置中心
    简单读读源码
    mybatis-plus.global-config.db-config.id-type=auto 和 @TableId(value = "id", type = IdType.ASSIGN_ID)哪个优先生效
  • 原文地址:https://www.cnblogs.com/0bug/p/13043595.html
Copyright © 2011-2022 走看看