vue 学习笔记(三)

一、如何使用组件
1.全局注册一个组件

Vue.component('my-component',{
    template:'<div>这是一个组件</div>'
});
// 注: 全局组件在任何实例中都可以使用。要在实例中使用全局组件,必须在初始化根实例之前注册组件,否则会报错。

2.注册一个局部组件

/**html**/
<div id='app1'>
    <my-component></my-component>
</div>
// js
var app1 = new Vue({
    el: '#app1',
    data: {
        msg: 'app1的内容'
    },
    components: {
        'my-component': {
            template: "<div>这是一个局部组件</div>"
        }
    }
});
//注:局部注册的组件只能在其实例中使用,当全局组件与实例组件重名时,会优先使用局部组件。

3.组件的data选项必须是一个函数
当一个组件被定义,data必须声明为一个初始数据对象的函数,因为组件可能用来创建多个实例。如果data仍然是一个纯粹的对象,则所有的实例将共享引用同一个数据对象。通过提供data函数,每次创建一个新实例后,我们能够调用data函数,从而返回初始数据的一个全新副本数据对象。如:

<div id="example1">
  <simple-counter></simple-counter>
  <simple-counter></simple-counter>
  <simple-counter></simple-counter>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script>
var data = { counter: 0 }

Vue.component('simple-counter', {
  template: '<button v-on:click="counter += 1">{{ counter }}</button>',
  // 技术上 data 的确是一个函数了,因此 Vue 不会警告,
  // 但是我们却给每个组件实例返回了同一个对象的引用
  data: function () {
    return data
  }
})

new Vue({
  el: '#example1'
})
</script>

// 这时点击 button ,每个按钮的 counter 都是一样的,因为三个组件实例共享了同一个 data 对象,因此递增一个 counter 会影响所有组件。
修改一下: 可以通过为每个组件返回全新的数据对象来修复这个问题,每个counter组件都有自己的状态。

二、组件组合
组件最常见的关系就是父子组件关系:组件A在其模板中使用了组件B,它们之间必然需要相互通信:父组件给子组件下发数据,子组件则将内部的事件告知父组件
Vue中,父子组件的关系总结为:父组件通过prop向子组件传递数据,子组件通过事件向父组件发送消息。
1.使用prop传递数据

//组件的作用域不是孤立的,不能再子组件模块内直接使用父组件的数据,父组件的数据需要通过prop才能下发到子组件中。
// 子组件要显示地使用prop选项声明他预期的数据
<div id="example1">
    <!--给子组件传递了一个字符串-->
    <child message='hello world'></child>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script>
    Vue.component('child',{
        props:['message'],//子组件预期希望的数据
        template:'<span>{{message}}</span>'
    });
    var example1 = new Vue({
        el: '#example1'
    });
</script>

2.prop命名
a.camelCase(驼峰式) b. kebab-case(短线分割式)

// html特性是不区分大小写的。所以camelCase(驼峰式命名)的prop需要转换为相对应的kebab-case(短线分割式命名)。
<div id="example1">
    <!-- messageMsg需要转化为message-Msg -->
    <child message-Msg='hello world'></child>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script>
    Vue.component('child',{
        props:['messageMsg'],
        template:'<span>{{messageMsg}}</span>'
    });
    var example1 = new Vue({
        el: '#example1'
    });
</script>
// 注:对于字符串模板,没有这个限制

3.动态prop
a.prop静态的传值

<blog-post title="My journey with Vue"></blog-post>
b.prop动态传值 与绑定到任何普通的html特性相类似,可以用v-bind来动态的将prop绑定到父组件的数据。每当父组件的数据变化时,该变化也会传递给子组件。
<div id="example1">
    <input type="text" v-model="msg" />
    <child v-bind:message-Msg='msg'></child>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script>
            Vue.component('child',{
                props:['messageMsg'],
                template:'<span>{{messageMsg}}</span>'
            });
            var example1 = new Vue({
                el: '#example1',
                data: {
                    msg: '动态的数据'
                }
            });
</script>

4.字面量语法 vs 动态语法
要传递javascript表达式,而不是字符串时,需要动态语法 v-bind,prop可以接受任何类型的值。
a.传入一个数字

<!-- 即便 `42` 是静态的,我们仍然需要 `v-bind` 来告诉 Vue -->
<!-- 这是一个 JavaScript 表达式而不是一个字符串。-->
<blog-post v-bind:likes="42"></blog-post>
<!-- 用一个变量进行动态赋值。-->
<blog-post v-bind:likes="post.likes"></blog-post>

b.传入一个布尔值

<!-- 包含该 prop 没有值的情况在内,都意味着 `true`。-->
<blog-post favorited></blog-post>
<base-input v-bind:favorited="false">
<base-input v-bind:favorited="post.currentUserFavorited">

