likes
comments
collection
share

Vue.js 理论基础 | 写给 Vue 初学者的理论实操教程,(我的风格)通俗易懂,跟完就可独立上手!

作者站长头像
站长
· 阅读数 15
本文版权归 “公众号 | 前端一万小时” 所有,欢迎转载!

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

🔥🔥🔥“前端一万小时”两大明星专栏已于本月大改版,合二为一,欢迎点击公众号菜单栏各模块了解。

❗️❗️❗️由于篇幅原因,本文只能详细列示整个系列的前 5 篇文章,整个系列文章请点击公众号免费查看。

Vue.js 理论基础 | 写给 Vue 初学者的理论实操教程,(我的风格)通俗易懂,跟完就可独立上手!


目录:
  Vue 初识——① Hello World
  Vue 初识——② 简易 TodoList
  Vue 初识——③ MVVM 模式
  Vue 初识——④ 使用组件改造 TodoList
  Vue 初识——⑤ 简单的组件间传值
  Vue 入门——① Vue 实例
  Vue 入门——② Vue 实例的生命周期函数
  Vue 入门——③ 模板语法
  Vue 入门——④ 计算属性、方法与侦听器
  Vue 入门——⑤ 计算属性的 gettersetter
  Vue 入门——⑥ Class 与 Style 绑定
  Vue 入门——⑦ 条件渲染
  Vue 入门——⑧ 列表渲染
  深入理解 Vue 组件——① 使用组件的细节点
  深入理解 Vue 组件——② 父子组件间的数据传递
  深入理解 Vue 组件——③ 组件参数校验与非 props 特性
  深入理解 Vue 组件——④ 给组件绑定原生事件
  深入理解 Vue 组件——⑤ 非父子组件间的传值
  深入理解 Vue 组件——⑥ 在 Vue 中使用插槽
  深入理解 Vue 组件——⑦ 作用域插槽
  深入理解 Vue 组件——⑧ 动态组件与 v-once 指令
  Vue 中的动画特效——① Vue 中的 CSS 动画原理
  Vue 中的动画特效——② 在 Vue 中使用 Animate.css 库
  Vue 中的动画特效——③ 在 Vue 中同时使用过渡和动画
  Vue 中的动画特效——④ Vue 中的 JS 动画与 Velocity.js 的结合
  Vue 中的动画特效——⑤ Vue 中多个元素或组件的过渡
  Vue 中的动画特效——⑥ Vue 中的列表过渡
  Vue 中的动画特效——⑦ Vue 中的动画封装

一、《Vue 介绍——① Hello World》

涉及面试题:
1. Vue.js 是什么?
2. Vue.js 的主要功能是什么?

[编号:vue_01]

❗❗️❗️️P.s. 公众号对话框回复 vue_01、vue_02、web_01、html_01 或 css_01 查看参考答案样本~

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

1 如何在 div 里显示一个 Hello World 字符串

1.1 用原生 JS 实现

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>前端一万小时-Hello World</title>
  </head>
  <body>
    <div id="app"></div>
    
    <script>
      var dom = document.getElementById("app");
      dom.innerHTML = "Hello World"
    </script>
  </body>
</html>

Vue.js 理论基础 | 写给 Vue 初学者的理论实操教程,(我的风格)通俗易懂,跟完就可独立上手!

1.2 用 Vue.js 实现

1️⃣打开 Vue.js 官网,点击右上角“学习-教程”,完成 Vue.js 开发版本的安装(我们这里是把源代码下载到本地,然后进行引入)。 Vue.js 理论基础 | 写给 Vue 初学者的理论实操教程,(我的风格)通俗易懂,跟完就可独立上手!

项目目录结构: Vue.js 理论基础 | 写给 Vue 初学者的理论实操教程,(我的风格)通俗易懂,跟完就可独立上手!

