vue极速入门总结

环境准备

#1 准备 Node 环境

由于大部分 Vue 项目都是依赖于 Node 环境. 在开始之前, 我们需要先准备好 Node 环境

访问Node 中文官网 (opens new window)下载最新版的Node.js

找到下载的 node-v12.16.1-x64.msi, 双击安装

一路Next, 到安装完成.

安装完成后, 按win+R键打开 cmd 命令窗口

在 windows 命令行中, 使用如下命令测试

# 查看node的版本
node -v

# 查看npm的版本
npm -v

node 是一个 js 的运行环境, 这里我们安装 node 主要是需要其中的 npm 包管理工具

这里, 我的电脑上 node 的版本不是最新的, 是10.16.3的版本.

如果大家按下载的版本安装, 应该是更新的版本

#2 配置 npm 镜像

npm 默认的仓库地址是在国外网站,速度较慢,建议大家设置到淘宝镜像。但是切换镜像是比较麻烦的。推荐一款切换镜像的工具:nrm

我们首先安装 nrm,这里-g代表全局安装

npm install nrm -g

全局安装后, 会在如下目录, 产生如下文件

然后, 我们就可以使用 nrm 命令了

通过nrm ls命令查看 npm 的仓库列表,带*的就是当前选中的镜像仓库:

通过nrm use taobao来指定要使用的镜像源:

注意

有教程推荐大家使用 cnpm 命令,但是我使用发现 cnpm 有时会有 bug,不推荐

#3 创建项目

在 D 盘, 新建一个文件夹 ==code== . 打开, 按住shift+鼠标右键, 打开 powerShell 窗口

注意

路径中不要出现中文

#4 初始化

使用如下指令初始化

npm init -y

发现在目录下会多一个文件 package.json, 这个文件用来管理该项目使用了哪些包

#5 安装 vue

执行如下命令安装 vue

npm install vue --save

以上命令可以简写为

npm i vue

在项目目录会产生一个文件夹 node_modules 和一个文件 package-lock.json

在 package.json 文件中, 会多如下内容

在 node_modules 里就是 vue 了

#6 小结

总结

使用 Npm 安装 Vue 分为两步

  1. 项目初始化: npm init -y
  2. 安装 vue: npm install vue

=====================

 起步案例

做为第一个案例, 主要给大家介绍 vue 的最基本使用.

vue 使用的 3 步曲

  1. 引入 vue.js
  2. 编写页面(视图)
  3. 编写 vue 实例

#1 引入 vue.js

在 html 的头部, 通过<script src>引入 vue.js

这里我用到了 VSCode 插件: Path Intellisense 快速补全路径

示例

<!-- 1. 引入vue.js -->
<script src="../node_modules/vue/dist/vue.js"></script>

演示

#2 编写页面(视图)

在 boby 中, 编写一个div元素, id 为 app, 所有视图部分将在这部分渲染

示例

<!-- 2. 编写页面 -->
<div id="app"></div>

演示

#3 编写 vue 实例

在 body 的最末尾, 使用<script>, 编写 vue 实例

示例

<!-- 3. 编写vue实例 -->
<script>
  const vm = new Vue({
    el: '#app', // 对应操作的元素, 必填参数
    data: {}, // 数据部分
    methods: {}, // 方法部分
  })
</script>

  • el(element 元素): 表示 vue 实例操作页面元素
  • data(数据): 数据部分
  • methods(方法): 方法部分

演示

#4 渲染数据

需求

将数据渲染到页面中

#1) 定义数据

在 data 中定义数据

示例

<!-- 3. 编写vue实例 -->
<script>
  const vm = new Vue({
    el: '#app', // 对应操作区的元素, 必填参数
    data: {
      msg: 'hello world',
    }, // 数据部分
    methods: {}, // 方法部分
  })
</script>

使用键值对方式定义数据. 其中

  • msg: 相当于变量名
  • 'hello world': 相当于变量值

演示

#2) 在页面中渲染

示例

<div id="app">
  {
   
   { msg }}
</div>

  • 通过{ {}}(插值表达式)使用在 data 部分定义的变量

演示

======================================

MVVM模型

MVVM 由 Model(数据模型) View(视图) 和 VM(ViewModel) 组成

核心思想

实现 数据 与 视图 的 双向绑定

各自的作用

  • Model(数据模型): 操作数据
  • View(视图): 显示数据
  • VM: 模型与视图间的双向操作

