组件化开发

2020-03-05  本文已影响0人  zhchhhemmm

组件化开发思想

组件的注册方式

Vue.component(组件名称,{
       data:组件数据,
       template:组件模板内容
  })

一个具体组件:
      Vue.component('button-counter',{
            data:function(){
                return{
                    count:0
                }
            },
            template:'<button @click="count++" >按钮被点击{{count}}次</button>'
        })

组件是可以重用的,重用的每个组件是相互独立的,他们之间的数据是相互不影响的

注意事项:
1 自定义组件的data必须是一个函数,而Vue实例的data可以是个对象
2 组件内部的模板根元素只应该有一个
3 组件模板内容可以是模板字符串
eg:

template:`
                <button @click='count++'>
                    按钮被点击{{count}}次
                </button>
            `

4 组件的命名方式有短横线方式和驼峰命名方式
如果组件要在别的组件中使用,可以直接按照命名的写法用
如果要在html中直接使用,在命名时无论用的哪种方法,使用时都得时短横线方式

//注册一个Vue实例中的局部组件
        var ComponentA = {
            data:function(){
                return {

                }
            },
            template:``
        }
        var vm = new Vue({
            el:'#box',
            components:{
                'component-a':ComponentA
            }
        })

组件之间数据的交互

<body>
    <div id="box">
        <div :style='{fontSize:fontSize+"px"}'>{{msg}}</div>
        <button-son @enlarge-text='handle'></button-son>
    </div>
        <script>
        Vue.component('button-son',{
            template:`
                <button @click='$emit("enlarge-text")'>扩大父组件的字体大小</button>
            `
        })
        var vm = new Vue({
            el:'#box',
            data() {
                return {
                    msg:'Hello world',
                    fontSize:13
                }
            },
            methods: {
                handle:function(){
                    //扩大字体大小
                    this.fontSize ++;
                    console.log(this.fontSize);
                    
                }
            },
        })
        </script>
    
</body>

-- 传值:在emit时传递的第一个参数是自定义事件名,而第二个参数则可以用来传递值,在父组件中用$event来接收值

子组件:
<button @click='$emit("enlarge-text",2)'>扩大父组件的字体大小</button>
父组件:
<button-son @enlarge-text='handle($event)'></button-son>
-- 单独的事件中心管理组件间的通信
var eventBus = new Vue();
-- 监听事件与销毁事件
eventBus.$on('add-todo',addtodo);
eventBus.$off('add-todo')
-- 触发事件
eventBus.$emit('add-todo',id)
image.png

实例:在一个父组件中有两个子组件,都是button和data,点击第一个子组件的button,第二个子组件的data改变,点击第二个子组件的button,第一个子组件的data改变。

<body>
    <div id="box">
        <p>father</p>
        <button v-on:click='handle'>销毁事件</button>
        <button-a></button-a>
        <button-b></button-b>
    </div>
    <script>
        //事件中心
        var eventBus = new Vue()

        Vue.component('button-a',{
            data:function(){
                return {
                    msg:0
                }
            },
            template:`
            <div>   
                <div>A:{{msg}}</div>
                <button @click='handle'>给老弟加2</button>
            </div> 
            `,
            methods: {
                handle:function(){
                    eventBus.$emit('b-event',2)
                }
            },
            mounted() {
                //监听事件
                eventBus.$on('a-event',(val)=>{
                    this.msg += val
                })
            },
        })
        Vue.component('button-b',{
            data:function(){
                return {
                    msg:0
                }
            },
            template:`
            <div>
                <div>B:{{msg}}</div>
                <button @click='handle'>给老哥加3</button>
            </div>
            `,
            methods: {
                handle:function(){
                    //触发兄弟组件的事件
                    eventBus.$emit('a-event',3)
                }
            },
            mounted() {
                //监听事件
                eventBus.$on('b-event',(val)=>{
                    this.msg += val
                })
            },
        })
        var vm = new Vue({
            el:'#box',
            data:{

            },
            methods: {
                handle:function(){
                    eventBus.$off('a-event')
                    eventBus.$off('b-event')
                }
            },
        })
    </script>
</body>

组件插槽的用法

在之前的自定义组件中,我们在使用的时候都是没有具体值的,比如:

<a-button><a-button>

可如果我们想要这样使用呢?:

<a-button>click me</a-button>

这时候,我们要使用插槽
我们在模板字符串中定义组件的dom时,可以预留<slot></slot>,
在使用组件时输入的值就在slot中
eg:

        <my-com>I don't know...</my-com>
...
        Vue.component('my-com',{
            template:`
            <div>   
                <strong>Error : </strong>
                <slot></slot>
            </div> 
            `
        })

-- 具名插槽
定义方法:

template:`
          <div>   
              <div>
              <slot name='header'></slot>
              </div>
              <strong>Error : </strong>
              <div><slot></slot></div>
              <div>
              <slot name='footer'></slot>    
              </div>
          </div> 
          `

使用:

<my-com>
            <div slot="header">标题信息</div>
            I don't know...
            <div slot="footer">底部信息</div>
 </my-com>

给了name的插槽对号入座,没有给name的,放入默认插槽中

