Vue组件

Vue组件

创建方法

1、创建组件构造器对象Vue.extend({template:})
     template自定义的组件模板
2、注册组件Vue.component(注册组件的标签名,组件构造器)
// 1、创建组件构造器对象Vue.extend({template:})
        // template自定义的组件模板
        const cpnC = Vue.extend({
            template:`
            <div>
                <h2>我是小恐龙</h2>
                <p>真的是小恐龙</p>
            </div>`
        })
        // 2、注册组件Vue.component(注册组件的标签名,组件构造器)

        Vue.component('my_cpn',cpnC)

全局组件

按上述方法创建的就是全局组件Vue.component(’’,…)

意味着可以在多个Vue实例下使用
ps:是可以有多个vue实例,只不过常用一个

语法糖
//全局语法糖
        Vue.component('my_cpn',{
            template:`
            <div>
                <h2>我是小恐龙</h2>
                <p>真的是小恐龙</p>
            </div>`
        })

局部组件

在vue实例的components中写出
<script>
        const cpnC = Vue.extend({
            template:`
            <div>
                <h2>我是小恐龙</h2>
                <p>真的是小恐龙</p>
            </div>`
        })

        const app=new Vue({
            el:'#app',
            components:{
          //my_cpn是使用组件时的标签名
                my_cpn:cpnC
            }
        })
    </script>
语法糖
 const app=new Vue({
            el:'#app',
            components:{
                //引号加不加都可以
                'my_cpn':{
                    template:`
                    <div>
                        <h2>我是小恐龙</h2>
                        <p>真的是小恐龙</p>
                    </div>`
                }
            }
        })

组件模板分离写法

script标签类型必须是type=“text/x-template”
 <!-- 1、写在script中,用id ,注意类型:!!! type="text/x-template"-->
    <script type="text/x-template" id="cpn1">
        <div>
            <h2>我是小恐龙</h2>
            <p>真的是小恐龙</p>
        </div>
    </script>
template标签
<!-- 2、template标签 -->
    <template id="cpn2">
        <div>
            <h2>我是小恐龙</h2>
            <p>真的是小恐龙</p>
        </div>
    </template>

注册组件
 Vue.component('my_cpn',{
            template:'#cpn2'
        })

组件不能直接访问vue实例的数据

组件除了template,还有data属性,用于存放自己使用的数据;以及methods等属性
而data属性是个函数,还需要返回一个对象,对象内部中保存着数据
使得每个实例可以维护一份被返回对象的独立的拷贝

组件通信

父传子props

1、传数组,props里写{{}}中的变量
2、传对象,可以限制数据类型
3、传对象,可以限制数据类型,还能用default提供一些默认值,required+布尔值,是否是必须传入的值

