VuecomponentBasics

深入LearningVue.jscomponent basicconcepts, creation方式, 通信mechanism and 生命周期

1. component basicconcepts

component is Vue.jsapplication basic构建块, 它允许我们将UI拆分 for 独立 , 可复用 module. 每个component都package含自己 模板, 逻辑 and 样式.

1.1 component 优势

  • reusability: component可以 in 不同 页面 and 场景in重复using.
  • 可maintenance性: 每个component专注于单一functions, 便于maintenance and update.
  • 可test性: component可以独立fortest.
  • 协作Development: team members可以同时Development不同 component, improvingDevelopmentefficiency.

2. component register

Vuecomponent需要先register才能using. componentregister has 两种方式: 全局register and 局部register.

2.1 全局register

全局register component可以 in 任何Vueinstance 模板inusing.

// 全局registercomponent
Vue.component('my-component', {
    // component选项
    template: '<div>这 is a 全局component</div>',
    data: function() {
        return {
            count: 0
        };
    },
    methods: {
        increment: function() {
            this.count++;
        }
    }
});

2.2 局部register

局部register component只能 in register它 父componentinusing.

// 定义component
var MyComponent = {
    template: '<div>这 is a 局部component</div>',
    data: function() {
        return {
            count: 0
        };
    },
    methods: {
        increment: function() {
            this.count++;
        }
    }
};

//  in Vueinstanceinregister局部component
var app = new Vue({
    el: '#app',
    components: {
        'my-component': MyComponent
    }
});

2.3 componentregister Notes

  • component名称应该usingkebab-case ( short 横线分隔) or PascalCase (首字母 big 写) .
  • in 模板inusingkebab-case引用component.
  • component data选项必须 is a function, 这样每个componentinstance才能拥 has 独立 datareplica.
  • 全局register component会 in Vueinstance化之 before 就被register, 所以不能访问Vueinstance data.

3. component 模板

component 模板定义了component HTMLstructure.

3.1 in 联模板

可以直接 in component选项inusingtemplateproperty定义 in 联模板.

Vue.component('my-component', {
    template: '<div class="my-component">
        <h3>{{ title }}</h3>
        <p>{{ content }}</p>
        <button @click="increment">点击次数: {{ count }}</button>
    </div>',
    data: function() {
        return {
            title: 'component标题',
            content: 'component in 容',
            count: 0
        };
    },
    methods: {
        increment: function() {
            this.count++;
        }
    }
});

3.2 单filecomponent (.vuefile)

in practicalDevelopmentin, 通常using单filecomponent (.vuefile) 来定义component, 这样可以将模板, 脚本 and 样式放 in 同一个filein.

<!-- MyComponent.vue -->
<template>
    <div class="my-component">
        <h3>{{ title }}</h3>
        <p>{{ content }}</p>
        <button @click="increment">点击次数: {{ count }}</button>
    </div>
</template>

<script>
export default {
    data() {
        return {
            title: 'component标题',
            content: 'component in 容',
            count: 0
        };
    },
    methods: {
        increment() {
            this.count++;
        }
    }
};
</script>

<style scoped>
.my-component {
    padding: 20px;
    border: 1px solid #e0e0e0;
    border-radius: 5px;
    background-color: #f8f9fa;
}

button {
    background-color: #4285F4;
    color: white;
    border: none;
    padding: 8px 16px;
    border-radius: 4px;
    cursor: pointer;
}

button:hover {
    background-color: #3367D6;
}
</style>

提示

单filecomponent需要using构建tool (such asWebpack or Vite) for编译才能 in 浏览器inrun.

4. component data and method

component可以拥 has 自己 data and method, and Vueinstanceclass似.

4.1 component data

component data必须 is a function, 这样每个componentinstance才能拥 has 独立 datareplica.

// 正确 做法: data is function
Vue.component('my-component', {
    data: function() {
        return {
            count: 0
        };
    }
});

// error 做法: data is object
Vue.component('my-component', {
    data: {
        count: 0
    }
});

4.2 component method

component method定义 in methods选项in, and Vueinstance methodsclass似.

Vue.component('counter-component', {
    template: '<div>
        <p>当 before 计数: {{ count }}</p>
        <button @click="increment">增加</button>
        <button @click="decrement">reducing</button>
        <button @click="reset">reset</button>
    </div>',
    data: function() {
        return {
            count: 0
        };
    },
    methods: {
        increment: function() {
            this.count++;
        },
        decrement: function() {
            this.count--;
        },
        reset: function() {
            this.count = 0;
        }
    }
});