2️⃣将现有的 index.html 中的原生 JS 代码删除,编写 Vue 的代码:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>前端一万小时-Hello World</title>

    <script src="./vue.js"></script> <!-- 2️⃣-①:从当前目录下引入 vue.js; -->

  </head>
  <body>
    <div id="app">

      {{content}} <!-- 2️⃣-⑥:用 {{}} 包裹 content,写在 #app 这个 div 里。 -->

    </div>

    <script>
      
      var app = new Vue({ // 2️⃣-②:创建一个 Vue 实例;

        el: '#app', // 2️⃣-③:这个实例接收的第一个参数 el,稍后会详细讲解它,暂时不管;

        data: { // 2️⃣-④:接收的第二个参数 data,它指的是数据;

          content: 'hello world' /*
          											 2️⃣-⑤:定义一个叫 content 的数据,内容是“hello world”,
          											 与原生的作区分。
                                  */

        }
      })
    </script>
  </body>
</html>

写完后保存,刷新网页可以看到我们使用 Vue.js 也展示出了“hello world”。 Vue.js 理论基础 | 写给 Vue 初学者的理论实操教程,(我的风格)通俗易懂,跟完就可独立上手!

现在来详细了解一下刚才写的这段 Vue 的代码:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>前端一万小时-Hello World</title>
    <script src="./vue.js"></script>
  </head>
  <body>
    
    <div id="app">{{content}}</div> <!-- 3️⃣content 数据中的内容在 DOM 元素中用
																	  插值表达式 “{{}}”来调用。 -->

    <script>

      var app = new Vue({ // ❗️创建一个名为 app 的实例,实例接收一些配置项:
        
        el: '#app', /*
        						1️⃣el 配置项限制了一个 Vue 实例负责管理的区域,
        						这里即让“app 实例”去接管 id 为 app 的 DOM 元素标签里的所有内容;
                     */
        
        data: { /*
        				2️⃣data 配置项定义了一些数据,
          			这里即定义了内容为 "hello world" 的数据 content;
                 */
          
          content: 'hello world'
        }
      })
    </script>
  </body>
</html>

❗️题外话

假如:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>前端一万小时-Hello World</title>
    <script src="./vue.js"></script>
  </head>
  <body>
    <div id="app">{{content}}</div>

    <div>{{content}}</div> <!-- ❗️再增加一个 div。
													 ❗️使用了 {{}} 调用 content 中的内容,但无 id! -->

    <script>
      var app = new Vue({
        el: '#app',
        data: {
          content: 'hello world'
        }
      })
    </script>
  </body>
</html>

保存后,刷新页面查看,发现页面上只显示了一个“hello world”和这个新 div 中的原内容“{{content}}”:

Vue.js 理论基础 | 写给 Vue 初学者的理论实操教程,(我的风格)通俗易懂,跟完就可独立上手!

❓为什么没有显示两个“hello world”?

答:因为 Vue 实例只接管了 el 所对应的 DOM 元素标签下的所有内容,而没有接管其他部分的内容,所以它只会替换 #app 所在 DOM 标签下的 {{content}} 内容。

2 如何在几秒后,更改 data 中数据的内容

2.1 用原生 JS

var dom = document.getElementById("app");
dom.innerHTML = "hello world"

setTimeout(function() {
  dom.innerHTML = "bye world"
}, 2000)

原生 JS 将“变动的数据”集中在对 DOM 的操作上。

2.2 用 Vue.js

var app = new Vue({
  el: "#app",
  
  data: { // 2️⃣-②:$data 可以理解为 data 后面的对象。
    content: "hello world"
  }
  
})

setTimeout(function() {

  app.$data.content = "bye world" // ❗️Vue 关注点在数据!
  																// 1️⃣app 指的是这个 Vue 实例;
                                  // 2️⃣-①:$data 是 data 的别名;

}, 2000)

Vue.js 将“变动的数据”集中在对其的管理上:数据的内容是什么,那么页面展示的就是什么。数据改变了,页面就会跟着变!

Vue.js 理论基础 | 写给 Vue 初学者的理论实操教程,(我的风格)通俗易懂,跟完就可独立上手!

祝好,qdywxs ♥ you!


二、 Vue 介绍——② 开发 TodoList(v-model、v-for、v-on)》

涉及面试题:
1. v-model 的使用?
2. v-on 可以监听多个方法吗?
3. 如何使用事件处理程序?
4. 如何实现双向绑定?
5. v-model 支持什么修饰符?

