Vue.js组件简介及组件通信(1)

这是我参与更文挑战的第1天,活动详情查看: 更文挑战

组件简介

  • 组件用于封装页面的部分功能,将功能的结构、样式、逻辑代码封装为整体。
  • 提高功能的复用性与可维护性,更好的专注于业务逻辑。
  • 组件使用时为自定义HTML标签形式,通过组件名作为自定义标签名。

组件注册

全局注册

  • 全局注册的组件在注册后可以用于任意实例或组件中。
  • 注意:全局注册必须设置在根Vue实例创建之前

组件基础

  • 本质上,组件是可复用的Vue实例所以它们可与new Vue接收相同的选项,例如data、methods以及生命周期钩子等。
  • 仅有的例外是:el是根实例特有的选项,组件不具有。

组件命名规则

  • 组件具有两种命名规则:
    • kebab-case:’my-component’
    • PascalCase:’MyComponent’
  • 注意:无论采用哪种命名方式,在DOM中都只有 kebab-case可以使用。

template选项

  • 用于设置组件的结构,最终被引入根实例或其他组件中。
Vue.component('MyComponentA',{
    template:`
    <div>
        <h3>组件A的标题内容</h3>
    </div>
    `
});
复制代码
  • 注意:组件必须只有一个根元素。像下面代码这样书写,就会出错。
Vue.component('MyComponentA',{
    template:`
    <div>
        <h3>组件A的标题内容</h3>
    </div>
    <div>
        <h3>组件A的另一个标题内容</h3>
    </div>
    `
});
复制代码

data选项

  • data选项用于存储组件的数据,与根实例不同,组件的data选项必须为函数,数据设置在返回对象中。
  • 这种实现方式是为了确保每个组件实例可以维护一份被返回对象的独立的拷贝,不会相互影响。
// 创建Vue的组件
Vue.component('MyComA',{
    template:`
    <div>
        <h3>{{title}}</h3>
    </div>
    `,
    data:function(){
        return {
            title:'新的内容'
        }
    }
});
复制代码

局部注册

  • 局部注册的组件只能用在当前实例或组件中。
new Vue({
    el:'#app',
    // 局部注册
    components:{
        'my-component-a':{
            template:`<h3>{{title}}</h3>`,
            data(){
                return {
                    title:'a组件示例内容'
                }
            }
        }
    }
});
复制代码

局部注册的其他写法

  • 单独配置组件的选项对象
var MyComponentA = {
    template:`
    <p>{{title}}</p>
    `,
    data() {
        return {
            title:'HelloA'
        }
    }
};
var MyComponentB = {
    template:`
    <p>{{title}}</p>
    `,
    data() {
        return {
            title:'HelloB'
        }
    }
};
new Vue({
    el:'#app',
    // 局部注册
    components:{
        // 'my-component-a':{
        //     template:`<h3>{{title}}</h3>`,
        //     data(){
        //         return {
        //             title:'a组件示例内容'
        //         }
        //     }
        // }
        'my-component-a':MyComponentA,
        'my-component-b':MyComponentB
    }
});
复制代码
  • ES6的对象属性简写
new Vue({
    el:'#app',
    components:{
        MyComponentA,
        MyComponentB
    }
});
复制代码

组件通信

  • 问题
    • 子组件如何获取父组件中的数据?
    • 父组件如何得知子组件的数据变更?
  • 在组件间传递数据的操作,称为组件通信。

父组件向子组件传值

  • 通过子组件的props选项接收父组件的传值。
<body>
    <div id="app">
        <my-component-a :child-title = "title"></my-component-a>
    </div>
    <script src="lib/vue.js"></script>
    <script>
        // 子组件
        Vue.component('MyComponentA',{
            // 接收父组件的值
            props:['childTitle'],
            template:`
            <div>
                <p>{{titleB}}</p>
            </div>
            `,
            data() {
                return {
                    titleB:this.childTitle+' 子组件成功接收!'
                }
            }
        });
        // 父组件
        new Vue({
            el:'#app',
            data:{
                title:'父组件的标题'
            }
        });
    </script>
</body>
复制代码
  • 注意:props不要与data存在同名属性
    • 如果希望在子组件中更改、处理父组件传递给我们的数据
    • 应该通过data做存储或通过计算属性的一个功能进行设置
  • 在子组件上写的属性,会直接添加到子组件的根标签上。

Props命名规则

  • 建议prop命名使用camelCase,父组件绑定时使用kebab-case