5. component 生命周期

component 生命周期 and Vueinstance 生命周期class似, 但 has 一些specific hookfunction.

5.1 component 生命周期hook

  • beforeCreate: componentinstancecreation before 调用, 此时data and methods还未初始化.
  • created: componentinstancecreation after 调用, 此时data and methods已初始化, 但DOM还未挂载.
  • beforeMount: DOM挂载 before 调用, 此时模板已编译, 但还未挂载 to DOM on .
  • mounted: DOM挂载 after 调用, 此时模板已挂载 to DOM on , 可以访问DOM元素.
  • beforeUpdate: dataupdate before 调用, 此时data已update, 但DOM还未update.
  • updated: dataupdate after 调用, 此时data and DOM都已update.
  • beforeDestroy: component销毁 before 调用, 此时component仍然可用.
  • destroyed: component销毁 after 调用, 此时component已不可用.
  • activated: (仅用于keep-alivecomponent) component被激活时调用.
  • deactivated: (仅用于keep-alivecomponent) component被停用时调用.
Vue.component('life-cycle-component', {
    template: '<div>
        <p>当 before 计数: {{ count }}</p>
        <button @click="increment">增加</button>
    </div>',
    data: function() {
        return {
            count: 0
        };
    },
    methods: {
        increment: function() {
            this.count++;
        }
    },
    beforeCreate: function() {
        console.log('component beforeCreate hook');
    },
    created: function() {
        console.log('component created hook');
    },
    beforeMount: function() {
        console.log('component beforeMount hook');
    },
    mounted: function() {
        console.log('component mounted hook');
    },
    beforeUpdate: function() {
        console.log('component beforeUpdate hook');
    },
    updated: function() {
        console.log('component updated hook');
    },
    beforeDestroy: function() {
        console.log('component beforeDestroy hook');
    },
    destroyed: function() {
        console.log('component destroyed hook');
    }
});

5.2 生命周期 application场景

  • created: 适合fordata初始化, APIrequestetc.operation.
  • mounted: 适合forDOMoperation, 第三方library初始化etc.operation.
  • updated: 适合 in dataupdate after 执行DOMoperation.
  • beforeDestroy: 适合forclean工作, such as清除定时器, 取消event监听etc..

6. component props

props is 父component向子component传递data 方式.

6.1 basicusing

// 子component
Vue.component('child-component', {
    // 定义props
    props: ['message', 'count'],
    template: '<div>
        <p>父component传递 message: {{ message }}</p>
        <p>父component传递 计数: {{ count }}</p>
    </div>'
});

// 父component
var app = new Vue({
    el: '#app',
    data: {
        parentMessage: 'Hello from parent',
        parentCount: 100
    }
});
<!--  in 父component模板inusing子component -->
<div id="app">
    <child-component 
        :message="parentMessage" 
        :count="parentCount">
    </child-component>
</div>

6.2 props class型validation

可以 for props指定class型, Vue会 in Developmentenvironmentinforclass型validation.

Vue.component('child-component', {
    props: {
        // Basicsclass型check
        message: String,
        count: Number,
        isActive: Boolean,
        items: Array,
        config: Object,
        callback: Function,
        date: Date,
        
        // 带默认值 props
        defaultMessage: {
            type: String,
            default: 'Default message'
        },
        
        // 带默认值 object or array
        defaultItems: {
            type: Array,
            default: function() {
                return [1, 2, 3];
            }
        },
        
        // 必填项
        requiredProp: {
            type: String,
            required: true
        },
        
        // 自定义verificationfunction
        customProp: {
            validator: function(value) {
                return value > 0;
            }
        }
    },
    template: '<div>...</div>'
});

warning

props is 单向data流, 子component不应该直接modify父component传递 props. such as果需要modify, 应该througheventnotification父componentformodify.

7. component event

子component可以throughevent向父component发送message.

7.1 自定义event

// 子component
Vue.component('child-component', {
    template: '<div>
        <button @click="sendMessage">向父component发送message</button>
    </div>',
    methods: {
        sendMessage: function() {
            // using$emit触发自定义event
            this.$emit('child-event', 'Hello from child', 123);
        }
    }
});

// 父component
var app = new Vue({
    el: '#app',
    methods: {
        handleChildEvent: function(message, data) {
            console.log('收 to 子component message:', message, data);
        }
    }
});
<!--  in 父component模板in监听子componentevent -->
<div id="app">
    <child-component @child-event="handleChildEvent"></child-component>
