博客列表 >Vue组件基础与父子组件之间的通信方式

Vue组件基础与父子组件之间的通信方式

残破的蛋蛋
残破的蛋蛋原创
2021年01月20日 17:06:13640浏览

Vue组件基础与父子组件之间的值传递方式

一、组件基本示例

1.1 组件的概念

组件从形式上看就是一个自定义的HTML标签,组件是可复用的vue实例,要构造函数Vue的子类。

1.1.1 全局组件

  • 创建一个组件分为3步,这里有一个Vue组件的实例:
  1. <script>
  2. // 第一步:创建组件
  3. const childComponent = Vue.extend({
  4. template: `<h2>Hello World</h2>`
  5. });
  6. // 第二步:注册组件
  7. Vue.component("child-component", childComponent);
  8. // Vue实例
  9. const vm = new Vue({
  10. el: "#app"
  11. });
  12. </script>
  1. <!-- 第三步:将组件挂载到页面中。 -->
  2. <div id="app">
  3. <child-component></child-component>
  4. <child-component></child-component>
  5. <child-component></child-component>
  6. </div>
  • 效果图:

Vue基础组件

以上是一个Vue组件从创建到挂载到页面中的过程。其中可以省略掉第一步的创建过程,直接在第二步注册的时候自动执行创建。

  • 语法:

Vue.component(id, [function | object | definition])

  • 参数说明:
  1. id:字符串类型,组件名称。
  2. function:可以传入函数Vue.extend({ /* ... */ })
    传入一个选项对象 (自动调用 Vue.extend) { /* ... */ }
    获取注册的组件 (始终返回构造器) Vue.component('my-component')

因此,上述Vue基础实例可以使用以下方法简化:

  1. Vue.component("child-component", {
  2. template: `<h2>Hello World</h2>`
  3. });

实例 利用全局组件做一个点赞的小案例:

  1. <div id="app">
  2. <btn-inc></btn-inc>
  3. <btn-inc></btn-inc>
  4. <btn-inc></btn-inc>
  5. </div>
  6. <hr>
  7. <template id="inc">
  8. <div>
  9. <button @click="count++">点赞:+{{count}}</button>
  10. </div>
  11. </template>
  12. <script>
  13. Vue.component("btn-inc", {
  14. template: "#inc",
  15. data() {
  16. return {
  17. count: 0
  18. }
  19. }
  20. });
  21. const vm = new Vue({
  22. el: "#app"
  23. });
  24. </script>
  • 效果图:

全局组件案例

注意:

  • 使用Vue.component()方法创建的组件是全局组件。

  • 全局组件必须声明在Vue实例的外部,并且必须声明在实例创建前。

1.1.2 局部组件

局部组件:需要在实例化对象中通过components属性进行注册。

1.第一种写法:直接写在组件里面的template属性中。

  1. const vm = new Vue({
  2. // 局部组件是属于vue实例的。
  3. components: {
  4. "btn-inc": {
  5. template: `<h2>Hello {{site}} </h2>`,
  6. data () {
  7. return {
  8. site: "PHP中文网"
  9. }
  10. }
  11. }
  12. }
  13. }).$mount("#app");

使用:

  1. <div id="app">
  2. <btn-inc></btn-inc>
  3. <btn-inc></btn-inc>
  4. <btn-inc></btn-inc>
  5. </div>

2.在自定义html标签中渲染

  1. <div id="app">
  2. <btn-inc></btn-inc>
  3. <btn-inc></btn-inc>
  4. <btn-inc></btn-inc>
  5. </div>
  6. <template id="hello">
  7. <div>
  8. <h2>Hello {{site}} </h2>
  9. </div>
  10. </template>
  1. const vm = new Vue({
  2. components: {
  3. "btn-inc": {
  4. // 创建一个id为hello的自定义hmtl标签
  5. template: "#hello",
  6. data () {
  7. return {
  8. site: "PHP中文网"
  9. }
  10. }
  11. }
  12. }
  13. }).$mount("#app");

3.给模板字面量赋给一个变量值

  1. const hello = `<h2>Hello {{site}} </h2>`;
  2. const vm = new Vue({
  3. components: {
  4. "btn-inc": {
  5. template: hello,
  6. data () {
  7. return {
  8. site: "PHP中文网"
  9. }
  10. }
  11. }
  12. }
  13. }).$mount("#app");

使用:

  1. <div id="app">
  2. <btn-inc></btn-inc>
  3. <btn-inc></btn-inc>
  4. <btn-inc></btn-inc>
  5. </div>

4.根据ES6新特性进行简化

现在,我把整个模板和它的data()函数全部拿出来做一个对象字面量付给一个变量hello:

  1. let hello = {
  2. template: `<h2>Hello {{site}}</h2>`,
  3. data () {
  4. return {
  5. site: "PHP中文网"
  6. }
  7. }
  8. };

然后,在vue实例的components组件中定义一个组件名也为hello的组件:

  1. const vm = new Vue({
  2. components: {
  3. hello: hello
  4. }
  5. }).$mount("#app");

由于ES6有一个新特性,当对象的属性和值相同时,可简写,所以我还可以这样写:

  1. const vm = new Vue({
  2. components: {
  3. hello,
  4. }
  5. }).$mount("#app");

使用:

  1. <div id="app">
  2. <hello></hello>
  3. <hello></hello>
  4. <hello></hello>
  5. </div>
  • 以上四种写法都可以实现相同的效果,如下图:

局部组件

注意事项:

在使用子组件的时候,例如上述我们定义的<btn-inc>组件,我们会发现他的data并不是一个对象:

  1. data: {
  2. site: "PHP中文网"
  3. }