在 MVVM 之前, 开发人员需要从后端获取数据, 然后通过 DOM 操作 Model 渲染到 View 中.

当用户操作了视图, 再通过 DOM 获取 View 中的数据, 同步到 Model 中

而 VM 的作用就是把 DOM 操作完全的封装起来, 开发人员不用再关心 Model 和 View 之间如何影响

  • 只要 Model 发生改变, View 就可以自然的表现出来
  • 只要用户操作了 ViewModel 中的数据也会跟着变化

案例

实现如下效果, 当在输入框中输入字符时, 同步显示到页面中

#1 完成 Vue 的三步曲

在 src 目录下创建一个新的文件: 02_MVVM模型.html

#1) 引入 vue.js

示例

<!-- 1. 引入vue.js -->
<script src="../node_modules/vue/dist/vue.js"></script>

演示

#2) 编写 div 元素

示例

<!-- 2. 编写div元素 -->
<div id="app"></div>

演示

#3) 编写 vue 实例

示例

<!-- 3. 编写vue实例 -->
<script>
  const vm = new Vue({
    el: '#app',
    data: {},
  })
</script>

演示

#2 编写页面

分析

页面由文字, input 框, 内容显示三部分组成

示例

<!-- 2. vue的主操作区 -->
<div id="app">
    在这里输入的内容会在下面显示: <input v-model="msg" type="text">
    <h3>{
   
   { msg }}</h3>
</div>

  • v-model 表示双向绑定, 将输入框中的内容和 vue 实例中的 msg 属性绑定
  • { {}}是插值表达式, 用来显示 msg 的数据

#3 编写逻辑

这里的逻辑比较简单, 只需要在 data 部分, 添加一个msg变量就可以

示例

<script>
  const vm = new Vue({
    el: '#app',
    data: {
      msg: '',
    },
  })
</script>

#4 测试

使用 Open In Default Browser 测试(使用到的插件: open in browser)

#5 调试工具

为了方便调试 vue, 可以在 chrome 浏览器中安装 vue-devtools.

#6 小结

小结

  1. vue 使用的三步曲(引入 vue.js div 元素 vue 实例)
  2. data 中的内容就是 M(模型), div 中的内容是 V(视图), vue 实例是 VM

============================

Vue实例

#1 属性和方法

Vue 应用的核心就是 Vue 实例 , 一个基本的 Vue 实例包括如下图所示:

new Vue({
  el: '#app',
  data: {},
  methods: {},
})

  • el: 表示要操作的页面元素
  • data: 数据, 可以理解为面向对象中类的"属性"
  • methods: 方法, 可以理解为面向对象中类的"方法"

属性

当 Vue 实例创建时, 会获取 data 中的数据, 并渲染到视图中, 并监视 data 中数据的变化, 当 data 中的数据改变时, 重新渲染视图

方法

方法就是: 响应视图中的事件, 并修改 data 里的数据

重要结论

  • 属性就是用来 保存 数据的
  • 方法就是用来 修改 数据的

案例

实现一个简单的加法器

两个输入框,填写两个数字, 点击=号时, 计算结果

#1) 完成 Vue 的三步曲

在 src 目录下创建03_加法器.html

示例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>03_加法器</title>
    <!-- 1. 引入vue.js -->
    <script src="../node_modules/vue/dist/vue.js"></script>
  </head>
  <body>
    <!-- 2. 编写div元素 -->
    <div id="app"></div>
    <!-- 3. 编写vue实例 -->
    <script>
      const vm = new Vue({
        el: '#app',
      })
    </script>
  </body>
</html>

#2) 编写页面

分析

页面由两个 input 框和一个按钮, 再加一个 input 框组成

示例

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

#3) 编写逻辑

#i 绑定属性

html 部分

<div id="app">
  <input v-model="first" type="text" />
  +
  <input v-model="second" type="text" />
  <button>=</button>
  <input v-model="result" type="text" />
</div>

使用 v-model 绑定属性

js 部分

const vm = new Vue({
  el: '#app', // 元素
  data: {
    first: 0,
    second: 0,
    result: 0,
  }, // 属性
  methods: {}, // 方法
})

#ii 绑定方法

html 部分

<button v-on:click="add">=</button>

使用 v-on 绑定 click 方法

