zoukankan      html  css  js  c++  java
  • Vue学习笔记2--组件化开发

    组件化开发

    完整的基础篇笔记PDF下载,完全手打有用的话请给个赞呗Thanks♪(・ω・)ノ

    推荐官方文档内容最全

    组件化思想

    • 标准
    • 分治
    • 重用
    • 组合

    组件注册

    全局注册

    Demo--注册

    Vue.component('button-counter',{
        //组件内部需要的数据
        data: function(){
            return {
                count: 0
            }
        },
        //组件的模板
        template: '<button @click="count++">点击了{{count}}</button>'
    });
    

    使用

    <button-counter></button-counter>
    

    注意事项:

    • data必须是一个函数(形成闭包保证每个组件数据的独立性)

    • 组件模板内容必须是单个根元素

    • 组件模板内容可以使用模板字符串

       Vue.component('button-counter',{
       	data: function(){
          	return {
              	count: 0
                  }
           },
           template: `
               <div>
                   <button @click='count++'>{{count}}</button>
                   <button @click='count++'>{{count}}</button>
               </div>
                  `
      });
      
    • 命名方式

      • 短横线:推荐

      • 驼峰式:不可以在页面上直接使用驼峰式(换为对应的短横线),只可以在其他组件模板中使用驼峰式

        HelloWorld --> hello-world
        

    局部注册

    var ComponentA = { /* ... */ }
    var ComponentB = { /* ... */ }
    var ComponentC = { /* ... */ }
    new Vue({
      el: '#app',
      components: {
        'component-a': ComponentA,
        'component-b': ComponentB
      }
    })
    

    注意

    • 局部注册的组件只能在其注册的父组件中使用
    • 全局组件模板中使用局部组件会报错

    Vue调试工具

    谷歌商店:vue-devtools

    组件间的数据交互

    父组件向子组件传值

    Vue.component('blog-post', {
      // 子组件接收父组件的值
      props: ['postTitle'],
      template: '<h3>{{ postTitle }}</h3>'
    })
    
    <!-- 父组件使用时直接在对应名称的属性中传值 -->
    <blog-post post-title="hello!"></blog-post>
    <!-- 动态获取 -->
    <blog-post :post-title="title"></blog-post>
    

    props支持类型

    子组件向父组件传值

    子组件可以直接操作父组件传过来的值

    props传递数据的原则:单向数据传递

    不推荐直接更改props中的数据

    使用$emit自定义事件改变父组件中的数据

    思路:

    • 子组件模板中绑定事件
    • 父组件中监听子组件的事件
    • 将改变逻辑放到父组件方法中
     //子组件
     Vue.component('button-counter',{
         template: `
            <div>
                <button @click='$emit("enlarge-text")'>扩大父组件的字体大小</button>
            </div>
        `
     });
    

    页面父组件中监听对应的事件enlarge-text

    <div id="app">
        <div :style='{fontSize: fontSize + "px"}'>{{msg}}</div>
        <button-counter @enlarge-text="handle"></button-counter>
    </div>
    

    父组件中处理逻辑handle

    var vm = new Vue({
        el: '#app',
        data: {
            fontSize: 10,
            msg: 'Hello World'
        },
        methods: {
            handle: function () {
                this.fontSize += 5;
            }
        }
    });
    
    子组件自定义事件携带参数
    Vue.component('button-counter',{
        template: `
            <div>
            	<button @click='$emit("enlarge-text",12)'>扩大父组件的字体大小</button>
            </div>
            `
    });
    

    父组件中使用$event获取传值

    <div id="app">
        <div :style='{fontSize: fontSize + "px"}'>{{msg}}</div>
        <button-counter @enlarge-text="handle($event)"></button-counter>
    </div>
    

    父组件处理方法handle接收参数

    handle: function (val) {
    	this.fontSize += val;
    }
    

    非父子组件间的传值

    使用事件中心管理组件间的通信

    • 单独的事件中心

      var eventHub = new Vue();
      
    • 监听事件和销毁事件

      eventHub.$on('add-todo',addTodo);
      eventHub.$off('add-todo');
      
    • 触发事件

      eventHub.$emit('add-todo',id);
      
    Demo
    • 创建事件中心处理组件
    var hub = new Vue();
    
    • 定义组件1:
    Vue.component('test-tom', {
        data: function () {
            return {
                num: 0
            }
        },
        template: `
        <div>
            <div>Tom : {{num}}</div>
            <div>
            	<button @click='handle'>点击</button>
            </div>
        </div>
        `,
        methods:{
            handle: function(){
                //通过事件处理中心触发兄弟组件的事件
                hub.$emit('jerry-event',1);
            }
        },
        mounted() {
            //监听事件中心组件中的事件
            hub.$on('tom-event',(val)=>{
                this.num += val;
            });
        }
    });
    
    • 定义组件2
    Vue.component('test-jerry', {
        data: function () {
            return {
                num: 0
            }
        },
        template: `
        <div>
            <div>Jerry : {{num}}</div>
            <div>
            	<button @click='handle'>点击</button>
            </div>
        </div>
        `,
        methods:{
            handle: function(){
                //通过事件处理中心触发兄弟组件的事件
                hub.$emit('tom-event',2);
            }
        },
        mounted() {
             //监听事件中心组件中的事件
            hub.$on('jerry-event',(val)=>{
                this.num += val;
            });
        }
    });
    
    • 页面使用
    <div id="app">
        <test-tom></test-tom>
        <test-jerry></test-jerry>
    </div>
    

    组件插槽

    父组件向子组件传递内容

    使用指定插槽位置

    Vue.component('alert-box',{
        template: `
        <div>
            <strong>ERROR:</strong>
            <slot></slot>
        </div>
        `
    });
    

    父组件中传递内容

    <div id="app">
        <alert-box>传递的内容</alert-box>
    </div>
    

    默认内容在不传递内容时显示

    具名插槽

    组件template

    <div class="container">
      <header>
        <slot name="header"></slot>
      </header>
      <main>
        <slot></slot>
      </main>
      <footer>
        <slot name="footer"></slot>
      </footer>
    </div>
    

    页面调用v-slot指定插入的位置,未指定的填充到未命名的插槽

    template临时包裹信息,不会渲染到页面

    <base-layout>
      <template v-slot:header>
        <h1>Here might be a page title</h1>
      </template>
    
      <p>A paragraph for the main content.</p>
      <p>And another one.</p>
    
      <template v-slot:footer>
        <p>Here's some contact info</p>
      </template>
    </base-layout>
    

    作用域插槽

    • 应用场景

      父组件对子组件的内容进行处理

    子组件中使用slot指定插槽,并且指定slot的属性返回要在父组件中处理的数据

    Vue.component('fruit-list',{
        //获取父组件通过属性传过来的数据
        props: ['list'],
        template: `
            <div>
                <ul>
                    <li :key='item.id' v-for='item in list'>
                        <slot :info='item'>{{item.name}}</slot>
                    </li>
                </ul>
            </div>
            `
    });
    

    父组件提供数据

    var vm = new Vue({
        el: '#app',
        data: {
            list: [{
                id: 1,
                name: 'apple'
            },{
                id: 2,
                name: 'banane'
            },{
                id: 3,
                name: 'orange'
            }]
        }
    });
    

    父组件页面调用子组件

    • :list="list" 向子组件传递数据
    • v-slot="slotProps" 用来接收子组件
    • slotProps.info 获取子组件通过属性(info)返回的数据
    <div id="app">
        <fruit-list :list="list">
            <template v-slot="slotProps">
                <!-- 子组件通过属性名传递回来数据 info -->
                <strong v-if="slotProps.info.id == 2">{{slotProps.info.name}}</strong>
            </template>
        </fruit-list>
    </div>
    

    案例:购物车

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>选项卡</title>
        <!-- 引入vue.js -->
        <script src="js/vue.js"></script>
        <style>
            #app{
                position: relative;
                left: 50%;
            }
            .cart{
                 50%;
            }
            .title{
                 100%;
                height: 30px;
                border: 1px solid blueviolet;
                background-color: aqua;
                text-align: center;
                font-size: large;
            }
            .cartlist{
                 100%;
                border: 1px outset pink;
            }
            .cartitem{
                height: 50px;
                text-align: center;
                font-size: x-large;
            }
            .itemname{
                position: relative;
                left: -70px;
            }
            .option input{
                 40px;
            }
            .total{
                 100%;
                border: 1px solid yellow;
                background-color: yellow;
                text-align: right;
            }
    
    
        </style>
    </head>
    
    <body>
        <div id="app">
          <my-cart></my-cart>
        </div>
        <script>
            var cartTitle = {
                props: ['uname'],
                template: `
                    <div class="title">{{uname}}的购物车</div>
                `
            }
            var cartList = {
                props: ['list'],
                template: `
                <div class="cartlist">
                    <div class="cartitem" :key='item.id' v-for='item in list'>
                        <span class="itemname">{{item.name}}</span>
                        <span class="option">
                            <button @click='dec(item.id)'>-</button>
                            <input type="number" :value='item.num' @blur='changeNum(item.id,$event)'>
                            <button @click='add(item.id)'>+</button>
                            <button @click='del(item.id)'>×</button>
                        </span>
                    </div>
                </div>
                `,
                methods:{
                    del: function(id){
                        //将id传递给父组件
                        this.$emit('cart-del',id);
                    },
                    dec: function(id){
                        this.$emit('cart-dec',id);
                    },
                    add: function(id){
                        this.$emit('cart-add',id);
                    },
                    changeNum: function(id,event){
                        this.$emit('change-num',{
                            id: id,
                            num: event.target.value
                        })
                    }
                }
            }
            var cartTotal = {
                props: ['list'],
                template: `
                <div class="total">
                    <span class="price">
                        <span>总价</span>
                        <span>{{total}}</span>
                    </span>
                    <span class="sum">
                        <button>结算</button>
                    </span>
                </div>
                `,
                computed: {
                    total: function(){
                        //计算商品总价
                        var t = 0;
                        this.list.forEach(item=>{
                            t += item.price * item.num;
                        });
                        return t;
                    }
                },
            }
            Vue.component('my-cart',{
                data: function(){
                    return {
                        uname: '张三',
                        list: [
                            {
                                id: 1,
                                name: '小米',
                                price: 200,
                                num: 1
                            },{
                                id: 2,
                                name: '小狗',
                                price: 200,
                                num: 2
                            },{
                                id: 3,
                                name: '小猫',
                                price: 200,
                                num: 3
                            },{
                                id: 4,
                                name: '小野猪',
                                price: 200,
                                num: 1
                            },{
                                id: 5,
                                name: '小皮球',
                                price: 200,
                                num: 1
                            }
                        ]
                    }
                },
                template: `
                <div class="cart">
                    <cart-title :uname='uname'></cart-title>
                    <cart-list :list='list' @change-num='changeNum($event)' @cart-del='delCart($event)' @cart-dec='decNum($event)' @cart-add='addNum($event)'></cart-list>
                    <cart-total :list='list'></cart-total>
                </div>
                `,
                components: {
                    'cart-title': cartTitle,
                    'cart-list': cartList,
                    'cart-total': cartTotal
                },
                methods: {
                    delCart: function(id){
                        //根据id删除列表中的数据
                        var index = this.list.findIndex(item=>{
                            return item.id = id;
                        });
                        this.list.splice(index,1);
                    },
                    decNum: function(id){
                        //减少指定商品的数量
                        this.list.some(item=>{
                            if(item.id == id){
                                item.num--;
                                return true;
                            }
                        });
                    },
                    addNum: function(id){
                        //增加指定商品的数量
                        this.list.some(item=>{
                            if(item.id == id){
                                item.num++;
                                return true;
                            }
                        });
                    },
                    changeNum: function(pojo){
                        //通过更改输入框更改数量
                        this.list.some(item=>{
                            if(item.id == pojo.id){
                                item.num += pojo.num;
                                return true;
                            }
                        });
                    }
                }
            });
            var vm = new Vue({
                el: '#app',
                data: {
                   
                },
                methods: {
                    handle: function () {
    
                    }
                }
            });
        </script>
    </body>
    
    </html>
    
  • 相关阅读:
    数据结构之fhq-treap
    [AtCoder Regular Contest 096 E] Everything on It 解题报告 (第二类斯特林数+容斥原理)
    指纹识别人脸识别 iOS
    HTTP协议的8种请求类型介绍
    获取已安装app的bundle id
    iOS生成Bundle包及使用
    为什么说Objective-C是一门动态的语言?
    引用外部静态库(.a文件)时或打包.a时,Category方法无法调用。崩溃
    代码混淆 iOS
    HDU 1695 GCD(莫比乌斯反演)
  • 原文地址:https://www.cnblogs.com/erkye/p/12825204.html
Copyright © 2011-2022 走看看