[编号:vue_02]

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

1 要实现的效果

我们要使用 Vue 实现一个简易的 TodoList:输入内容点击“添加”后,可以新增内容至列表中,同时清空输入框。

Vue.js 理论基础 | 写给 Vue 初学者的理论实操教程,(我的风格)通俗易懂,跟完就可独立上手!

2 Vue 中的循环

通过效果展示,我们知道其实要实现的内容不多,结构非常简单,只有一个 input 框、一个“添加”按钮和一个列表项。

打开编辑器,跟着我一步步来熟悉 Vue 的代码编写。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>前端一万小时-开发 TodoList</title>
    <script src="./vue.js"></script> <!-- 2️⃣引入 Vue.js 库; -->
  </head>
  <body>

    <!-- 1️⃣写出页面的结构; -->
    <div id="app">
      <input type="text">
      <button>添加</button>

      <ul> <!-- ❗️ul 中 li 标签的内容,实际应是根据数据循环显示出来的内容。 -->
        <li>Oli</li>
        <li>qdywxs</li>
      </ul>

    </div>

    <script>
      var app = new Vue({ // 3️⃣创建一个 Vue 的实例;
        el: '#app' // 4️⃣指定使用 Vue 接管 #app 的 DOM 区域;
      })
    </script>
  </body>
</html>

Vue.js 理论基础 | 写给 Vue 初学者的理论实操教程,(我的风格)通俗易懂,跟完就可独立上手!

❓Vue 中如何对列表进行循环?

答:Vue 中使用 v-for 指令将数组渲染成列表。

所以既然 li 标签的内容是数据,我们就将其定义在实例的 data 内:

<div id="app">
  <input type="text">
  <button>添加</button>

  <ul> <!-- ❗️当我们定义了 list 数据后,借助 v-for 指令把数据内容渲染在页面上! -->
    
    <li v-for="item in list">{{item}}</li> <!-- 3️⃣保留一个 li 标签,写上 v-for 指令;

																						3️⃣-①:item in list 指的是循环 data 里的
																						list 数据,循环的每一项放入 item;

																						3️⃣-②:li 标签内用 {{}} 调用 item,
																						即渲染 list 中的每一项内容。 -->
  </ul>

</div>

<script>
  var app = new Vue({
    el: '#app',
    
    data: { // 1️⃣data 是固定的写法,指的是这个 Vue 实例里具体的数据;
      
      list: ['Oli', 'qdywxs', '666'] // 2️⃣data 中定义 list 的数据,其中有三组内容;
    }
  })
</script>

保存后,刷新页面查看效果,三组内容都显示在了页面上: Vue.js 理论基础 | 写给 Vue 初学者的理论实操教程,(我的风格)通俗易懂,跟完就可独立上手!

3 Vue 中绑定事件

接下来我们给 button 绑定事件。

❓Vue 中如何绑定事件?

答:Vue 中使用 v-on 指令绑定事件。

<div id="app">
  <input type="text">

  <button v-on:click="handleBtnClick">添加</button> <!-- 1️⃣:在 button 标签写上 v-on 指令;

																										1️⃣-①:v-on 后面以冒号分隔监听的
																										DOM 事件 click;
																										
																										1️⃣-②:当点击“添加”按钮,即 click 事
																										件触发后执行 handleBtnClick 方法; -->

  <ul>
    <li v-for="item in list">{{item}}</li>
  </ul>
</div>

<script>
  var app = new Vue({
    el: '#app',
    data: {
      list: ['Oli', 'qdywxs', '666']
    },
    
    methods: { // ❗️Vue 中的方法都定义在实例的 methods 内,methods 中文即译为“方法”!

      handleBtnClick() { // 2️⃣我们在 handleBtnClick 方法中让它 alert 出“click”。
        alert('click')
      }
    }
  })
</script>

Vue.js 理论基础 | 写给 Vue 初学者的理论实操教程,(我的风格)通俗易懂,跟完就可独立上手!