js 部分

 methods: {
     add() {
         this.result = parseInt(this.first) + parseInt(this.second)
     }
 } // 方法

4) 小结

小结

  • data: 保存 数据
  • methods: 改变 数据

=========================

模板语法

模板语法主要用于视图的编写,以v-指令. 常见的有

  • 属性绑定: v-bind, 简写为:
  • 方法绑定: v-on, 简写为@
  • 双向绑定: v-model
  • 条件渲染: v-if
  • 列表渲染: v-for

#1 属性绑定和双向绑定

在 src 目录下, 创建04_属性绑定.html, 完成 vue 的 3 步曲

示例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>04_属性绑定</title>
    <!-- 1. 引入vue.js -->
    <script src="../node_modules/vue/dist/vue.js"></script>
  </head>
  <body>
    <!-- 2. 编写div元素 -->
    <div id="app"></div>
    <!-- 3. 编写vue实例 -->
    <script>
      const vm = new Vue({
        el: '#app',
      })
    </script>
  </body>
</html>

属性绑定

将 非表单标签 的一个属性和 data 中的一个变量绑定

html 部分

<a :href="url"></a>

js 部分

const vm = new Vue({
  el: '#app',
  data: {
    url: 'http://baidu.com',
  },
})

  • 将 a 标签href属性和 data 中的 url 变量绑定
  • 相当于<a href="http://baidu.com"></a>

双向绑定

将 表单标签 的 value 值和 data 中的变量双向绑定

html 部分

<input type="text" v-model="uName" />

js 部分

const vm = new Vue({
  el: '#app',
  data: {
    uName: 'xiaoming',
  },
})

1
2
3
4
5
6

  • 将 input 标签的 value 属性和 data 中的 uName 变量绑定
  • 相当于<input type="text" value="xiaoming" />

#2 条件渲染

条件渲染

当条件满足时, 渲染到页面

主要指令: v-ifv-show

#1) 完成 vue 的 3 步曲

在 src 目录下, 创建05_条件渲染.html, 编写 vue 的基础模板

示例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>05_条件渲染</title>
    <!-- 1. 引入vue.js -->
    <script src="../node_modules/vue/dist/vue.js"></script>
  </head>
  <body>
    <!-- 2. 编写div元素 -->
    <div id="app"></div>
    <!-- 3. 编写vue实例 -->
    <script>
      const vm = new Vue({
        el: '#app',
      })
    </script>
  </body>
</html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

#2) 编写页面与逻辑

示例

html 部分

<!-- 2. 编写div元素 -->
<div id="app">
  <div v-if="flag">这是用v-if渲染的元素</div>
  <div v-show="flag">这是用v-show渲染的元素</div>
</div>

1
2
3
4
5

js 部分




 




 

<script>
  const vm = new Vue({
    el: '#app',
    data: {
      flag: true,
    },
  })
</script>

1
2
3
4
5
6
7
8

  • 当 flag 为 true 时, 两个元素都可以显示
  • 当 flag 为 false 时, 两个元素都不显示, 区别
    • v-if: 不会创建元素
    • v-show: 创建元素, 但是 display=none

#3) 表达式

除了使用变量外, 还可以使用表达式

比如

<div v-if="flag == true">这是用v-if渲染的元素</div>

1

案例

通过按钮控制元素的显示/隐藏

示例

html 部分

<div id="app">
  <button @click="flag = !flag">切换</button>
  <div v-if="flag">这是用v-if渲染的元素</div>
  <div v-show="flag">这是用v-show渲染的元素</div>
</div>

1
2
3
4
5

  • 绑定按钮的点击事件
    • 当 flag==true 时点击, flag 先取反, 再保存, 此时 flag 为 false
    • 当 flag==false 时点击, flag 先取反, 再保存, 此时 flag 为 true

#3 列表渲染

列表渲染也称"循环渲染", 通过v-for遍历数组或者对象

#1) 遍历数组

如果只希望得到每个数组元素的值, 不需要得到下标

语法

v-for="item in items"

1

示例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>06_列表渲染</title>
    <!-- 1. 引入vue.js -->
    <script src="../node_modules/vue/dist/vue.js"></script>
  </head>
  <body>
    <!-- 2. 编写div元素 -->
    <div id="app">
      <ul>
        <li v-for="item in items">{
   
   { item }}</li>
      </ul>
    </div>
    <!-- 3. 编写vue实例 -->
    <script>
      const vm = new Vue({
        el: '#app',
        data: {
          items: ['test1', 'test2', 'test3'],
        },
      })
    </script>
  </body>