取而代之的是函数,也就是说一个组件的data选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立拷贝:

  1. data () {
  2. return {
  3. site: "PHP中文网"
  4. }
  5. }

以上这一点是特别需要注意的。


二、组件之间的值传递

2.1 父组件向子组件的传值方式

父组件向子组件传值是通过props属性进行的,Prop是我们在组件上注册的一些自定义attitude。当一个值传递给一个prop attribute的时候,它就变成组件实例的一个property。为了给下面的user-info组件传递用户id,用户名,用户邮箱值,我们可以使用一个props数组将其包含在该组件可接收的prop列表中:

  1. const vm = new Vue({
  2. el: "#app",
  3. data () {
  4. return {
  5. users: [
  6. { id: 1, name: "残破的蛋蛋", email: "canpo@dd.cn" },
  7. { id: 2, name: "拤碎的蛋蛋", email: "qiasui@dd.cn" },
  8. { id: 3, name: "漂亮的蛋蛋", email: "piaoliang@dd.cn" },
  9. ]
  10. }
  11. },
  12. components: {
  13. userInfo: {
  14. props: ["selfId", "selfUsername", "selfEmail"],
  15. template: `
  16. <div>
  17. <span>id:{{selfId}},</span>
  18. <span>用户名:{{selfUsername}},</span>
  19. <span>邮箱:{{selfEmail}}</span>
  20. </div>
  21. `
  22. }
  23. }
  24. });

一个组件可以拥有任意数量的prop,任何值都可以传递给prop,在上述案例中,我们就可以在组件实例中访问到这个值,就跟直接访问data中的值一样。

一个组件被注册了之后,我们就可以这样把数据作为一个自定义的attribute传递进来:

  1. <div id="app">
  2. <user-info
  3. v-for="user of users"
  4. :self-username="user.name"
  5. :self-id="user.id"
  6. :self-email="user.email"
  7. :key="user.id"
  8. >
  9. </user-info>
  10. </div>
  • 效果图:

实例解释

父子组件的传值

2.2 子组件向父组件的传值方式

正常情况下,子组件向父组件传参的是无法直接传递的,需要用到Vue内建的$emit()方法传入事件名称来触发一个事件,

  • 语法:

$emit(eventName, […args])

  • 参数:

eventName:事件方法,字符串类型
[…args]*:子组件传递给父组件的参数值

以下是一个点赞的案例:首先声明一个Vue实例,并创建一个组件<btn-inc>,由于子组件向父组件传值需要使用同名事件方法通过$emit()进行传值,因此我们需要在子组件<button>上添加一个点击事件方法@click="$emit('click-count', 10)并传递一个click-count方法和值。

  1. <!-- 子组件 -->
  2. <template id="btn">
  3. <div>
  4. <button @click="$emit('click-count', 10)">
  5. 点赞 + {{myCount}}
  6. </button>
  7. <span>{{myUsername}}</span>
  8. </div>
  9. </template>

父组件<btn-inc>上需要监听一个点击事件click-count

  1. <div id="app">
  2. <btn-inc :my-count="count" :user-name="username" @click-count="handle"></btn-inc>
  3. </div>

在Vue实例下创建一个handle方法来处理点击事件,这样我们就可以通过子组件向父组件传值了:

  1. handle(value) {
  2. this.count += value
  3. }

完整的案例代码:

  1. <div id="app">
  2. <btn-inc :my-count="count" :user-name="username" @click-count="handle"></btn-inc>
  3. </div>
  4. <template id="btn">
  5. <div>
  6. <button @click="$emit('click-count', 10)">
  7. 点赞 + {{myCount}}
  8. </button>
  9. <span>{{myUsername}}</span>
  10. </div>
  11. </template>
  12. <script>
  13. const vm = new Vue({
  14. data () {
  15. return {
  16. count: 0,
  17. username: "残破的蛋蛋"
  18. };
  19. },
  20. components: {
  21. btnInc: {
  22. props: ["userName", "myCount"],
  23. template: "#btn",
  24. }
  25. },
  26. methods: {
  27. handle(value) {
  28. console.log(this.count);
  29. this.count += value
  30. }
  31. },
  32. }).$mount("#app");
  33. </script>
  • 相关参数方法对应关系图:

关系图

  • 效果图:

子组件向父组件传值

2.23 父子组件之间的双向传参

上面两个案例讲述了父组件向子组件传参以及子组件向父组件传参,下面这个案例讲展示父子组件之间如何双向传参。

  1. <div id="app">
  2. <!-- 父组件 -->
  3. <p>父组件:{{price}} 元</p>
  4. <my-input :my-price="price" @input-text="handle"></my-input>
  5. </div>
  6. <!-- 子组件 -->
  7. <template id="myinput">
  8. <div>
  9. <input type="text" :value="myPrice" @input="$emit('input-text', $event.target.value)">
  10. </div>
  11. </template>
  12. <script>
  13. const vm = new Vue({
  14. data() {
  15. return {
  16. price: 4588
  17. };
  18. },
  19. // 子组件向父组件传参时通过声明同名事件实现的
  20. components: {
  21. myInput: {
  22. template: "#myinput",
  23. props: ["my-price"],
  24. }
  25. },
  26. methods: {
  27. handle (value) {
  28. this.price = value;
  29. }
  30. },
  31. }).$mount("#app");
  32. </script>
  • 效果图:

组件之间的双向传参

不论我们是在输入框内改变子组件的值,还是在控制台中修改父组件的值,另外一个值都会随之而改变,这就是组件之间的双向传参。

声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议