-- 作用域插槽:
应用场景:父组件可以对子组件的内容进行加工处理
例子:子组件是个水果列表,但是高亮内容和文本内容应该是动态的

        <fruit-list v-bind:list='list'>
            <template slot-scope="slotProps">
                <strong v-if='slotProps.info.id==2' class="orange">{{slotProps.info.name}}</strong>
                <span v-else>{{slotProps.info.name}}</span>
            </template>
        </fruit-list>
//组件定义
        Vue.component('fruit-list',{
            props:['list'],
            
            template:`
                <div>
                    <li :key='item.id' v-for='item in list'>
                        <slot :info='item'>{{item.name}}</slot>    
                    </li>                        
                </div>
            `
        })

Vue组件调试工具的用法

组件在浏览器中会被渲染成原始的DOM,我们在浏览器的检查工具上只能看到已经渲染好了的DOM,不便于调试
官方调试工具,dev-tools,直接下载安装chrome插件即可
https://github.com/vuejs/vue-devtools

基于组件方式实现业务功能

一个小例子:

<body>
    <script>
        /*
        1 组件化划分「
                    1.标题组件(展示文本)
                    2.列表组件(列表展示、商品数量变更、商品删除)
                    3.结算组件(计算商品总额)
                    」
        
        */
    </script>
    <div id="box">
        <div id="containner">
            <my-cart></my-cart>
        </div>
    </div>
    <script>
        var cartTitle = {
            props:['uname'],
            template:`
            <div class='title'>{{uname}}的商品</div>
            `
        }
        var list = {
            props:['list'],
            template:`
                <div>
                    <div :key=item.id  v-for='item in list'>
                        <img :src="item.img" alt="">
                        <div>{{item.name}}</div>
                        <div class='change'>
                            <a class='a' href="" @click.prevent='sub(item.id)'>-</a>    
                            <input type="text" class='num' :value='item.num' @blur='changeNum(item.id,$event)'/>    
                            <a class='a' href="" @click.prevent='add(item.id)'>+</a>    
                            <button class='delete' @click='del(item.id)'>✖️</button>
                        </div>
                        
                    </div>    
                </div>
            `,
            methods: {
                changeNum:function(id,event){
                    this.$emit('numChange',{id:id,num:parseInt( event.target.value),type:'change'})
                    //console.log(id,parseInt( event.target.value));
                    //新的值是event.target.value
                },
                del:function(id){
                    this.$emit('cart-del',id)
                },
                sub:function(id){
                    this.$emit('numChange',{
                        id:id,
                        type:'sub'
                    })
                },
                add:function(id){
                    this.$emit('numChange',{
                        id:id,
                        type:'add'
                    })
                }
            },
        }
        var totol = {
            props:['list'],
            template:`
            <div class='totol'>
                <span>{{result}}</span>    
                <button>结算</button>
            </div>
            `,
            computed: {
                result:function(){
                    var totolNum = 0;
                for(var i = 0;i<this.list.length;i++){
                    totolNum += this.list[i].num * this.list[i].price;                   
                }
                // console.log(this.list.length);
                // console.log(totolNum);
                
                return totolNum;
                }
            }
        }
        Vue.component('my-cart',{
            data:function(){
                return{
                    list:[
                    {id:1,name:'tcl',img:'',num:1,price:100},
                    {id:2,name:'tl',img:'',num:1,price:1100},
                    {id:3,name:'tfel',img:'',num:1,price:1200},
                    {id:4,name:'gdgmkll',img:'',num:1,price:1400},
                    {id:5,name:'fghl',img:'',num:2,price:1900}
                ],
                uname:'sam'
                }
            },
            template:`
                <div class='cart'>
                    <cart-title :uname='uname'></cart-title>    
                    <cart-list :list='list' @numChange='changeNum($event)' @cart-del='delCart($event)'></cart-list>
                    <cart-totol :list='list'></cart-totol>
                </div>
            `,
            components:{
                'cart-title':cartTitle,
                'cart-list':list,
                'cart-totol':totol
            },
            methods:{
                delCart:function(id){
                    console.log(id);
                    //根据ID删除list中对应的数据
                    //1 根据id找到需要删除的数据的索引
                    var index = this.list.findIndex(item=>{
                        return item.id == id
                    })
                    //2 根据索引删除对应的数据
                    this.list.splice(index,1)
                },
                changeNum:function(obj){
                    //根据子组件传递来的数据,更新list的数据
                    // for(var i = 0; i< this.list.length;i++){
                    //     if(this.list[i].id == obj.id){
                    //         this.list[i].num = obj.num
                    //     }
                    // }
                    if(obj.type == 'change'){
                       this.list.some(item=>{
                        if(item.id == obj.id){
                         item.num = obj.num
                         return true
                        }
                    })
                    //some这个API用起来遍历,简洁了很多
                    }else if(obj.type == 'sub'){
                        this.list.some(item=>{
                            if(item.id == obj.id&&item.num!=1){
                                item.num -= 1;
                                return true
                            }
                        })
                    }
                    else{
                        this.list.some(item=>{
                            if(item.id == obj.id){
                                item.num += 1
                                return true
                            }
                        })

                    }
                    
                }
            }
        })
        var vm = new Vue({
            el:'#box',
            data:{
                
            },

        })
    </script>
</body>
上一篇下一篇

猜你喜欢

热点阅读