</html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

如果只希望得到每个数组元素的值和下标

语法

v-for="(item, index) in items"

1

示例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>06_列表渲染</title>
    <!-- 1. 引入vue.js -->
    <script src="../node_modules/vue/dist/vue.js"></script>
  </head>
  <body>
    <!-- 2. 编写div元素 -->
    <div id="app">
      <ul>
        <li v-for="(item, index) in items">{
   
   { index }}--{
   
   { item }}</li>
      </ul>
    </div>
    <!-- 3. 编写vue实例 -->
    <script>
      const vm = new Vue({
        el: '#app',
        data: {
          items: ['test1', 'test2', 'test3'],
        },
      })
    </script>
  </body>
</html>

#2) 遍历对象

  • 只取值: v-for="value in obj"
  • 取键和值: v-for="(value, key) in obj"
  • 取键和值和索引: v-for="(value, key, index) in obj"

 ===========================

计算属性与侦听器

#1 计算属性

计算属性用于对原始数据的再次加工

需求

实现如下效果

#1) 完成 Vue 的三步曲

在 src 目录下创建07_计算属性.html, 编写基础的 vue 模板

示例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>07_计算属性</title>
    <!-- 1. 引入vue.js -->
    <script src="../node_modules/vue/dist/vue.js"></script>
  </head>
  <body>
    <!-- 2. 编写div元素 -->
    <div id="app"></div>
    <!-- 3. 编写vue实例 -->
    <script>
      const vm = new Vue({
        el: '#app',
      })
    </script>
  </body>
</html>

#2) 使用传统方式

分析

页面由一个输入框和一个提示组成

示例

html 部分

<!-- 2. 编写div元素 -->
<div id="app">
  输入金额:
  <input type="text" v-model="total" />
  <h3>您一共消费了{
   
   { total }}元</h3>
</div>

js 部分

<!-- 3. 编写vue实例 -->
<script>
  const vm = new Vue({
    el: '#app',
    data: {
      total: 0,
    },
  })
</script>

#3) 使用计算属性

示例

html 部分

<!-- 2. 编写div元素 -->
<div id="app">
  输入金额:
  <input type="text" v-model="total" />
  <h3>{
   
   { msg }}</h3>
</div>

js 部分

<!-- 3. 编写vue实例 -->
<script>
  const vm = new Vue({
    el: '#app',
    data: {
      total: 0,
    },
    computed: {
      msg() {
        return `您一共消费了${this.total}元`
      },
    },
  })
</script>

#4) 小结

举个极端的案例, 我们写了一万个页面, 您一共消费了元这段代码就要写一万次

如果, 突然有一天, 需求改变了, 提示信息是: 您本次消费xx元, 那么就要修改一万次

设计原则

视图业务无关性原则: 尽量将视图显示和业务处理解耦

#2 侦听器

侦听器用于侦听数据的改变, 进而自动触发相应的方法

需求

实现如下效果:

