vue组件化开发

一、基本步骤

1.创建组件构造器

调用Vue.extend()方法创建组件构造器。

  • 通常在创建组件构造器时,传入template代表我们自定义组件的模板。该模板就是在使用到组件的地方,要显示的HTML代码。(此种方法很少使用)

2.注册组件

调用Vue.component()方法注册组件。

  • 调用Vue.component()是将刚才的组件构造器注册为一个组件,并且给它起一个组件的标签名称。所以需要传递两个参数:1、注册组件的标签名 2、组件构造器

3.使用组件

在Vue实例的作用范围内使用组件。

<body>
    <div id="app">
        <!-- 3.使用组件 -->
        <my-cpn></my-cpn>
        <my-cpn></my-cpn>
        <my-cpn></my-cpn>
    </div>

    <script>
        //1.创建组件构造器
        const cpnC = Vue.extend({
            template:`
                <div>
                    <h2>我是标题</h2>
                    <p>我是内容,哈哈哈</p>
                    <p>我是内容,呵呵呵</p>
                </div>`
        })

        //2.注册组件(全局组件)
        // Vue.component("组件标签名", 组件构造器)
        Vue.component("my-cpn", cpnC);

        const app = new Vue({
            el: '#app',
            data: {
                
            },
        })

    Vue.config.productionTip = false
    </script>
</body>

二、全局组件与局部组件

  • 当我们通过调用Vue.component()注册组件时,组件的注册是全局的,这意味着该组件可以在任意Vue示例下使用。
  • 如果我们注册的组件是挂载在某个实例中, 那么就是一个局部组件
<body>
    <div id="app">
        <cpn></cpn>
        <cpn></cpn>
        <cpn></cpn>
    </div>
    <div id="root">
        <cpn></cpn>
        <cpn></cpn>
        <cpn></cpn>
    </div>

    <script>
        //1.创建组件构造器
        const cpnC = Vue.extend({
            template:`
                <div>
                    <h2>我是标题</h2>
                    <p>我是内容,哈哈哈</p>
                    <p>我是内容,呵呵呵</p>
                </div>`
        })
        // //2.注册组件(全局组件,意味着可以在多个Vue实例下面使用)
        // Vue.component("cpn", cpnC);

        const app1 = new Vue({
            el: '#app',
            data: {
                
            },
            //这里注册局部组件,只能在该Vue实例下面使用 
            components:{
                cpn: cpnC
            }
        });
        const app2 = new Vue({
            el: '#root',
            data: {
                
            },
        })

    Vue.config.productionTip = false
    </script>
</body>

三、父组件与子组件

  • 父子组件错误用法以子标签的形式在Vue实例中使用

1.因为当子组件注册到父组件的components时,Vue会编译好父组件的模块

2.该模板的内容已经决定了父组件将要渲染的HTML(相当于父组件中已经有了子组件中的内容了)

3.< cpn1>< /cpn1>是只能在父组件中被识别的。

<body>
    <div id="app">
        <cpn2></cpn2>
    </div>

    <script>
        //1.创建第一个组件构造器(子组件)
        const cpnC = Vue.extend({
            template:`
                <div>
                    <h2>我是标题1</h2>    
                    <p>内容1</p>
                </div>`
        });
        //创建第二个组件构造器(父组件)
        const cpnC2 = Vue.extend({
            template:`
                <div>
                    <h2>我是标题2</h2>    
                    <p>内容2</p>
                    <cpn1></cpn1>
                </div>`,
            components:{
                cpn1: cpnC,//在父组件中声明子组件
            }
        })

        const app = new Vue({
            el: '#app',
            data: {
                
            },
            components:{
                cpn2: cpnC2
            }
        })

    Vue.config.productionTip = false
    </script>
</body>

四、注册组件的语法糖

主要是省去了调用Vue.extend()的步骤,而是可以直接使用一个对象来代替。

<body>
    <div id="app">
        <cpn1></cpn1>
        <cpn2></cpn2>
    </div>

    <script>
        //全局注册组件语法糖写法
        // const cpnC1 = Vue.extend()
        Vue.component("cpn1",{
            template:`
                <div>
                    <h2>我是标题</h2>    
                    <p>内容</p>
                </div>`
        });


        const app = new Vue({
            el: '#app',
            data: {
                
            },
            components:{
                //局部组件语法糖
                cpn2:{
                    template:`
                        <div>
                            <h2>我是标题2</h2>    
                            <p>内容2</p>
                        </div>`
                } 
            }
        })

    Vue.config.productionTip = false
    </script>
</body>

五、组件模板抽离

Vue提供了两种方案来定义HTML模块内容:

  • 使用< script>标签
  • 使用< template>标签