我们再梳理一次 v-on 绑定事件的整个流程:因为我们在这个名为 app 的 Vue 实例中传入的 DOM 元素是 #app 这个 div,所以当点击它里面的“添加”按钮要执行 handleBtnClick 方法时,Vue 会自动到实例的 methods 中找到 handleBtnClick 这个方法并执行,最终页面弹出“click”。

4 Vue 中的双向绑定数据

搞定了事件绑定,我们就可以让 input 框里输入的内容在点击按钮后,显示在列表里了。

❓在点击按钮后,如何拿到 input 框里输入的内容?

答:使用 Vue 中的指令 v-model 实现双向数据绑定(即当 input 框里的内容发生变化时,Vue 实例中 data 的 inputValue 就会发生变化,反之亦然)。

    <div id="app">

      <input type="text" v-model="inputValue"> <!-- 1️⃣在 input 上写 v-model 指令,
												它等于 inputValue 这个数据; -->

      <button v-on:click="handleBtnClick">添加</button>
      <ul>
        <li v-for="item in list">{{item}}</li>
      </ul>
    </div>

    <script>
      var app = new Vue({
        el: '#app',
        data: {

          list: [], // ❗️将 list 里的内容清除,默认为空数组!

          inputValue: '' // 2️⃣把数据 inputValue 写入 data 内,默认为空字符串;
        },

        methods: {
          handleBtnClick() {
            
            // 3️⃣通过 push 把 input 框里的内容放入 list 中;
            this.list.push(this.inputValue)

            // 4️⃣当输入内容放入 list 后,让 inputValue 为空,清空输入框里的内容。
            this.inputValue = '' 
          }
        }
      })
    </script>

v-model 负责监听用户的输入事件以更新数据 inputValue 。当数据更新后,通过 this.inputValue 获取输入的内容放入 list 中。与此同时让 inputValue 变为空字符串,以清空输入框。

Vue.js 理论基础 | 写给 Vue 初学者的理论实操教程,(我的风格)通俗易懂,跟完就可独立上手!

祝好,qdywxs ♥ you!


三、《Vue 介绍——③ MVVM 模式》

涉及面试题:
1. 什么是 MVVM?比之 MVC 有什么区别?
2. Vue 的优点?
3. 渐进式框架的理解?
4. 三大框架的对比?

[编号:vue_03]

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

MVVM 设计模式

Vue.js 理论基础 | 写给 Vue 初学者的理论实操教程,(我的风格)通俗易懂,跟完就可独立上手!

Vue 是 MVVM 模式的框架。

当我们使用 MVVM 这种模式的框架进行编码的时候,我们不需要关注 VM 这一层到底是怎么实现的,它是 Vue 内置的。我们只需要关注“ M 层”和“ V 层”。 对 MVVM 这种模式进行编码的时候,编码的重点在于“视图层”和“模型层”。

  • View:视图层,负责显示数据。 会监听数据、事件的触发(主要是 Vue 的指令)。
<div id="app">
  <input type="text" v-model="inputValue">
  <button v-on:click="handleBtnClick">添加</button>
  <ul>
    <li v-for="item in list">{{item}}</li>
  </ul>
</div>
  • Model:数据层,负责存储数据。 在 Vue 中,我们主要在写数据。

     💡 【重点关注这一层】——面向数据开发。

<script>
  var app = new Vue({
    el: '#app',
    data: {
      list: [],
      inputValue: ''
    },
    methods: {
      handleBtnClick() {
        this.list.push(this.inputValue) // 1️⃣实现了当点击时,把获取到的输入内容这个数据放入列表中;
        this.inputValue = '' // 2️⃣通过改变 inputValue 数据,实现了清空输入框的功能。
      }
    }
  })
</script>
  • ViewModel: 这是 Vue 自带的一层,不需要我们编写。它将 View 层和 Model 层连接起来,当视图层变化时,数据层也跟着变化,反之亦然。这其中 ViewModel 带动其视图和数据的变化。