![05_watch](http://image.brojie.cn// images05_watch.gif)

#1) 完成 Vue 的三步曲

在 src 目录下创建08_侦听器.html, 编写基础的 vue 模板

示例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>08_侦听器</title>
    <!-- 1. 引入vue.js -->
    <script src="../node_modules/vue/dist/vue.js"></script>
  </head>
  <body>
    <!-- 2. 编写div元素 -->
    <div id="app"></div>
    <!-- 3. 编写vue实例 -->
    <script>
      const vm = new Vue({
        el: '#app',
      })
    </script>
  </body>
</html>


 

#2) 使用侦听器实现

示例

html 部分

<!-- 2. 编写div元素 -->
<div id="app">
  单价:10元
  <br />
  数量:
  <input type="text" v-model="number" />
  <h3>总价: {
   
   { total }}元</h3>
</div>

js 部分

<!-- 3. 编写vue实例 -->
<script>
  const vm = new Vue({
    el: '#app',
    data: {
      number: 0,
      total: 0,
    },
    watch: {
      number() {
        this.total = 10 * this.number
      },
    },
  })
</script>


 

watch: {
  // 监听data中已经存在的变量, 在watch中写的函数跟变量是同名
  // 是一对多, 当变量值发生改变时, 执行一系列的操作
  number(newValue, oldValue) {
    // number被改变, 就会执行对应watch函数

    // 操作一: 计算total的值
    this.total = this.number * 10
    // 操作二: 可以记录旧的值, 新的值
    console.log(newValue, oldValue)
},

#3) 使用计算属性实现

示例

html 部分

<!-- 2. 编写div元素 -->
<div id="app">
  单价:10元
  <br />
  数量:
  <input type="text" v-model="number" />
  <h3>总价: {
   
   { total }}元</h3>
</div>

js 部分

<!-- 3. 编写vue实例 -->
<script>
  const vm = new Vue({
    el: '#app',
    data: {
      number: 0,
    },
    computed: {
      total() {
        return this.number * 10
      },
    },
  })
</script

#3 总结

两者的区别:

  1. 计算属性用于对原始数据的再次加工, 计算属性是有缓存的. 相当于在 vue 实例中添加了一个新的属性, 可以同时依赖多个值, 只要其中依赖的一个值发生改变就会重新计算
  2. 侦听器用于侦听数据的改变, 进而自动触发相应的方法. 不会缓存, 每次重新计算, 可以获取新旧数据, 主要用于一个值的改变引起的一系列的操作

#4 过滤器

对数据进行格式化操作

#1) 完成 vue 的三步曲

<!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>Document</title>
    <script src="../node_modules/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app"></div>

    <script>
      const vm = new Vue({
        el: '#app',
      })
    </script>
  </body>
</html>

#2) 定义过滤器

过滤器分为

  • 全局过滤器
  • 局部过滤器

全局过滤器

可以所有的 vue 实例中使用

局部过滤器

只能在某一个 vue 实例中使用

示例

<!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>Document</title>
    <script src="../node_modules/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">{
   
   {price | priceFormat}}</div>

    <script>
      const vm = new Vue({
        el: '#app',
        data: {
          price: 88,
        },
        filters: {
          // 格式化价格. 保留两位小数, 前面加¥
          // 88 -> ¥88.00
          priceFormat(value) {
            return '¥' + value.toFixed(2)
          },
        },
      })
    </script>
  </body>
</html>

作业

实现如下效果

=============================

组件

组件可以理解成项目的零件

一个 项目 就是由多个 组件 构成的

举例

一个房子是一个 Vue 应用, 那么客厅/卧室/厨房/卫生间就是组件

一个电脑是一个 Vue 应用, 那么硬盘/内存/主板/显示器/键盘就是组件

组件分为

  • 全局组件
  • 局部组件

#1 全局组件

顾名思义, 全局都可以使用的组件

#1) 完成 Vue 三步曲

在 src 目录下创建09_全局组件.html, 编写基础的 vue 模板

示例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>09_全局组件</title>
    <!-- 1. 引入vue.js -->
    <script src="../node_modules/vue/dist/vue.js"></script>
  </head>
  <body>
    <!-- 2. 编写div元素 -->
    <div id="app"></div>
    <!-- 3. 编写vue实例 -->
    <script>
      const vm = new Vue({
        el: '#app',
      })
    </script>
  </body>
</html>

#2) 定义全局组件

语法

Vue.component('组件名', { 组件参数 })

示例

Vue.component('com1', {
  template: '<button @click="count++">你点了我{
   
   {count}}次</button>',
  data() {
    return {
      count: 0,
    }
  },
})
  • 组件没有 el 参数, 原因是组件不会和具体的页面元素绑定
  • 组件必须有 template 参数, 原因是组件需要渲染页面, template 就是需要渲染的 html
  • 组件也是一个 Vue 的实例, 所以在组件中也有 data/methods 等
  • data 必须是一个函数, 并返回一个对象

#3) 引用组件

在 html 中, 通过组件名引用组件

<!-- 2. 编写div元素 -->
<div id="app">
  <!-- 引用组件 -->
  <com1></com1>
  <com1></com1>
  <com1></com1>
</div>

我们发现每个组件互不干扰,都有自己的 count 值。怎么实现的?

重点

组件中的 data 属性必须是函数

当我们定义这个 <com1> 组件时,它的 data 并不是像这样直接提供一个对象:

data: {
  count: 0
}

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

data: function () {
  return {
    count: 0
  }
}

如果 Vue 没有这条规则,点击一个按钮就会影响到其它所有实例!

#4) 全局使用

创建一个新的 vue 实例 vm2

const vm2 = new Vue({
  el: '#app2',
})

创建新的 div 元素 app2

html

<div id="app2">
  <com1></com1>
</div>

发现在 app2 中, 也可以引用 com1 组件, 这样定义的就是全局组件, 所有的 vm 实例都可以引用

#5) 小结

全局组件的使用步骤

  1. 定义组件
  2. 引用组件

#2 局部组件

一般在单页面应用(SPA)中使用较多的是局部组件

注意

局部组件只属于某一个 Vue 实例, 通过 comopnents 添加(挂载)

  • 通常将组件参数单独定义, 方便工程化时管理
  • 通常将组件模板单独定义, 方便工程化时管理

#1) 完成 Vue 三步曲

在 src 目录下创建10_局部组件.html, 编写基础的 vue 模板

示例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>10_局部组件</title>
    <!-- 1. 引入vue.js -->
    <script src="../node_modules/vue/dist/vue.js"></script>
  </head>
  <body>
    <!-- 2. 编写div元素 -->
    <div id="app"></div>
    <!-- 3. 编写vue实例 -->
    <script>
      const vm = new Vue({
        el: '#app',
      })
    </script>
  </body>
</html>

#2) 定义局部组件

模板部分

<!-- 组件模板 -->
<template id="tmp">
  <button @click="count++">
    你点了我{
   
   {count}}次
  </button>
</template>

js 部分

// 定义组件对象
const com1 = {
  template: '#tmp', // 定义组件模板
  data() {
    // 定义属性
    return {
      count: 0,
    }
  },
}

#3) 挂载组件

在 vue 实例中挂载组件

const vm = new Vue({
  el: '#app',
  components: {
    // 组件名: 组件对象
    son: com1,
  },
})

  • 在 vue 实例中, 通过components完成挂载

#4) 引用组件

在 html 中, 通过组件名引用组件

<!-- 2. 编写div元素 -->
<div id="app">
  <!-- 引用组件 -->
  <son></son>
</div>

#5) 小结

局部组件的使用步骤

  1. 定义组件模板
  2. 定义组件对象
  3. 在 vue 实例中挂载组件
  4. 引用组件

========================

组件通信

通常一个单页应用(SPA)会以一棵嵌套的组件树的形式来组织

页面首先分成了顶部导航、左侧内容区、右侧边栏三部分

  • 左侧内容区又分为上下两个组件
  • 右侧边栏中又包含了 3 个子组件

各个组件之间以嵌套的关系组合在一起,那么这个时候不可避免的会有组件间通信的需求

主要分为两种情况:

  • 父向子 传递数据
  • 子向父 传递数据

#1 父组件向子组件传值

#1) 完成 Vue 三步曲

在 src 目录下创建11_父向子传值.html, 编写基础的 vue 模板

示例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>11_父向子传值</title>
    <!-- 1. 引入vue.js -->
    <script src="../node_modules/vue/dist/vue.js"></script>
  </head>
  <body>
    <!-- 2. 编写div元素 -->
    <div id="app"></div>
    <!-- 3. 编写vue实例 -->
    <script>
      const vm = new Vue({
        el: '#app',
      })
    </script>
  </body>
</html>

#2) 定义子组件

在 vue 对象中, 使用 components 定义一个局部组件

components: {
    // 组件名: {组件参数}
    son: {
        template: '<h3></h3>',
    }
}

#3) 引用子组件

在 html 中通过组件名, 通过组件名引用组件

<div id="app">
  <son></son>
</div>

#4) 传值

父组件向子组件传递数据的步骤

  1. 修改 html, 在子组件标签中添加一个属性 f2s

    <div id="app">
      <!-- 1. 在son标签中, 添加一个属性 -->
      <son f2s="父组件给子组件的数据"></son>
    </div>
    

  2. 修改 js, 在子组件中使用 props 接收

    components: {
        son: {
            template: '<h3></h3>',
            props: ['f2s']
        }
    }
    

  3. 在子组件的模板中使用

    components: {
        son: {
            template: '<h3>{
         
         { f2s }}</h3>',
            props: ['f2s']
        }
    }
    