<body>
    <div id="app">
        <cpn></cpn>
    </div>

    <!-- 方法1:<script type="text/x-template" id="temp"> -->
    <!-- <script type="text/x-template" id="temp">
        <div>
            <h2>标题</h2>
            <p>内容</p>
        </div>
    </script> -->

    <!-- 方法2: -->
    <template id="temp">
        <div>
            <h2>标题</h2>
            <p>内容</p>
        </div>
    </template>
    
    <script>
        Vue.component("cpn",{
            template:"#temp"
        })


        const app = new Vue({
            el: '#app',
            data: {
                
            },
        })

    Vue.config.productionTip = false
    </script>
</body>

六、组件中的数据存放问题

组件是一个单独功能模块的封装:这个模块有属于自己的HTML模板,也应该有属性自己的数据data。

组件中的数据是保存在哪里呢?顶层的Vue实例中吗?答:不在顶层的Vue实例中,Vue组件有自己保存数据的地方

  • 组件对象也有一个data属性(也可以有methods等属性,下面我们有用到),只是这个data属性必须是一个函数,而且这个函数返回一个对象,对象内部保存着数据。

  • 为什么data在组件中必须是一个函数呢? 原因是在于Vue让每个组件对象都返回一个新的对象,因为如果是同一个对象的,组件在多次使用后会相互影响。

<body>
    <div id="app">
        <!-- 这里的content是 数组数据 -->
        <cpn></cpn>
        <!-- 这里的content是 title -->
        <cpn2></cpn2>
    </div>

    <template id="temp">
        <div>
            <h2>标题</h2>
            <p>{{content}}</p>
        </div>
    </template>
    
    <script>
        //Vue组件
        Vue.component("cpn", {
            template:"#temp",
            data() {//这里的data必须是函数
                return {
                    content: "组件数据"
                }
            }
        });
        //顶层Vue
        const app = new Vue({
            el: '#app',
            data: {
                content: "根数据"
            },
            components:{
                cpn2:{
                    template:"#temp",
                    data() {
                        return {
                            content: "title"
                        }
                    }
                }
            }
        })

    Vue.config.productionTip = false
    </script>
</body>

七、父子组件的通讯

1.通过props向子组件传递数据

(1)props的值有两种方式
  • 方式一:字符串数组,数组中的字符串就是传递时的名称。

  • 方式二:对象,对象可以设置传递时的类型,也可以设置默认值等。

类型可以是: String Number Boolean Array Object Date Function Symbol

<body>
    <div id="app">
        <div>
             内容
        </div>
        <cpn v-bind:cmovies="movies" ></cpn>//注意这里要用v-bind绑定数据
    </div>

    <template id="temp">
        <!-- div不能省略 -->
        <div>
            <p>{{cmessage}}</p>
            <p>{{cmovies}}</p>
            <ul>
                <li v-for="item in cmovies">{{item}}</li>
            </ul>
        </div>
    </template>

    <script>
        // const cpn = Vue.extend({
        //     template:"#temp",  //此处#忘记加了
        //     data() {
        //         return {}
        //     },
        //     props:["cmovies","cmessage"],
        // });
        // 可以简写为
        const cpn = {
            template:"#temp",  //此处#忘记加了
            data() {
                return {}
            },
            // 方式一:字符串数组,数组中的字符串就是传递时的名称。
            // props:["cmovies","cmessage"],
            // 方式二:对象,对象可以设置传递时的类型,也可以设置默认值等。
            props:{
                // 1.类型限制
                cmovies: Array,
                cmessage: String,
                
                // 2.可以是多个可能的类型
                // cmessage: [String,Number]

                // 3.提供一些默认值
                // cmessage:{
                //     type: String,
                //     default: "aaaaaaaa"
                // }

                // 4.必须传递值
                // cmessage:{
                //     type: String,
                //     required: true,
                // }

                // 5.type是对象或数组时必须从工厂函数获取
                // cmessage: {
                //     type: Object,
                //     default() {//这里必须是工厂函数
                //        return {
                //            cmessage:"hello"
                //        } 
                //     }
                // }

                // 6.自定义验证函数
            }

        }

        const app = new Vue({
            el: '#app',
            data: {
                movies:["该往","发生的反对","范德萨"],
                message: "sfd"
            },
            components:{
                cpn
                // 也可以写成
                // cpn:{
                //     template:"#temp",  //此处#忘记加了
                //     data() {
                //         return {}
                //     },
                //     props:["cmovies","cmessage"],
                // }
            }
            
            
        })

    Vue.config.productionTip = false
    </script>
</body>
(2)驼峰标识问题
<body>
    <div id="app">
        <!-- 驼峰标识,这里需要使用c-message的形式 -->
        <cpn :c-message="message"></cpn>
    </div>


    <template id="temp">
        <div>
            <!-- 这里直接驼峰标识就可以了,不用c-message的形式 -->
            <h2>{{cMessage}}</h2>
            <h2>{{cMessage}}</h2>
        </div>
    </template>
    <script>

        const app = new Vue({
            el: '#app',
            data: {
                message: [12,21,312]
            },
            components:{
                cpn:{
                    template:"#temp",//又一次忘了#
                    props:{
                        cMessage: {
                            type: Array,
                            default() {
                                return "默认值"
                            }
                        }
                    }
                }
            }
        })

    Vue.config.productionTip = false
    </script>