<!-- 父组件绑定   child-title-->
<my-component-a :child-title = "title"></my-component-a>
复制代码
// 子组件接收  childTitle
<script>
        Vue.component('MyComponentA',{
            // 接收父组件的值
            props:['childTitle']
            .....
        }
</script>
复制代码

练习(父组件向子组件传值练习)

  • 通过v-for创建组件
<body>
    <div id="app">
        <my-component-a v-for="good in goods"
                        :key = "good.id" 
                        :name = "good.name"></my-component-a>
    </div>
    <script src="lib/vue.js"></script>
    <script>
        // 子组件
        Vue.component('MyComponentA',{
            props:['name'],
            template:`
            <p>{{goodName}}</p>
            `,
            data() {
                return {
                    goodName:this.name
                }
            }
        });
        // 通过v-for创建组件 练习
        // 父组件
        new Vue({
            el:'#app',
            data:{
                goods:[{id:1,name:'梨子'},
                       {id:2,name:'草莓'},
                       {id:3,name:'香蕉'}
                      ]
            }
        });
    </script>
</body>
复制代码
  • 总结:props中的名字,需要和子组件绑定的名称相同

父组件向子组件传值props值名称.png

单向数据流

  • 父子组件间的所有prop都是单向下行绑定的。
  • 如果子组件要处理prop数据,应当存储在data中再操作。
  • 注意:如果prop为数组或对象时,子组件操作将会影响到父组件的状态。因此,避免将数组或对象整体进行传递,可拆分传递。
<!-- 整体传递,会修改父组件中的内容 -->
<body>
    <div id="app">
        <!-- 子组件 -->
        <my-com :user='user'></my-com>
    </div>
    <script src="lib/vue.js"></script>
    <script>
        // 创建子组件
        Vue.component('MyCom',{
            props:['user'],
            template:`
                <div>
                    <p>{{user.name}}</p>
                </div>
            `,data(){
                return {
                    users:this.user
                }
            }
        });
        // 创建根实例
        new Vue({
            el:'#app',
            data:{
                user:{
                    name:'张三',
                    hobby:'弹琴,看书,练瑜伽'
                }
            }
        });
    </script>
</body>
复制代码

Props类型

  • Prop可以设置类型检查,这时需要将props更改为一个带有验证需求的对象,并指定对应类型。(不按照规定类型来传值,Vue会警告warn⚠)
  • 注意:null和undefined都可以存储任意值
  • prop可以同时指定多个类型,通过数组方式保存即可。
// 创建子组件
Vue.component('MyCom',{
    props:{
        parStr:[String,Array],
        parArr:Array,
        parBool:Boolean,
        parAny:undefined
    },
    template:`
        <div>
            {{parStr}}
            {{parArr}}
            {{parBool}}
            {{parAny}}
        </div>
    `
});
复制代码

Props验证

  • 当prop需要设置多种规则时,可以将prop的值设置为选项对象
  • 1.之前的类型检测功能通过type选项设置。
  • 2.required用于设置数据为必填项
  • 3.default用于给可选项指定默认值,当父组件未传递数据时生效。
<div id="app">
<!-- 不传arr给子组件,就会警告 -->
<my-com :par-str='str'
        :par-bool='bool'
        :par-any='any'
        ></my-com>
</div>
复制代码
// 创建子组件
Vue.component('MyCom',{
    props:{
        // 通过type进行类型检测(Vue警告)
        parStr:{
            type:[String,Array]
        },
        // 原本的类型检测方式(Vue警告)
        parArr:{
            type:Array,
            required:true
        },
        parBool:{
            type:Boolean,
            default:true
        },
        parAny:undefined
    },
    template:`
        <div>
            {{parStr}}
            {{parArr}}
            {{parBool}}
            {{parAny}}
        </div>
    `
});
复制代码
  • 注意:当默认值为数组或对象时,必须为工厂函数返回的形式。
props:{
  // 通过type进行类型检测(Vue警告)
  parStr:{
      type:[String,Array,Object],
      default:function(){
          return [1,67,34,2];
      }
    }
  }
复制代码
  • validator用于给传入的prop设置校验函数,return值为false时Vue.js会发出警告。
parStr:{
    type:String,
    // 验证函数
    validator:function(val){
        return val.startsWith('swun');
    }
}
复制代码
  • 注意:验证函数中无法使用实例的data、methods等功能。
    • 因为prop的验证功能是在实例创建完成之前,做的验证。所以组件的实例还没有创建完成,没法使用data\methods这些内容(即:并不能通过this访问其他的,此时的this为window)。

非Props属性

  • 当父组件给子组件设置了属性,但此属性在prop中不存在,这时会自动绑定到子组件的根元素上。
  • 如果组件根元素已经存在了对应属性,则会替换组件内部的值。
  • class与style是例外,当内外都设置时,属性会自动合并。
  • 如果不希望继承父组件继承的属性,可以设置inheritArrts:false,但只适用于普通属性,class与style不受影响。
<div id="app">
    <my-com
        demo-attr='示例属性'
        title="示例title"
        style="height: 200px;"
        class="colorBlue"
    ></my-com>
</div>
复制代码
// 创建子组件
Vue.component('myCom',{
    inheritAttrs:false,
    template:`
        <div title='模板标题' class="zj" style="width:100px;">子组件内容</div>
    `
});
 // 创建根实例
new Vue({
    el:'#app'
});
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享