c. 传入一个数组

<blog-post v-bind:comment-ids="[234, 266, 273]"></blog-post>
<blog-post v-bind:comment-ids="post.commentIds"></blog-post>

d.传入一个对象

<blog-post v-bind:comments="{ id: 1, title: 'My Journey with Vue' }"></blog-post>
<blog-post v-bind:post="post"></blog-post>

e. 传入一个对象的所有属性

<div id="parent">
    <Asyncexample v-bind="post"></Asyncexample>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script>
            Vue.component('Asyncexample',{
                props:['id','title'],
                template: '<div>{{id}}<div>{{title}}</div></div>'
            });
            var parent = new Vue({
                    el: '#parent',
                    data: {
                        bool:false,
                        post:{
                            id:1,
                            title:'hello world'
                        }
                    }
            });

</script>

5.单向数据流
prop是单向绑定的:当父组件属性变化时,将传导到子组件,但反过来不会。这是为了防止组件无意间修改了父组件的状态,避免应用的数据难以理解。
每次父组件更新时,子组件的所有prop都会更新为最新值,这意味不应该在子组件内部改变prop,如果做了,vue会在控制台发出警告。
有两种情况很容易去修改prop的数据
(1)prop作为初始值传入后,子组件想把它作为局部数据来用

<div id="example1">
        <child v-bind:order='num'></child>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script>
            Vue.component('child',{
                props:['order'],
                template:'<input v-model="order">',//如果直接在页面input修改数据,控制台会报错,提示避免直接修改prop,父组件更新时会覆盖修改的数据
                data: function () {
                  return {

                  }
                }
            });
            var example1 = new Vue({
                el: '#example1',
                data: {
                    num: 100
                }
            });
</script>
// 正确的应对方法是:定义一个局部变量,并用prop的值初始化它:
// 修改为:
<div id="example1">
    <child v-bind:order='num'></child>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script>
            Vue.component('child',{
                props:['order'],
                template:'<input v-model="counter">',
                data: function () {
                  return {
                     counter: this.order  //把prop的值赋给counter,此时修改input的值就不会报错了  
                  }
                }
            });
            var example1 = new Vue({
                el: '#example1',
                data: {
                    num: 100
                }
            });
</script>

(2)prop作为原始数据传入后,由子组件处理成其他数据输出:

// 正确的做法是:定义一个计算属性,处理prop的值并返回
<div id="example1">
    <child v-bind:message='msg'></child>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script>
            Vue.component('child',{
                props:['message'],
                template:'<span>{{format}}</span>',
                computed: {
                    format: function () {
                      return  this.message.toLowerCase()
                    }
                }
            });
            var example1 = new Vue({
                el: '#example1',
                data: {
                    msg: 'HELLO,WORLD'
                }
            });
</script>
// 注:在javascript中对象和数组是通过引用传递的,所以对于一个数组或者对象类型的prop来说,
// 在子组件中改变对象或者数组本身,将会影响到父组件的状态。

6.prop验证
组件的prop可以指定验证规则,如果传入组件的数据不符合要求,vue会抛出警告
要指定验证规则,需要用对象的形式来定义prop,而不能用字符串数组。

<div id="example1">
    <child v-bind:order='num'></child>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script>
        Vue.component('child', {
             props: {
                     'order': {// 自定义验证函数
                         validator: function(value) {
                             if(value == 1){
                                 console.log('验证成功');
                                 this.order = '第一名';//修改不起作用,因为 prop 会在组件实例创建之前进行校验
                                 return  true
                             }
                         }
                     }
//                      'order':{
//                          type: Number,
//                          default: 100
//                      }
//                      propNameA: Number,// 基础类型检测 (null指允许任何类型)                       
//                      propNameB: [String, Number],// 可能是多种类型                      
//                      propNameC: {// 必传且是字符串
//                          type: String,
//                          required: true
//                      },                      
//                      propNameD: {// 数值且有默认值
//                          type: Number,
//                          default: 100
//                      },                      
//                      propNameE: {//  数组/对象的默认值应当由一个工厂函数返回
//                          type: Object,
//                          default: function() {
//                              return {
//                                  message: 'hello'
//                              }
//                          }
//                      },                  
             },
             template: '<span>排序:{{order}}</span>',
         });
         var example1 = new Vue({
             el: '#example1',
             data: {
                 num:1
             }
         });
 // prop 的类型type可以是原生构造器,string,number,Boolean,function,object,array,symbol
 // 注:prop会在组件实例创建之前进行校验,所以字default或validator函数里,诸如data,computed,或methods等实例属性还无法使用。        
</script>

猜你喜欢

转载自blog.csdn.net/cxz792116/article/details/80760321