</div>

7.2 event修饰符

Vueproviding了一些event修饰符, 用于简化eventprocessing逻辑.

  • .stop: 阻止event冒泡
  • .prevent: 阻止默认event
  • .capture: usingevent捕获模式
  • .self: 只当event in 该元素本身触发时才触发processingfunction
  • .once: event只触发一次
  • .passive: 告诉浏览器该event监听器不会调用preventDefault()
<!-- 阻止event冒泡 -->
<div @click.stop="handleClick">点击</div>

<!-- 阻止默认event -->
<form @submit.prevent="handleSubmit">
    <button type="submit">submitting</button>
</form>

<!-- event只触发一次 -->
<button @click.once="handleClickOnce">只点击一次</button>

8. component 插槽

插槽允许父component向子component 指定位置插入 in 容.

8.1 basic插槽

// 子component
Vue.component('child-component', {
    template: '<div class="child">
        <h3>子component标题</h3>
        <slot>默认 in 容</slot>
        <p>子component底部</p>
    </div>'
});
<!--  in 父componentinusing插槽 -->
<div id="app">
    <child-component>
        <p>这 is 插入 to 子component插槽in  in 容</p>
    </child-component>
    
    <child-component>
        <ul>
            <li>list项1</li>
            <li>list项2</li>
            <li>list项3</li>
        </ul>
    </child-component>
</div>

8.2 具名插槽

具名插槽允许 in 子componentin定义 many 个插槽, 父component可以向不同 插槽插入 in 容.

// 子component
Vue.component('layout-component', {
    template: '<div class="layout">
        <header>
            <slot name="header">默认头部</slot>
        </header>
        <main>
            <slot>默认 in 容</slot>
        </main>
        <footer>
            <slot name="footer">默认底部</slot>
        </footer>
    </div>'
});
<!--  in 父componentinusing具名插槽 -->
<div id="app">
    <layout-component>
        <template v-slot:header>
            <h1>自定义头部</h1>
        </template>
        
        <template v-slot:default>
            <p>自定义 in 容</p>
            <p>更 many  in 容</p>
        </template>
        
        <template v-slot:footer>
            <p>自定义底部</p>
        </template>
    </layout-component>
</div>

提示

v-slot可以缩写 for #, 例such asv-slot:header可以缩写 for #header.

8.3 作用域插槽

作用域插槽允许子component向父component传递data, 父component可以using这些data来渲染插槽 in 容.

// 子component
Vue.component('list-component', {
    data: function() {
        return {
            items: ['苹果', '香蕉', '橙子', '葡萄', '西瓜']
        };
    },
    template: '<div class="list">
        <h3>水果list</h3>
        <ul>
            <li v-for="(item, index) in items" :key="index">
                <slot :item="item" :index="index">
                    {{ item }}
                </slot>
            </li>
        </ul>
    </div>'
});
<!--  in 父componentinusing作用域插槽 -->
<div id="app">
    <list-component>
        <template v-slot="slotProps">
            <strong>{{ slotProps.index + 1 }}. {{ slotProps.item }}</strong>
        </template>
    </list-component>
    
    <list-component>
        <template v-slot:default="{ item, index }">
            <span style="color: red;">{{ index + 1 }}. {{ item }}</span>
        </template>
    </list-component>
</div>

练习 1: creation and usingcomponent

  1. creation一个全局component, 用于显示userinformation (package含姓名, 年龄, 性别) .
  2. creation一个局部component, 用于显示商品list (package含商品名称, 价格, describes) .
  3. in Vueinstanceinusing这两个component.
  4. for component添加适当 样式.

练习 2: component间通信

  1. creation一个父component and 一个子component.
  2. 父component向子component传递data (usingprops) .
  3. 子component向父component发送event (using$emit) .
  4. implementation一个 simple 计数器functions:
    • 子component显示计数 and 增加按钮
    • 点击增加按钮, 子component向父component发送event
    • 父componentupdate计数, 并throughprops传递给子component

练习 3: using插槽

  1. creation一个卡片component, package含头部, in 容 and 底部三个插槽.
  2. in 父componentinusing该卡片component, 向不同 插槽插入 in 容.
  3. for 卡片component添加适当 样式, 使其看起来像一个真正 卡片.
  4. creation一个listcomponent, using作用域插槽向父component传递list项data.
  5. in 父componentinusing作用域插槽自定义list项 渲染方式.