(05)Vue 初识——⑤ 简单的组件间传值 | Vue 基础理论实操

1,371 阅读2分钟
本文版权归 “公众号 | 前端一万小时” 所有,欢迎转载!

转载请注明出处,未经同意,不可修改文章内容。

🔥🔥🔥本系列文章已在“公众号 | 前端一万小时”更新完毕,有需要的小伙伴可按需前往查看。

🔥🔥🔥“前端一万小时”两大明星专栏——“从零基础到轻松就业”、“前端面试刷题”,已于本月大改版,合二为一,干货满满,欢迎点击公众号菜单栏各模块了解。


涉及面试题:
props 是什么?

[编号:vue_05]

🔗本阶段对应的“官方文档”阅读“介绍”章节

1 父组件向子组件传值

上一篇我们封装列表组件时,让 input 框的输入内容显示在列表组件上就已经用到了“父组件向子组件传值”。

<div id="app">
  <input type="text" v-model="inputValue">
  <button v-on:click="handleBtnClick">添加</button>
  <ul>
    
    <todo-item v-bind:content="item" 
               v-for="item in list"> <!-- 2️⃣-①:使用子组件;
    																 2️⃣-②:父组件通过 v-bind 动态绑定
																		 content 的形式传递内容给子组件; -->
    </todo-item>

  </ul>
</div>

<script>
  var TodoItem = {
    props: ['content'], // 3️⃣子组件中以 props 接收 content;
    template: '<li>{{content}}</li>' // 4️⃣在模板中使用接收到的数据。
  }

  var app = new Vue({ // 1️⃣父组件是 app 实例这个根组件,即整个 #app 这个 div 的内容;
    
    el: '#app',
    
    components: { // 2️⃣子组件是注册在根组件的 TodoItem,它在根组件里的名字也叫 TodoItem;
      TodoItem: TodoItem
    },
    
    data: {
      list: [],
      inputValue: ''
    },
    methods: {
      handleBtnClick() {
        this.list.push(this.inputValue)
        this.inputValue = ''
      }
    }
  })
</script>

简而言之:父组件通过“属性”向子组件传值,子组件通过 props 接收属性来调用其内容。

2 子组件向父组件传值

🚀需求:当点击列表项时,删除所点击的对应内容。

也就是说,当点击子组件中的某个列表项时,父组件收到对应信息来删除对应列表项。那么完成这个需求,就涉及到“子组件向父组件传值”。

❗️注意:为了代码简洁,接下来大家已经比较熟悉的 v-bind 和 v-on 指令都将用简写!

v-on 简写为 @ ,用来绑定事件监听器;v-bind 简写为 : ,用来动态绑定属性。

<div id="app">
  <input type="text" v-model="inputValue">
  <button @click="handleBtnClick">添加</button>
  <ul>

    <todo-item :content="item"
               v-for="item in list"
               @delete="handleItemDelete"
    > <!-- 3️⃣-①:父组件在创建子组件时,通过 v-on 指令监听 delete 事件;
       3️⃣-②:一旦 delete 事件被触发,父组件就执行 handleItemDelete 方法; -->
      
    </todo-item>

  </ul>
</div>

<script>

  var TodoItem = {
    props: ['content'],

    // 1️⃣子组件的 li 标签监听 click 事件,当触发时执行 handleItemClick 方法;
    template: '<li @click="handleItemClick">{{content}}</li>',

    methods: { // 2️⃣-①:子组件的方法定义在子组件的 methods 中;

      handleItemClick() {
        this.$emit('delete') // 2️⃣-②:子组件中,通过 $emit 向外触发 delete 事件;
      }
    }
  }

  var app = new Vue({
    el: '#app',
    components: {
      TodoItem: TodoItem
    },
    data: {
      list: [],
      inputValue: ''
    },
    methods: {
      handleBtnClick() {
        this.list.push(this.inputValue)
        this.inputValue = ''
      },

      handleItemDelete() { // 4️⃣-①:在父组件的 methods 中定义 handleItemDelete 方法;
        
        this.list = [] // 4️⃣-②:让 list 为空数组 []。
      }
    }
  })
</script>

保存返回页面,刷新查看效果:我们完成了子组件向父组件传值,成功删除了列表项。但,当点击列表项时,清空了“整个”列表!

vue_05-01.gif

这是因为当 delete 事件触发后,父组件执行的 handleItemDelete 方法中我们让 list 为空数组。

handleItemDelete() { // 4️⃣-①:在父组件的 methods 中定义 handleItemDelete 方法;
  
	this.list = [] // 4️⃣-②:让 list 为空数组 []。
}

而当 list 为空数组,即改变了 list 的数据,让它已有的列表项被全部清空。所以当点击某一个列表项时,我们就看到整个列表被清空。

❓如何正确删除所点击的某一项列表?

答:可以通过获取列表项的下标来完成此功能。

<div id="app">
  <input type="text" v-model="inputValue">
  <button @click="handleBtnClick">添加</button>
  <ul>

    <todo-item :content="item"
               :index="index"
               v-for="(item, index) in list"
               @delete="handleItemDelete"
    > <!-- 1️⃣当循环 list 数组时,第一项获取内容 item,
			第二项获取数组的下标 index;
			 
			2️⃣动态绑定一个名为 index 的属性,当父组件向子组件传值时,
			除了 content 对应的内容 item,同时再传入 index 对应的列表项下标; -->
    </todo-item>

  </ul>
</div>

<script>
  var TodoItem = {
    props: ['content', 'index'], // 3️⃣子组件要使用列表项下标,必须在 props 中接收 index 属性;

    template: '<li @click="handleItemClick">{{content}}</li>',
    methods: {

      handleItemClick() {
        this.$emit('delete', this.index) /*
        																 4️⃣当子组件被点击时,不但触发 delete 事件,
        																 同时把被点击列表项的下标作为参数传给父组件;
                                          */
      }
    }
  }

  var app = new Vue({
    el: '#app',
    components: {
      TodoItem: TodoItem
    },
    data: {
      list: [],
      inputValue: ''
    },
    methods: {
      handleBtnClick() {
        this.list.push(this.inputValue)
        this.inputValue = ''
      },

      handleItemDelete(index) { /*
      													5️⃣-①:父组件接收子组件传来的下标,
        											  当监听到 delete 事件被触发时执行 handleItemDelete 方法;
                                 */
        
        this.list.splice(index, 1) // 5️⃣-②:从传来的下标开始,删除一项。
      }
    }
  })
</script>

vue_05-02.gif

现在我们完成了“当点击列表项时,删除所点击的对应内容”的需求,同时还学到了子组件向父组件传值的方式。

再简述一次此实现流程:

  1. 父组件通过 v-bind 指令传递下标 index 值;
  2. 父组件传递的值,子组件一定要在自己的 props 接收;
  3. 子组件通过 $emit 触发 delete 事件,同时传递被点击列表项的下标;
  4. 父组件通过 v-on 监听 delete 事件,获取到子组件传递的下标并执行 handleItemDelete 方法;
  5. 最终实现当点击某项列表时,删除此项。

祝好,qdywxs ♥ you!