#5) 使用属性绑定

也可以和父组件中的一个数据绑定起来使用

<div id="app">
  <!-- 1. 在son标签中, 添加一个属性 -->
  <son :f2s="msg"></son>
</div>

#6) 小结

父向子传值的步骤

  1. 在子组件标签中添加一个属性, 发送数据
  2. 在子组件中通过props, 接收数据

#2 子组件向父组件传值

#1) 完成 Vue 三步曲

在 src 目录下创建12_子向父传值.html, 编写基础的 vue 模板

示例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>12_子向父传值</title>
    <!-- 1. 引入vue.js -->
    <script src="../node_modules/vue/dist/vue.js"></script>
  </head>
  <body>
    <!-- 2. 编写div元素 -->
    <div id="app"></div>
    <!-- 3. 编写vue实例 -->
    <script>
      const vm = new Vue({
        el: '#app',
      })
    </script>
  </body>
</html>

#2) 定义子组件

在 vue 对象中, 使用 components 定义一个局部组件

components: {
    // 组件名: {组件参数}
    son: {
        template: '<button>点我</button>',
    }
}

#3) 引用子组件

在 html 中通过组件名, 通过组件名引用组件

<div id="app">
  <son></son>
</div>

#4) 传值

子组件向父组件传递数据的步骤

  1. 在子组件模板中绑定一个方法

    components: {
      //1. 定义组件
      son: {
        template: '<button @click="sendMsg">点我</button>',
      }
    }
    

  2. 在方法中向父组件提交(emit)一个事件

    components: {
      //1. 定义组件
      son: {
        template: '<button @click="sendMsg">点我</button>',
        methods: {
          sendMsg(){
            // 调用$emit, 向父组件提交一个send事件
          	this.$emit('send', "子组件->父组件")
          }
        }
      }
    }
    

  3. 在子组件标签中监听事件(绑定方法)

    <div id="app">
      <!-- 2. 引用组件 -->
      <son @send="handleSend"></son>
    </div>
    

  4. 在父组件中编写处理程序

