0
点赞
收藏
分享

微信扫一扫

Vue可复用性的组件详解

互联网码农 2021-09-30 阅读 61
1、组件的使用方法
  1. 全局注册
 Vue.component('my-component', {
        template: '<div>我是一个组件</div>'
    })
    var app = new Vue({
        el: '#app',
        data: {

        },
    })

优点:所有的vue实例都可以用
缺点:权限太大,容错率降低

  1. 局部注册
 var bpp = new Vue({
        el: '#bpp',
        components: {     //注意这里的components是复数
            'bpp-component': {
                template: '<div>我是bpp里面的组件</div>'
            }
        },
        data: {

        }
  1. vue组件的模板在某些情况下会受到html标签的限制,比如 <table>中只能有 <tr>, <td> 这些元素,所以直接在table中使用组件是无效的,此时可以使用is属性来挂载组件
<table>
<tbody is="my-component"></tbody>
</table>
2、组件使用的小技巧

需求:实现两个按钮各自点击能实现加1,互不影响

 <div id='app'>
    <my-component></my-component>
    <my-component></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
    var app = new Vue({
        el: '#app',
        components: {
            'my-component': {
                template: '<button @click="count++">{{count}}</button>',
                data: function () {
                    return {
                        count: 0
                    }
                }
            },
        }
    })
</script>
3、使用props传递数据(父亲向儿子传递数据)
  1. 在组件中使用props来从父亲组件接收参数,注意,在props中定义的属性,都可以在组件中直接使用
<div id='app'>
    <h5>我是父组件</h5>
    <my-component msg='我是来自父组件内容'></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
    var app = new Vue({
        el: '#app',
        components:{
            'my-component':{
                props:['msg'],
                template:'<div>{{msg}}</div>'
            }
        }
    })
</script>
  1. props来自父级,而组件中data中return的数据就是组件自己的数据,两种情况作用域就是组件本身,可以在templatecomputedmethods中直接使用。

3、可以使用v-­bind动态绑定父组件来的内容

<div id="app" style="border:1px solid red;height:150px">
    <h5>我是父组件</h5>
    <input type="text" v-model='parentmsg' style="border-bottom:10px">
    <my-component v-bind:msg="parentmsg"></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
    var app = new Vue({
        el: '#app',
        data: {
            parentmsg: '今天的太阳真热'
        },
        components: {
            'my-component': {
                props: ['msg'],
                template: '<div style="border:1px solid green;height:50px">{{msg}}</div>'
            }
        }
    })
</script>

3.props的值有两种,一种是字符串数组,一种是对象,本节先只讲数组

 <div id="app" style="border:1px solid red;height:150px">
    <h5>我是父组件</h5>
    <my-component msg=[3,6,9]></my-component>
    <my-component :msg=[3,6,9]></my-component>  //利用v-bind进行绑定
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
    var app = new Vue({
        el: '#app',
        components: {
            'my-component': {
                props: ['msg'],
                template: '<div style="border:1px solid green;height:30px">
                           {{msg}}--{{msg.length}}</div>'  
            }
        }
    })
</script>


能看出来利用v-bind进行数组数据传输和没有v-bind的区别,所以当我们进行数组数据传递时要绑定v-bind,才能确保数组长度没有发生改变。

4、单向数据流

1、解释 : 通过 props 传递数据是单向的了, 也就是父组件数据变化时会传递给子组件,但是反过来不行。
2、目的: 是尽可能将父子组件解稿,避免子组件无意中修改了父组件的状态。
3、应用场景: 业务中会经常遇到两种需要改变 prop 的情况

<div id="app">
    <my-component msg='我是父组件传递的数据'></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
    var app = new Vue({
        el: '#app',
        components: {
            'my-component': {
                props: ['msg'],
                template: '<div>{{count}}</div>',
                data: function () {
                    return {
                        //props中的值可通过this.xxx来获取
                        count: this.msg
                    }
                }
            }
        }
    })
</script>
 <div id="app">
    <input type="text" v-model="width">
    <my-component :width="width"></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
    var app = new Vue({
        el: '#app',
        data: {
            width: 0
        },
        components: {
            'my-component': {
                props: ['width'],
                template: '<div :style="style"></div>',
                computed: {
                    style: function () {
                        return {
                            width: this.width + "px",
                            height: '30px',
                            background: 'red'
                        }
                    }
                }
            }
        }
    })
</script>

5、数据验证

vue组件中的camelCased(驼峰式)命名与kebab-case(短横线命名)规则

1、验证Number类型

<div id="app">
    <my-component :a='a' ></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
    var app = new Vue({
        el: '#app',
        components: {
            'my-component': {
                props: {
                    a: Number,
                },
                template: '<div>{{a}}</div>',
            },
        },
        data: {
            a: 1,
        }
    })
</script>

2、验证String类型

<div id="app">
    <my-component :a='a' ></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
    var app = new Vue({
        el: '#app',
        components: {
            'my-component': {
                props: {
                    a: String,
                },
                template: '<div>{{a}}</div>',
            },
        },
        data: {
            a: 'abc',   
        }
    })
</script>

3、验证StringNumber类型

<div id="app">
    <my-component :a='a' ></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
    var app = new Vue({
        el: '#app',
        components: {
            'my-component': {
                props: {
                    a: [Number,String]
                },
                template: '<div>{{a}}</div>',
            },
        },
        data: {
            a: 2,   //或者改成字符串a:'qwe'都不会报错
        }
    })
</script>

4、验证Boolean类型

<div id="app">
    <my-component :a='a' ></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
    var app = new Vue({
        el: '#app',
        components: {
            'my-component': {
                props: {
                    a: {
                        type:Boolean,
                        default:true,  //布尔值,如果没有定义,默认值就是 true
                     },
                },
                template: '<div>{{a}}</div>',
            },
        },
        data: {
            a: true,
        }
    })
</script>

5、验证Number类型是必传的

<div id="app">
    <my-component :a='a' ></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
    var app = new Vue({
        el: '#app',
        components: {
            'my-component': {
                props: {
                    a: {
                        type:Number,
                        required:true,
                     },
                },
                template: '<div>{{a}}</div>',
            },
        },
        data: {
            a: 111,
        }
    })
</script>

6、验证Array类型

<div id="app">
    <my-component :a='a' ></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
    var app = new Vue({
        el: '#app',
        components: {
            'my-component': {
                props: {
                    a: {
                        type:Array,
                        default:function(){
                            return [555]   //默认为数值[555]
                        }
                     },
                },
                template: '<div>{{a}}</div>',
            },
        },
        data: {
            a: [444],
        }
    })
</script>

7、验证Function类型

<div id="app">
    <my-component :a='a' ></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
    var app = new Vue({
        el: '#app',
        components: {
            'my-component': {
                props: {
                    a: {
                        type:Function,
                     },
                },
                template: '<div>{{a}}</div>',
            },
        },
        data: {
            a: console.log(),
        }
    })
</script>

8、自定义一个验证函数

<div id="app">
    <my-component :a='a' ></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
    var app = new Vue({
        el: '#app',
        components: {
            'my-component': {
                props: {
                    a: {
                     validator:function(value){     //validator验证器名字
                             return value>22
                      }
                     },
                },
                template: '<div>{{a}}</div>',
            },
        },
        data: {
            a: 33,
        }
    })
</script>
6、组件通信

组件关系可分为父子组件通信、兄弟组件通信、跨级组件通信

6.1 自定义事件—子组件给父组件传递数据

使用v­-on 除了监昕 DOM 事件外,还可以用于组件之间的自定义事件。JavaScript 的设计模式--观察者模式, dispatchEventaddEventListener这两个方法。 Vue 组件也有与之类似的一套模式,子组件用$emit()来触发事件,父组件用$on()来监昕子组件的事件 。

<!-- 需求:通过加、减按钮实现子组件给父组件传递数据 -->
<div id="app">
    你现在的总余额是{{total}}元
    <son-component @change='handleTotal'></son-component> //change是自定义事件
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
    var app = new Vue({
        el: '#app',
        components: {
            'son-component': {
                template: '<div>\
                        <button @click=handleincrease>+</button>\
                        <button @click=handleruduce>-</button>\
                           </div>',
                data: function () {
                    return {
                        count: 1000
                    }
                },
                methods: {
                    handleincrease: function () {
                        this.count = this.count + 1000,
                            this.$emit('change', this.count)
                    },
                    handleruduce: function () {
                        this.count = this.count - 1000,
                            this.$emit('change', this.count)
                    }
                }
            },
        },
        data: {
            total: 1000,
        },
        methods: {
            handleTotal: function (value) {
                this.total = value
            }
        }
    })
</script>
6.2 在组件中使用v­-model

对比6.1中的例子使用v-model实现需求

<!-- 需求:通过加、减按钮实现子组件给父组件传递数据 -->
<div id="app">
    你现在的总余额是{{total}}元
    <son-component v-model='total'></son-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
    var app = new Vue({
        el: '#app',
        components: {
            'son-component': {
                template: '<div>\
                        <button @click=handleincrease>+</button>\
                        <button @click=handleruduce>-</button>\
                           </div>',
                data: function () {
                    return {
                        count: 1000
                    }
                },
                methods: {
                    handleincrease: function () {
                        this.count = this.count + 1000,
                            this.$emit('input', this.count)
                    },
                    handleruduce: function () {
                        this.count = this.count - 1000,
                            this.$emit('input', this.count)
                    }
                }
            },
        },
        data: {
            total: 1000,
        },
    })
</script>
6.3 非父组件之间的通信

有时候两个组件也需要通信(非父组件),在简单的场景下,可以使用空的Vue实例作为中央事件总线进行。

1

var bus=new Vue()

2

//触发组件A中的事件
bus.$emit('id-selected',2)

3

//在组件B创建的钩子中监听事件
bus.$on('id-selected',function(){
     .....
})

1、点击a组件向b组件传递数据(非父组件)

<div id="app">
    <my-acomponent></my-acomponent>
    <my-bcomponent></my-bcomponent>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
    Vue.component('my-acomponent',{
        template:'<div><button @click="handle">点我向b组件传递数据</button></div>',
        data:function(){
            return{
                a:'我是来自a组件内容'
            }
        },
       methods:{
           handle:function(){
               this.$root.bus.$emit('lalala',this.a)
           }
       }
    })
    Vue.component('my-bcomponent',{
        template:'<div></div>',
        created:function( ){
           this.$root.bus.$on('lalala',function(value){
                alert(value)
           })
        }
    })
    var app = new Vue({
        el: '#app',
        data: {
          bus:new Vue(),
        },
    })
</script>

注意:这里通过this.$root访问是根父组件的内容,而通过this.parent访问的事最近一级父组件内容

2、点击子组件按钮修改父组件内容

<div id="app">
    <my-acomponent></my-acomponent>
    {{msg}}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
    Vue.component('my-acomponent',{
        template:'<div><button @click="handle">点击我修改父亲的数据</button></div>',
       methods:{
           handle:function(){
               this.$parent.msg='数据已修改'
           }
       }
    })
    var app = new Vue({
        el: '#app',
        data: {
          msg:'数据未修改',
        },
    })
</script>

注意:这里通过this.parent访问的事最近一级父组件内容

3、在父组件中拿到子组件的数据
Vue提供了为子组件提供索引的方法,用特殊的属性ref为其增加一个索引

<div id="app">
    <my-acomponent ref='a'></my-acomponent>
    <my-bcomponent ref='b'></my-bcomponent>
    <button @click='getchilddata'>点击我拿到子组件的数据</button>
    {{formchild}}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
    Vue.component('my-acomponent',{
        template:'<div></div>',
        data:function(){
            return{
                msg:'我是a中的msg'
            }
        },
    })
    Vue.component('my-bcomponent',{
        template:'<div></div>',
        data:function(){
            return{
                msg:'我是b中的msg'
            }
        },
    })
    var app = new Vue({
        el: '#app',
        data: {
          formchild:'还未拿到数据'
        },
        methods:{
           getchilddata:function(){
               this.formchild=this.$refs.a.msg   //注意这里是refs不是ref
           }
        }
    })
</script>

注意:如果父组件有多个子组件不能通过this.$child来获取子组件内容,而是通过给子组件添加索引,通过this.refs获取

7、使用slot分发内容
7.1、什么是slot(插槽)
7.2、 编译的作用域

在深入内容分发 API 之前,我们先明确内容在哪个作用域里编译。假定模板为:

<child-component>
{{ message }}
</child-component>

message 应该绑定到父组件的数据,还是绑定到子组件的数据?答案是父组件。

7.3 、插槽的用法

父组件的内容与子组件相混合,从而弥补了视图的不足

1、单个插槽:

<div id="app">
    <my-component>
       <p>我是父组件的内容</p>     //这是父组件插入的内容
    </my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
    Vue.component('my-component',{
        template:'<div>\
                     <slot>\
                     如果父组件没有插入内容,我就作为默认值出现\
                     </slot>\
                  </div>',
    })
    var app = new Vue({
        el: '#app',
        data: {},
    })
</script>

2、具名插槽

 <div id="app">
    <my-component>
       <h3 slot=header>标题</h3>    //标记
       <p>内容</p>
       <p slot=footer>结尾</p>
    </my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
    Vue.component('my-component', {
            template: '<div>\
                          <div class="header">\
                              <slot name="header">\    //关联
                              </slot>\
                          </div>\
                          <div class="container">\
                              <slot>\
                              </slot>\
                          </div>\
                          <div class="footer">\
                               <slot name="footer">\
                               </slot>\
                          </div>\
                       </div> ',
        })
    var app = new Vue({
        el: '#app',
        data: {},
    })
</script>
7.4 、作用域插槽

作用域插槽是一种特殊的slot,使用一个可以复用的模板来替换已经渲染的元素
------从子组件获取数据
------template模板是不会被渲染的

<div id="app">
    <my-component>
      <template slot="abc" slot-scope="prop">
          {{prop.text}}
          {{prop.ss}}    //子组件中的name中数据是关联用得,不能通过这样获取
      </template>>
    </my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
    Vue.component('my-component', {
            template: '<div>\
                         <slot text="我是子组件的数据" ss="sdfsd" name="abc">\
                         </slot>\
                       </div> ',
        })
    var app = new Vue({
        el: '#app',
        data: {},
    })
</script>
7.5、 访问slot

通过this.$slots.(NAME)

 <div id="app">
            <my-component>
               <h3 slot=header>标题</h3>   
               <p slot=footer>结尾</p>
            </my-component>
        </div>
        <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
        <script>
            Vue.component('my-component', {
                    template: '<div>\
                                  <div class="header">\
                                      <slot name="header">\
                                      </slot>\
                                  </div>\
                                  <div class="footer">\
                                       <slot name="footer">\
                                       </slot>\
                                  </div>\
                               </div> ',
                    mounted:function(){
                        var header=this.$slots.header
                        var text=header[0].elm.innerText  //由DOM结构得来
                        console.log(header)  //查看DOM结构
                        console.log(text)
                    }
                })
            var app = new Vue({
                el: '#app',
                data: {},
            })
        </script>
7.6、 组件高级用法–动态组件

1、需求:通过点击不同按钮切换不同视图

 <div id="app">
         <component :is=thisview></component>
         <button @click="handleview('A')">第一句</button>
         <button @click="handleview('B')">第二句</button>
        </div>
        <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
        <script>
            Vue.component('compA', {
                 template:'<div>山不在高<div>'
                })
                Vue.component('compB', {
                 template:'<div>有仙则名<div>'
                })
            var app = new Vue({
                el: '#app',
                data: {
                    thisview:'compA',
                },
                methods:{
                    handleview:function(tag){
                           this.thisview='comp'+tag
                    }
                }
            })
        </script>
举报

相关推荐

0 条评论