</body>

2.通过事件向父组件发送消息

自定义事件的流程:

1.在子组件中,通过$emit()来触发事件。

2.在父组件中,通过v-on来监听子组件事件。

<body>
    <div id="app">
        <!-- cpnclick这里省略参数后,默认将item传过去 -->
        <!-- 父组件监听子组件发射的itemclick事件,当收到子组件发射的自定义事件(itemclick事件)后执行事件cpnclick -->
        <cpn v-on:itemClick="cpnclick"></cpn>
    </div>

    <template id="temp">
        <div>
            <!-- 当点击了按钮触发btnclicl事件,btnclick(item)事件的作用是将自定义事件发射给父组件 -->
            <button v-for="item in choice" @click="btnclick(item)">{{item.name}}</button>
        </div>
    </template>
    <script>
        //子组件
        const cpn = {
            template:"#temp",
            data() {
                return {
                    choice:[
                    {id: 'aaa', name: '热门推荐'},
                    {id: 'bbb', name: '手机数码'},
                    {id: 'ccc', name: '家用电器'},
                    {id: 'ddd', name: '电脑办公'},
                    ]
                }
            },
            methods: {
                btnclick(item) {
                    // 发射事件(itemclick)给父组件
                    this.$emit('itemclick',item);//itemclick事件名称,itemclick为自定义事件,item为传递的参数
                }
            }
        }

        const app = new Vue({
            el: '#app',
            data: {
                
            },
            components: {
                cpn
            },
            methods: {
                cpnclick(item) {
                    console.log(item);
                }
            }
        })

    Vue.config.productionTip = false
    </script>
</body>

3.父组件访问子组件

父组件访问子组件:使用 c h i l d r e n 或 children或 childrenrefs

$children的缺陷:

  • 通过$children访问子组件时,是一个数组类型,访问其中的子组件必须通过索引值。
  • 但是当子组件过多,我们需要拿到其中一个时,往往不能确定它的索引值,甚至还可能会发生变化。
  • 有时候,我们想明确获取其中一个特定的组件,这个时候就可以使用$refs

$refs的使用:

  • $refs和ref指令通常是一起使用的。
  • 首先,我们通过ref给某一个子组件绑定一个特定的ID。
  • 其次,通过this.$refs.ID就可以访问到该组件了。
<body>
    <div id="app">
        <cpn></cpn>
        <cpn></cpn>
        <cpn ref="aaa"></cpn>
        <button @click="btnClick">按钮</button>
    </div>

    <template id="temp">
        <div>我是子组件</div>
    </template>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                message: "你好啊"
            },
            methods: {
                btnClick() {
                    // 1.$children (开发中很少用)
                    // console.log(this.$children);
                    // for (let c of this.$children) {
                    //     console.log(c.name);
                    //     c.showMessage();
                    // }

                    // 2.$refs(开发中几乎都用这个方法)
                    console.log(this.$refs.aaa.name);

                }
            },
            components:{
                cpn: {
                    template:"#temp",
                    methods: {
                        showMessage() {
                            console.log("showMessage")
                        }
                    },
                    data() {
                        return {
                            name: "我是子组件的name"
                        }
                    }
                }
            }
        })

    Vue.config.productionTip = false
    </script>
</body>

4.子组件访问父组件(了解)

如果我们想在子组件中直接访问父组件,可以通过$parent

注意事项:

  • 尽管在Vue开发中,我们允许通过$parent来访问父组件,但是在真实开发中尽量不要这样做。
  • 子组件应该尽量避免直接访问父组件的数据,因为这样耦合度太高了。
  • 如果我们将子组件放在另外一个组件之内,很可能该父组件没有对应的属性,往往会引起问题。
  • 另外,更不好做的是通过$parent直接修改父组件的状态,那么父组件中的状态将变得飘忽不定,很不利于我的调试和维护。
<body>

<div id="app">
  <cpn></cpn>
</div>

<template id="cpn">
  <div>
    <h2>我是cpn组件</h2>
    <ccpn></ccpn>
  </div>
</template>

<template id="ccpn">
  <div>
    <h2>我是子组件</h2>
    <button @click="btnClick">按钮</button>
  </div>
</template>

<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊'
    },
    components: {
      cpn: {
        template: '#cpn',
        data() {
          return {
            name: '我是cpn组件的name'
          }
        },
        components: {
          ccpn: {
            template: '#ccpn',
            methods: {
              btnClick() {
                // 1.访问父组件$parent
                // console.log(this.$parent);
                // console.log(this.$parent.name);

                // 2.访问根组件$root
                console.log(this.$root);
                console.log(this.$root.message);
              }
            }
          }
        }
      }
    }
  })
</script>

</body>

5.slot插槽

(1)默认插槽
(2)具名插槽
(3)作用域插槽
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值