methods: {
  handleSend(msg){
    alert('收到子组件的数据'+msg)
  }
},

#5) 小结

子向父传值的步骤

  1. 在子组件中绑定一个方法, 向父组件提交一个事件
  2. 在子组件标签中绑定一个方法, 监听事件
  3. 在父组件中编写处理程序

 =====================================

 Vue中的slot

#1 概述

#1) 什么是 slot

slot 可以理解为预留了一个可替换的地方

游戏卡是可以插拔的, 插游戏卡的地方就是一个插槽

思考

游戏卡插槽有什么作用?

再比如, USB 接口也可以看成一个插槽. 可以插入 U 盘, 硬盘, 鼠标, 键盘...

还有, CPU 槽, 内存槽. 他们的存在有什么共同点??

#2) 为什么需要 slot

通过上面的例子, 我们可以看出

  • 通过插不同的游戏卡, 可以玩不同的游戏
  • 通过插不同的外设, 可以扩展电脑的功能
  • 通过插不同型号的 CPU(i3/i5/i7/i9), 可以更换 CPU

所以, 插槽最主要的作用是提供扩展性.

#3) Vue 中的 slot

在 Vue 开发中, slot 主要应用在组件开发中, 通过在组件中预留 slot, 实现不同的功能

示例

<!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>Document</title>
    <script src="../node_modules/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <son></son>
    </div>

    <template id="tmp">
      <div>我是子组件</div>
    </template>

    <script>
      const vm = new Vue({
        el: '#app',
        components: {
          son: {
            template: '#tmp',
          },
        },
      })
    </script>
  </body>
</html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

子组件的模板编译后, 会替换<son>所在的地方

但是, 不管在<son>中添加任何内容, 都不起作用~

<div id="app">
  <son>
    <!-- 在子组件里写的内容不会生效 -->
    <h2>我是子组件的标题</h2>
  </son>
</div>

1
2
3
4
5
6

这样, 子组件的可扩展性就很不好. 如果希望子组件中的内容可以替换怎么办??

在子组件中预留一个插槽, 通过给子组件传递不同的内容来改变子组件

#2 具名插槽

#1) 作用

如果需要同时使用多个插槽, 就需要给插槽取名字.

就好比: 主板上同时有 CPU 槽和内存槽, 如何区分这两个插槽, 不至于把内存插到 CPU 中

当然, 现实中肯定不会, 但是程序中就需要使用名字区分开

#2) 使用

  • 在子组件中, 定义具名插槽
  • 在引用子组件时, 通过slot属性指定要替换的插槽
