批改状态:合格
老师批语:
组件是可复用的 Vue 实例,且带有一个名字。我们可以在一个通过 new Vue 创建的 Vue 根实例中,把这个组件作为自定义元素来使用
<!-- 挂载点:是隐式声明根组件 --><div id="root"><child-component></child-component><child-component></child-component><child-component></child-component></div><script>// 组件:从形式上看就是一个自定义html标签// 组件是可复用的vue实例,构造函数Vue的子类// 1. 创建// const childComponent = Vue.extend({// template: "<h2>hello world</h2>",// });// 2. 注册// 使用Vue.component()静态方法注册的是 全局组件// Vue.component(组件名,对象字面量表示的组件配置项)// 组件名:自定义的html标签// Vue.component("child-component", childComponent);Vue.component("child-component", {template: "<h2>hello world</h2>",});// 3. 挂载// 将标签添加到页面渲染const vm = new Vue({el: document.querySelector("#root"),});</script>
全局组件:全局可见,声明在Vue实例外部
<div id="root"><button-inc></button-inc></div><hr /><div id="app"><button-inc></button-inc></div><script>// 全局组件:全局可见,声明在Vue实例外部Vue.component("button-inc", {// 组件中的模板代码:允许存在数据占位符的html字符串// 模板内容必须写到一对父元素标签中template: `<div><button @click="count++">点赞:+{{count}}</button></div>`,data() {return {count: 0,};},});const vm = new Vue({el: document.querySelector("#root"),});const vm1 = new Vue({el: document.querySelector("#app"),});// 全局组件可以在多个Vue实例共享,通常一个项目只有一个vue实例,全局组件尽可能不用,使用局部组件。</script>
还可以将组件中的 template 提出去到html中。
<div id="root"><button-inc></button-inc></div><hr /><div id="app"><button-inc></button-inc></div><!-- 模板开始 --><template id="inc"><div><button @click="count++">点赞:+{{count}}</button></div></template><!-- 模板结束 --><script>Vue.component("button-inc", {template: "#inc",// 组件中必须使用函数data()来声明组件变量data() {return {count: 0,};},});const vm = new Vue({el: document.querySelector("#root"),});const vm1 = new Vue({el: document.querySelector("#app"),});// 全局组件可以在多个Vue实例共享,通常一个项目只有一个vue实例,全局组件尽可能不用,使用局部组件。</script>
局部组件是属于vue实例
<div id="root"><my-child></my-child></div><template id="hello"><p>hello {{userName}}</p></template><script>const vm = new Vue({el: document.querySelector("#root"),// 局部组件是属于vue实例components: {"my-child": {template: "#hello",data() {return {userName: "TJ",};},},},});</script>
另一种简写方案
<div id="root"><hello></hello></div><script>const hello={template: `<p>hello {{userName}}</p>`,data() {return {userName: "TJ",},}};const vm = new Vue({el: document.querySelector("#root"),// 局部组件是属于vue实例components: {hello},},});</script>
父组件是通过自定义属性的方式将参数传到子组件中的
<div id="app"><!-- 父组件是通过自定义属性的方式将参数传到子组件中的 --><btn-inc :username="username" :count="count"></btn-inc></div><script>const vm = new Vue({el: document.querySelector("#app"),data() {return {username: "TJ",count: 0,};},//局部组件components: {btnInc: {props: ["username","count"],// 报错原因,组件之间的数据传递是单向的,不允许在子组件中更新父组件的数据。template: `<div><button @click="inc(1)">点赞:+{{num}}</button><span>{{username}}</span></div>`,data(){return {num:this.count,}},methods:{inc(n) {this.num += n;}}},},});</script>
<div id="app"><!-- 子组件中的更新父组件数据是通过自定义同名事件完成的--><btn-inc:username="username":count="count"@click-count="handle"></btn-inc></div><script>const vm = new Vue({// 子组件向父组件传参是通过声明同名事件来实现el: document.querySelector("#app"),data() {return {username: "TJ",count: 0,};},//局部组件components: {btnInc: {props: ["username", "count"],// 报错原因,组件之间的数据传递是单向的,不允许在子组件中更新父组件的数据。// $emit(父组件中要使用的方法名称,子组件要传给父组件的值)template: `<div><button @click="$emit('click-count',10)">点赞:+{{count}}</button><span>{{username}}</span></div>`,methods: {inc(n) {this.num += n;},},},},// 父组件更新数据的方法methods: {handle(value) {this.count += value;this.username = "T.,j";console.log(vm.count);},},});// 总结:// 1. 父组件 向 子组件 传参: 自定义属性// 2. 子组件 向 父组件 传参: 自定义方法</script>
<div id="demo"><input type="text" :value="value" @input="value = $event.target.value" /><p>{{value}}</p></div><script>new Vue({el: "#demo",data() {return {value: 123,};},});</script><hr /><div id="app"><p>父组件 单价:{{price}} 元</p><p><span>子组件</span><my-input :my-price="price" @input-text="handle"></my-input>元</p></div><script>const vm = new Vue({// 子组件向父组件传参是通过声明同名事件来实现el: document.querySelector("#app"),data() {return {price: 4588,};},//局部组件components: {myInput: {props: ["my-price"],template: `<input type="text" :value="myPrice" @input="$emit('input-text',$event.target.value)" />`,},},methods: {handle(value) {this.price = value;},},});</script>
另一种简化方案:将$emit()提出去,写到methods里
<div id="app"><p>父组件 单价:{{price}} 元</p><p><span>子组件</span><my-input :my-price="price" @input-text="handle"></my-input>元</p></div><script>const vm = new Vue({// 子组件向父组件传参是通过声明同名事件来实现el: document.querySelector("#app"),data() {return {price: 4588,};},//局部组件components: {myInput: {props: ["my-price"],template: `<input type="text" :value="myPrice" @input="foo" />`,methods:{foo(ev){this.$emit('input-text',ev.target.value)}}},},methods: {handle(value) {this.price = value;},},});</script>
<div id="app"><my-comp>world</my-comp></div><script>new Vue({el: "#app",components: {myComp: {template: `<div><h2>Hello <slot>user</slot></h2></div>`,},},});</script>
注意:
难点是子组件向父组件传参通过同名事件完成 $emit(同名事件名,参数),如果把此处提出写到methods中要使用this.$emit(),因为是要指定是子组件
在手册中提到在组件中使用v-model
自定义事件也可以用于创建支持 v-model 的自定义输入组件。
<input v-model="searchText">
等价于:
<inputv-bind:value="searchText"v-on:input="searchText = $event.target.value">
当用在组件上时,v-model 则会这样:
<custom-inputv-bind:value="searchText"v-on:input="searchText = $event"></custom-input>
为了让它正常工作,这个组件内的 <input> 必须:
将其 value attribute 绑定到一个名叫 value 的 prop 上
在其 input 事件被触发时,将新的值通过自定义的 input 事件抛出
写成代码之后是这样的:
Vue.component('custom-input', {props: ['value'],template: `<inputv-bind:value="value"v-on:input="$emit('input', $event.target.value)">`})
现在 v-model 就应该可以在这个组件上完美地工作起来了:
<custom-input v-model="searchText"></custom-input>
完整代码
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>组件使用v-model</title><script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script></head><body><div id="app"><p>父组件:{{searchText}}</p><custom-input v-model="searchText"></custom-input></div><script>new Vue({el: "#app",data() {return {searchText: "test",};},components: {"custom-input": {props: ["value"],template: `<inputv-bind:value="value"v-on:input="$emit('input', $event.target.value)">`,},},});</script></body></html>
感觉组件使用v-model不是很灵活的样子
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号