要求如果type是对象或者数组时,要用default(){}工厂函数返回默认值
default(){ return []//{} }

<div id="app">
        <!-- <my_cpn v-bind:cnames="names" :csex="sex" :cmessage='message'></my_cpn> -->
        <my_cpn :csex="sex" :cmessage='message'></my_cpn>
    </div>
    <template id='cpn'>
        <div>
            <h2>{{cnames}}</h2>
            <ul>
                <li v-for='item in cnames'>{{item}}</li>
            </ul>
            <p>{{csex}}</p>
            <p>{{cmessage}}</p>
        </div>
    </template>
    <script src="js/vue.js"></script>
    <script>
        const cpn1 = Vue.extend({
            template:'#cpn',
            // 1、传数组,props里写{{}}中的变量
            // props:['cnames','csex','cmessage'],

            // 2、传对象,可以限制数据类型
            // props:{
            //     cnames:Array,
            //     csex:Array
            // },

            // 3、传对象,可以限制数据类型,还能用default提供一些默认值
            //required+布尔值,是否是必须传入的值
            props:{
                cnames:
                {
                    type:Array,
                    // default:['a','b'],
                    default(){
                        return ['a','b']
                    },
                    required:true
                },
                csex:{type:Array,default:['a','b']},
                cmessage:{type:String,default:'helloVue'}
            },
            data(){
                return {}
            }
        })

        // 有报错信息Invalid default value for prop "cnames": Props with type Object/Array must use a factory function to return the default value.
        //要求如果type是对象或者数组时,要工厂函数返回默认值

        const app=new Vue({
            el:'#app',
            data:{
                names:['royan','eddy','loudy'],
                sex:['female','male'],
                message:'Hello'
            },
            components:{
                my_cpn:cpn1
            }
        })
    </script>
驼峰表示

HTML 中的 attribute 名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名,
如果使用字符串模板,那么这个限制就不存在了
v-bind不支持驼峰,cInfo=>c-info

一般还需要在组件模板外嵌一个标签

< template>
< div>
…模板内容
< /div>
< /template>

子传父,自定义事件
子组件发射事件,用emit触发事件

父组件同v-on监听事件
父组件模板

<template id='fcpn'>
        <div>
            <my_cpn @item-click="cpnclick"></my_cpn>
        </div>
    </template>

子组件模板

<template id='cpn'>
        <div>
            <button v-for="item in categories"
            @click="btnClick(item)">{{item.name}}</button>
        </div>
    </template>

创建子组件

const cpn1 = Vue.extend({
            template:'#cpn',
            data(){
                return {
                    categories:[
                        {id:1,name:"royan",sex:'m'},
                        {id:2,name:"eddy",sex:'f'},
                        {id:3,name:"loudy",sex:'f'},
                    ]
                }
            },
            methods:{
                //子组件发射事件,用emit触发事件
						//此处触发了item-click这个自定义事件
                btnClick(item){
                    this.$emit('item-click',item)
                }
            }
        })

创建父组件

const cpn2 = Vue.extend({
            template:'#fcpn',
            components:{
                my_cpn:cpn1
            },
            methods:{
                // 父组件用v-on监听子组件事件
						//实现事件监听的内容
                cpnclick(item){
                    console.log('cpnclick',item);
                }
            }
        })

组件通信–双向绑定

<div id="app">
       <my_cpn :number1="num1" 
        :number2="num2"
        @num1changef="num1changez"
        @num2changef="num2changez"></my_cpn> 
    </div>

    <template id="cpn">
        <div>
            <h2>{{number1}}</h2>
            <h2>data:{{dnumber1}}</h2>

            <!-- <input type="text" v-model="dnumber1"> -->
            <!-- <input type="text" :value="dnumber1" @input="dnumber1=$event.target.value">、 -->

            <input type="text" :value="dnumber1" @input="num1Input">
            <h2>{{number2}}</h2>
            <h2>data:{{dnumber2}}</h2>

            <!-- <input type="text" v-model="dnumber2"> -->
            <!-- <input type="text" :value="dnumber2" @input="dnumber2=$event.target.value"> -->

            <input type="text" :value="dnumber2" @input="num2Input">

        </div>
    </template>

    <script src="js/vue.js"></script>
    <script>
       const app = new Vue({
           el:"#app",
           data:{
               num1:1,
               num2:2
           },
           components:{
               my_cpn:{
                   template:"#cpn",
                   props:{
                       number1:Number,
                       number2:Number
                   },

                   //number与dnumber仅在初始状态是一致的
                   //input变化=>dnumber变化,但number不会改变
                   data(){
                    return {
                        dnumber1:this.number1,
                        dnumber2:this.number2
                    }
                   },
                   methods:{
                       num1Input(event){
                        //    1、将input中的value赋值到dnumber中
                           this.dnumber1=event.target.value
                        //   2、为了改变input时同时修改父组件的值(让number也改变),子组件发射事件
                           this.$emit('num1changef',this.dnumber1)

                        //3、实现number2是number1的10倍
                           this.dnumber2=this.dnumber1*10
                           this.$emit('num2changef',this.dnumber2) 

                       },
                       
                       num2Input(event){
                           this.dnumber2=event.target.value
                           this.$emit('num2changef',this.dnumber2)

                           this.dnumber1=this.dnumber2/10
                           this.$emit('num1changef',this.dnumber1) 
                       },
                       
                   }
               }
           },
           methods:{
               num1changez(value){
                   this.num1=parseFloat(value)
               },
               num2changez(value){
                   this.num2=parseFloat(value)
               }
           }
       }) 
    </script>

父子组件的访问方式

父组件访问子组件$children $refs

$children
$refs

要给组件加key,通过$refs.key.属性访问

<my_cpn ref="aaa"></my_cpn>
        <!-- aaa是一个key -->
 console.log(this.$refs);//默认是空对象
                    //必须在组件上添加 ref="key"
 console.log(this.$refs.aaa);
 console.log(this.$refs.aaa.messages);

子访问父

$parent
$root访问vue实例

slot插槽

是组件预留的空间,使封装的组件具有扩展性,让使用者决定组件内部的一些展示内容
就可以在组件中嵌入其他元素
<my_cpn>< button>Click< /button></my_cpn>

slot插槽使组件可扩展

slot可以有默认值,但在使用时会被覆盖

hello

    <!-- slot插槽使组件可扩展 -->
    <div id="app">
        <my_cpn>
            <button>点击</button>
        </my_cpn>

        <my_cpn></my_cpn>
    </div>
    <template id="cpn">
        <div>
            <h2>Hi!</h2>
            <p>这是一个slot演示</p>
            <!-- slot中写入的是默认值,会被覆盖 -->
            <slot><i>check check</i></slot>
        </div>
    </template>

具名插槽

spot插槽的name属性
不指定name替换没有name属性的插槽

<!-- slot插槽使组件可扩展 -->
    <div id="app">
        <!-- 明确替换的是具体哪一个插槽 -->
        <my_cpn><button slot="s1">替换了s1</button></my_cpn>
    </div>
<template id="cpn">
        <div>
            <h2>Hi!</h2>
            <p>这是一个slot演示</p>
            <!-- slot中写入的是默认值,会被覆盖 -->
          
            <slot></slot>
            <slot name="s1"><span>s1</span></slot>
            <slot name="s2"><span>s2</span></slot>
            <slot name="s3"><span>s3</span></slot>
        </div>
    </template>

作用域插槽

父组件替换插槽的标签,但内容由子组件来提供

需求:案例中的数组定义在子组件中,需要在vue实例中用不同的格式展示
方法:插槽
问题:父组件不能直接拿到子组件的data内容
解决:1、为子组件中的插槽对象指定一个属性,用属性拿到子组件中的data内容
2、固定写法,用 < template slot-scope=“slot”></ template>

<div id="app">
        <my_cpn></my_cpn>
        <my_cpn>
          <!-- 目的是让vue实例获取子组件中的数据 -->
            <template slot-scope="slot">
                <!-- <span v-for="item in slot.data">{{item}}**</span> -->
                <span>{{slot.data.join('*')}}</span>
            </template>
        </my_cpn>
    </div>
<template id="cpn">
        <div>
            <!-- data名称可以任意,是为slot指定了一个属性,用这个属性拿到子组件中的数据 -->
            <slot :data="names">
                <ul>
                    <li v-for="item in names">{{item}}</li>
                </ul>
            </slot>
        </div>
    </template>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值