<div id="app">
  <son>
    <div slot="cpu">我是CPU</div>
    <div slot="memery">我是内存</div>
  </son>
</div>

<template id="tmp">
  <div>
    <slot name="cpu"></slot>
    <slot name="memery"></slot>
  </div>
</template>

没有指定的内容会全部放到<slot>中, 也就是默认插槽

<div id="app">
  <son>
    <div slot="cpu">我是CPU</div>
    <div slot="memery">我是内存</div>
    <hr />
    <div>我是剩余的内容</div>
    <p>我也是...</p>
  </son>
</div>

<template id="tmp">
  <div>
    <slot name="cpu"></slot>
    <slot name="memery"></slot>
    <!-- slot其实也有名字, 名字是default -->
    <slot></slot>
    <slot name="default"></slot>
  </div>
</template>

#3 作用域插槽

#1) 编译作用域

在 Vue 编译的过程中, 如果父子组件中定义的相同的状态, 会不会冲突呢?

如果不会冲突, 具体访问的是哪个状态

示例

<!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>Document</title>
    <script src="../node_modules/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <button v-show="isShow">按钮</button>
      <son></son>
    </div>

    <template id="tmp">
      <div>
        <h3>我是子组件</h3>
        <button v-show="isShow">子组件按钮</button>
      </div>
    </template>

    <script>
      const vm = new Vue({
        el: '#app',
        data: {
          isShow: false,
        },
        components: {
          son: {
            template: '#tmp',
            data() {
              return {
                isShow: true,
              }
            },
          },
        },
      })
    </script>
  </body>
</html>


 

父组件和子组件中都存在isShow.

  • 如果在父模板中使用 isShow, 访问的是父组件data中的值
  • 如果在子模板中使用 isShow, 访问的是子组件data中的值

通过上述示例, 我们可以发现, 在父组件中是不能直接访问子组件中的状态的.

需求

  • 在父模板中可定制子组件的内容
  • 同时使用子组件中的数据

#2) 为什么需要作用域插槽

为了解决上述问题, 引入了作用域插槽的概念, 其核心是在父模板中访问子组件的数据

示例

<div id="app">
  <button v-show="isShow">按钮</button>
  <!-- 通过v-slot指令找名字为default的插槽, 并指定prop对象对应default插槽 -->
  <son v-slot:default="prop">
    <!-- 通过prop对象访问show属性, 相当于访问了子组件的isShow -->
    <button v-show="prop.show">子组件按钮</button>
  </son>
</div>

<template id="tmp">
  <div>
    <h3>我是子组件</h3>
    <!-- 在slot:default对象中, 定义自定义属性show -->
    <slot :show="isShow"></slot>
  </div>
</template>

其中, v-slot可以使用#简写

<!-- 通过v-slot指令找名字为default的插槽, 并指定prop对象对应default插槽 -->
<son #default="prop">
  <!-- 通过prop对象访问show属性, 相当于访问了子组件的isShow -->
  <button v-show="prop.show">子组件按钮</button>
</son>

通过同时有多个插槽, 需要借用<template>语法

示例

<!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>Document</title>
    <script src="../node_modules/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <button v-show="isShow">按钮</button>
      <!-- 通过v-slot指令找名字为default的插槽, 并指定prop对象对应default插槽 -->
      <son>
        <template #default="prop">
          <!-- 通过prop对象访问show属性, 相当于访问了子组件的isShow -->
          <button v-show="prop.show">子组件按钮</button>
        </template>
        <template #left="left">
          <h3>{
   
   {left.info.name}}</h3>
        </template>
      </son>
    </div>

    <template id="tmp">
      <div>
        <h3>我是子组件</h3>
        <!-- 在slot:default对象中, 定义自定义属性show -->
        <slot :show="isShow"></slot>
        <slot name="left" :info="stu"></slot>
      </div>
    </template>

    <script>
      const vm = new Vue({
        el: '#app',
        data: {
          isShow: false,
        },
        components: {
          son: {
            template: '#tmp',
            data() {
              return {
                isShow: true,
                stu: {
                  name: 'xiaoming',
                  age: 18,
                },
              }
            },
          },
        },
      })
    </script>
  </body>
</html>

猜你喜欢

转载自blog.csdn.net/qq_38210427/article/details/130703460
今日推荐