🏆总结: Vue.js 理论基础 | 写给 Vue 初学者的理论实操教程,(我的风格)通俗易懂,跟完就可独立上手!

  • Vue (即 ViewModel 层)会监听到你数据变了,它会帮你去改变视图层;
  • Vue 也会监听到视图层有一些事件触发,然后帮助你通过 VM 这一层去调用你写的一些逻辑代码,通过这些代码,你又改变了 M 层的“数据”。当“数据”发生变化的时候,VM 层又会自动地把“数据”的变化映射到“视图层”上面来。

🏆这样的话有一个好处: 当我们使用 Vue 这种 MVVM 框架进行开发的时候,我们只需要去关注“ M 层”的开发就可以了!我们把“数据”做一个修改,页面会自动地跟着变。同时,页面上的变化,Vue 实例也能感知到,可以方便地帮我们去操作数据。

祝好,qdywxs ♥ you!


四、《Vue 介绍——④ 使用组件改造 TodoList》

涉及面试题:
1. 引进组件的步骤?
2. 组件是什么并给个例子?
3. 组件中的全局注册是什么?
4. 为什么你需要局部注册?
5. 局部注册和全局注册在模块系统中有什么区别?

[编号:vue_04]

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

1 前端组件化

组件,是页面的一个部分。也就是可以把一个页面,由原来一个整体,切分成一个一个的部分,每个部分都可称之为组件

Vue.js 理论基础 | 写给 Vue 初学者的理论实操教程,(我的风格)通俗易懂,跟完就可独立上手!

比如上图中,一号轮播可以是组件,二号分类区域可以是组件,三号榜单可以是组件,甚至四号城市切换区域也可以是个小组件。

合理地拆分组件,可以将一个大型的项目像拼积木一样拼接起来。一个大型项目,业务逻辑可能非常复杂,但当被拆分成一个个组件时,每个组件都会变得精小,这些小的组件维护起来也会相对更容易。

真实的项目中,使用组件化进行大型项目的开发,会使得代码在后续的维护性上得到极大的提高。每一个组件其实就是页面上的一个区域

前面,我们实现了一个简易的 TodoList:输入内容,可以将内容添加至列表内。这里的每个列表项其实也是页面的一个部分,所以我们可以把这个列表项拆分为一个组件。 Vue.js 理论基础 | 写给 Vue 初学者的理论实操教程,(我的风格)通俗易懂,跟完就可独立上手!

2 全局组件实现“列表”组件化

🚀需求:将 TodoList 中的列表封装成一个组件。

<div id="app">
  <input type="text" v-model="inputValue">
  <button v-on:click="handleBtnClick">添加</button>
  <ul>
    
    <li v-for="item in list">{{item}}</li> <!-- ❗️之前的列表项是通过循环 li 标签来显示的! -->
 
  </ul>
</div>

❓Vue 中如何把 li 标签的内容整体变为组件?

答:可以使用 Vue 中的 Vue.component 方法创建全局组件

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

    <todo-item v-for="item in list"></todo-item> <!--4️⃣在页面上使用组件替代原有的 li 标签;
                                                  4️⃣-①:组件名全小写,第二个单词前用 - 隔开;
                                                  4️⃣-②:v-for 循环添加在组件标签上,
                                                  即每次添加都让它向列表内增加一项内容。
                                                  -->

  </ul>
</div>

<script>

  // 1️⃣在 script 标签中注册全局组件;
  Vue.component('TodoItem', { /*
  														2️⃣Vue.component 方法的第一个参数为组件名“TodoItem”,
                              组件名一般首字母大写;
                               */

    template: '<li>hello qdywxs</li>' /*
    																	3️⃣第二个为组件的 template 模板项,
    																	这里添加一个 li 标签,内容暂时为“hello qdywxs”;
                                       */
  })

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

❗️注意:注册全局组件时,我们组件名定义为 TodoItem ,使用组件时可以当成小写 todo-item 。第二个词的大写字母换为小写时,前面需加上 - 。

保存,刷新页面查看效果,这里发现一个问题:当输入内容点击“添加”后,列表出现了,但是内容却都是我们写在模板中的内容 hello qdywxs

Vue.js 理论基础 | 写给 Vue 初学者的理论实操教程,(我的风格)通俗易懂,跟完就可独立上手!

❓组件中如何让输入的内容显示在列表里?

答:如果想让子组件显示输入的内容,则需要把内容传递给子组件。

<div id="app">
  <input type="text" v-model="inputValue">
  <button v-on:click="handleBtnClick">添加</button>
  <ul>
		
    <!--  1️⃣在组件上使用 v-bind 指令绑定 content;
		❗️这里整个意思是:在循环 list 数组时,每一项值赋值给 item,然后再把 item 的内容通过 v-bind 
		指令绑定给属性 content,传给 todo-item 这个子组件; -->
    <todo-item v-bind:content="item" v-for="item in list"></todo-item>

  </ul>
</div>

<script>
  Vue.component('TodoItem', {
    
    props: ['content'], // 2️⃣子组件内通过 props 来接收父组件的内容,即接收 content;
    
    template: '<li>{{content}}</li>' /*
    																 3️⃣在 template 的 li 标签内使用插值表达式
    																 显示 content 内容。
                                      */
  })

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

再次查看效果,没有问题了:

Vue.js 理论基础 | 写给 Vue 初学者的理论实操教程,(我的风格)通俗易懂,跟完就可独立上手!

这样就完成了“列表”组件化,我们再来梳理一遍逻辑:

  1. 定义了一个全局组件“TodoItem”,可以直接在模板里使用它( todo-item );
  2. 通过循环 list 来决定输出多少个 todo-item 组件;
  3. 同时,父组件把每一项内容 item 通过 v-bind 指令借助 content 变量传给 todo-item 子组件;
  4. todo-item 子组件中,若要使用父组件传递的数据 content ,则一定要在 props 属性里进行接收;
  5. 接收后, template 的模板里用 {{}} 包裹 content
  6. 最终页面上渲染出内容。

3 局部组件实现“列表”组件化

在 Vue 中,除了全局组件的方式来实现列表组件化,还可以使用“局部组件”来实现。

<script>

  var TodoItem = { // 1️⃣定义 TodoItem 组件,props 接收 content 并将其写入模板;
    props: ['content'],
    template: '<li>{{content}}</li>'
  }

  var app = new Vue({
    el: '#app',

    components: { // ❗️把局部组件注册到根实例里的 components,通常用“对象 {}”来注册!

      TodoItem: TodoItem /*
      									 2️⃣注册 TodoItem 组件到 Vue 实例里,并且在这个实例内,
      									 它还是名为 TodoItem。
                          */
    },
    data: {
      list: [],
      inputValue: ''
    },
    methods: {
      handleBtnClick() {
        this.list.push(this.inputValue)
        this.inputValue = ''
      }
    }
  })
</script>

Vue.js 理论基础 | 写给 Vue 初学者的理论实操教程,(我的风格)通俗易懂,跟完就可独立上手!

4 总结

这一篇我们初步认识了组件,包括 Vue 中“局部组件”和“全局组件”的使用。

组件就是把页面上的一些内容进行封装。 比如关于 li 标签里的所有逻辑,都封装在了 TodoItem 这个小的组件中。小组件有自己的 propstemplate

  • props :若要接收外部传递过来的数据,需定义在这里;
  • template :指子组件的模板。页面内的组件标签会被子组件里的模板替换。

祝好,qdywxs ♥ you!


五、《Vue 介绍——⑤ 简单的组件间传值》

涉及面试题:
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.js 理论基础 | 写给 Vue 初学者的理论实操教程,(我的风格)通俗易懂,跟完就可独立上手!

这是因为当 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.js 理论基础 | 写给 Vue 初学者的理论实操教程,(我的风格)通俗易懂,跟完就可独立上手!

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

再简述一次此实现流程:

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

祝好,qdywxs ♥ you!


🔥🔥🔥篇幅原因,后续文章详情请在「公众号 | 前端一万小时」内查看。

六、《Vue 基础精讲——① Vue 实例》

涉及面试题:
1. Vue 实例是什么?
2. 如何访问根实例?
3. 如何访问父实例?

[编号:vue_06]

七、《Vue 基础精讲——② Vue 实例生命周期》

涉及面试题:
1. Vue 生命周期的作用是什么?
2. 什么是 Vue 生命周期?
3. 第一次页面加载会触发哪几个钩子?
4. 简述每个周期具体适合哪些场景?
5. created 和 mounted 的区别?
6. Vue 获取数据在哪个周期函数?
7. $nextTick 的使用?

[编号:vue_07]

八、《Vue 基础精讲——③ Vue 的模板语法》

九、《Vue 基础精讲——④ 计算属性、方法与侦听器》

涉及面试题:
computed 计算属性的用法?与 watch、methods 的区别?分别简述 computed 和 watch 的使用场景?

[编号:vue_09]

十、《Vue 基础精讲——⑤ 计算属性的 getter 和 setter》

涉及面试题:
Vue.set 视图更新?

[编号:vue_10]

十一、《Vue 基础精讲——⑥ Vue 中的样式绑定》

涉及面试题:
如何让 CSS 只在当前组件中起作用?

[编号:vue_11]

十二、《Vue 基础精讲——⑦ Vue 中的条件渲染》

涉及面试题:
1. v-show 和 v-if 指令的共同点和不同点?
2. v-if 和 v-for 的优先级?
3. 条件指令是什么?

[编号:vue_12]

十三、《Vue 基础精讲——⑧ Vue 中的列表渲染》

涉及面试题:
 1. 说出几种 Vue 当中的指令和它的用法?
 2. 为什么使用 key?
 3. 列举常用的指令?
 4. v-for 指令的目的是什么?
 5. 如何复用有 key 属性的元素?
 6. 为什么不能在同一个元素上同时使用 v-if 和 v-for 指令?
 7. 为什么使用 for 指令时需要 key 属性?
 8. 如何在一个范围内使用 v-for 指令?
 9. 如何在模板上使用 v-for 指令?
10. 什么是数组检测突变的方法?
11. 什么是数组检测非突变方法?
12. 检测数组变化有什么注意事项?
13. 检测对象变化有什么注意事项?

[编号:vue_13]

十四、《深入理解 Vue 组件——① 使用组件的细节点》

涉及面试题:
1. Vue 组件中 data 为什么必须是一个函数?
2. Vue 的两个核心点?
3. 如何获取 DOM?

[编号:vue_14]

十五、《深入理解 Vue 组件——② 父子组件间的数据传递》

涉及面试题:
1. Vue 父组件向子组件传递数据?
2. 子组件像父组件传递事件?
3. 跨组件双向数据绑定?
4. 什么是可接受的 prop 类型?
5. props 后面的数据流是什么?
6. 什么是非 prop 属性?
7. props 有哪些可用的验证?

[编号:vue_15]

十六、《深入理解 Vue 组件——③ 组件参数校验与非 props 特性》

十七、《深入理解 Vue 组件——④ 给组件绑定原生事件》

十八、《深入理解 Vue 组件——⑤ 非父子组件间的传值》

涉及面试题:
组件间的通信?

[编号:vue_18]

十九、《深入理解 Vue 组件——⑥ 在 Vue 中使用插槽》

涉及面试题:
什么是 slot?

[编号:vue_19]

二十、《深入理解 Vue 组件——⑦ 作用域插槽》

廿一、《深入理解 Vue 组件——⑧ 动态组件与 v-once 指令》

涉及面试题:
什么是动态组件?

[编号:vue_21]

廿二、《Vue 中的动画特效——① Vue 中的 CSS 动画原理》

廿三、《Vue 中的动画特效——② 在 Vue 中使用 Animate.css 库》

廿四、《Vue 中的动画特效——③ 在 Vue 中同时使用过渡和动画》

廿五、《Vue 中的动画特效——④ Vue 中的 JS 动画与 Velocity.js 的结合》

涉及面试题:
提供 transitions 有什么可能的方式?

[编号:vue_25]

廿六、《Vue 中的动画特效——⑤ Vue 中多个元素或组件的过渡》

廿七、《Vue 中的动画特效——⑥ Vue 中的列表过渡》

廿八、《Vue 中的动画特效——⑦ Vue 中的动画封装》