【Web前端】Vue核心基础

文章目录

  • 1. Vue简介
  • 2. Vue官网使用指南
  • 3. 初识Vue
    • 3.1 搭建Vue开发环境
    • 3.2 HelloWorld案例
    • 3.3 el与data的两种写法
    • 3.4 MVVM模型
    • 3.5 模板语法
  • 4. 数据绑定
    • 4.1 v-bind单向数据绑定
    • 4.2 v-model双向数据绑定
  • 5. 事件处理
    • 5.1 v-on绑定事件
    • 5.2 事件修饰符
    • 5.3 键盘事件
  • 6. 计算属性
    • 6.1 姓名案例
    • 6.2 computed计算属性
  • 7. 监视属性
    • 7.1 天气案例
    • 7.2 watch监视属性
  • 8. 绑定样式
    • 8.1 绑定class样式
    • 8.2 绑定style样式
  • 9. 条件渲染
    • 9.1 v-show
    • 9.2 v-if、v-else与v-else-if
  • 10. 列表渲染
    • 10.1 v-for渲染列表数据
    • 10.2 key的作用与原理
    • 10.3 列表过滤
    • 10.4 列表排序
  • 11. 收集表单数据
  • 12. 内置指令
    • 12.1 v-text 解析普通文本
    • 12.2 v-html 解析html标签
    • 12.3 v-cloak 隐藏模板
    • 12.4 v-once 仅渲染一次
    • 12.5 v-pre 跳过元素编译
  • 13. 自定义指令
    • 13.1 函数式和对象式
    • 13.2 局部指令和全局指令
  • 14. Vue的生命周期
    • 14.1 生命周期概念
    • 14.2 生命周期演示
  • 15. Vue的组件化编程
    • 15.1 模块与组件
    • 15.2 非单文件组件
      • 15.2.1 组件的基本使用
      • 15.2.2 组件的注意事项
      • 15.2.3 组件的嵌套
      • 15.2.4 VueComponent
      • 15.2.5 一个重要的内置关系
    • 15.3 单文件组件
      • 15.3.1 单文件组件的组成
      • 15.3.2 单文件组件的示例

1. Vue简介

Vue的概念:Vue是一套用于构建用户界面的渐进式JavaScript框架。

渐进式:表示Vue可以自底向上逐层的应用,从简单应用逐渐递进到复杂应用。

Vue的特点:

  • 采用组件化模式,提高代码复用率,且让代码更好维护。
  • 声明式编码,让编码人员无需直接操作DOM,提高开发效率。
  • 使用虚拟DOM和Diff算法,尽量复用DOM节点。

学习Vue之前要掌握的js基础知识:

  • ES6语法规范
  • ES6模块化
  • 包管理器
  • 原型和原型链
  • 数组常用方法
  • axios
  • promise

2. Vue官网使用指南

Vue官网:

  • Vue3文档:https://cn.vuejs.org/
  • Vue2文档:https://v2.cn.vuejs.org/

以Vue2文档为例,对该文档顶部的导航栏做详细的介绍。

在这里插入图片描述

1.学习:其中最重要的是教程和API,贯穿vue学习的始终。

  • 教程:入门vue的教程
  • API:vue的属性、方法和指令等
  • 风格指南:官方推荐的vue代码风格指南
  • 示例:官方展示的一些vue案例
  • Cookbook:展示一些vue案例,教你如何优化vue代码
    在这里插入图片描述

2.生态系统:其中工具和插件很重要,用于搭建Vue工程。

在这里插入图片描述

3.资源列表:其中Awesome Vue、浏览和Vue相关的包,这两个包含了官方整理的一些优秀的vue周边库。
在这里插入图片描述

3. 初识Vue

3.1 搭建Vue开发环境

1.首先需要下载Vue

进入Vue官网的导航列表:学习 -> 教程 -> 安装,也可点击如下地址直接跳转:https://v2.cn.vuejs.org/v2/guide/installation.html

有开发和生产两种版本,这里我们使用开发版本,其中包含了完整的警告和调试模式,适用于学习阶段。

  • 开发环境版本:安装包名称为 vue.js,包含了有帮助的命令行警告,体积较大。
  • 生产环境版本:安装包名称为 vue.min.js,优化了尺寸和速度,体积较小。
    在这里插入图片描述

2.新建一个js文件夹,将下载好的vue.js放入js文件夹中,然后使用 <script>标签引入 vue.js,就可以使用Vue了

目录结构如下:

在这里插入图片描述

index.html内容如下:

<!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><!-- 引入Vue --><script src="../js/vue.js"></script></head><body></body>
</html>

打开页面后,再打开控制台,发现有两个提示:

在这里插入图片描述

3.消除开发环境的提示

添加vue开发者工具,消除第一个提示,步骤如下:打开Chrome扩展程序 -> 打开开发者模式 ->拖入vue_dev_tools.crx 文件到浏览器并松开,点击添加程序即可

在这里插入图片描述
script标签中写入以下vue配置,消除第二个提示:

Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示

3.2 HelloWorld案例

<!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><!-- 引入Vue --><script src="../js/vue.js"></script></head><body><!-- 准备好一个容器 --><div id="app"><h1>{{message}}</h1></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示// 创建Vue实例new Vue({// 配置el: "#app", // el用于指定当前Vue实例为哪个容器服务data: { // data中用于存储数据,数据供el所指定的容器去使用message: "Hello World!"}});</script></body>
</html>

代码解释:
1.el表示元素(element),值通常为css选择器,此处#app为id选择器,对应<div id="app">,此时当前vue实例挂载到了div容器上,为该容器服务。
2.data表示数据,数据供挂载的容器去使用,而容器中使用了模板语法 {{message}},引用了vue实例中的data数据。
3.vue实例中的message属性值Hello World!替换了{{message}},因此<h1>{{message}}</h1>最终解析成了<h1>Hello World!</h1>

运行结果如下:

在这里插入图片描述

注:
1.想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象
2.容器里的代码依然符合html规范,只不过混入了一些特殊的Vue语法
3.容器里的代码被称为Vue模板
4.Vue实例和容器是一一对应的
5.真实开发中只有一个Vue实例,并且会配合着组件一起使用
6.{{xxx}}中的xxx要写js表达式,且xxx可以自动读取到data中的所有属性
7.一旦data中的数据发生改变,那么页面中用到该数据的地方也会自动更新

3.3 el与data的两种写法

1.eldata的第一种写法是对象式写法,就是上述HelloWorld案例中的写法,即通过配置对象属性和属性值。

// 创建Vue实例
new Vue({// 配置el: "#app", // 将Vue实例挂载到 id=app的容器上data: {  // data中用于存储数据,数据供挂载的容器去使用message: "Hello World!"}
});

2.eldata的第二种写法是函数式写法

// 创建Vue实例
const vm = new Vue({// data的函数式写法,组件中必须使用该写法data() {return {message: "Hello World!"};}
});vm.$mount("#app"); // 等价于 el: "#app"

注意:vue实例中的函数不能使用箭头函数的写法,原本函数中的this指向的是vue实例对象,使用箭头函数后,函数中的this指向的就是window对象。

3.4 MVVM模型

Vue采用了MVVM架构模型,其对应关系如下:

  • M:模型(Model) ,对应 data 中的数据
  • V:视图(View) ,对应模板
  • VM:视图模型(ViewModel) , 对应 Vue 实例对象

在这里插入图片描述

在这里插入图片描述

3.5 模板语法

模板语法:Vue实例挂载的容器里中的代码被称为模板,模板语法也就是这个容器中代码的语法规范,模板语法分为两大类(插值语法和指令语法)。

插值语法:

  • 功能:用于解析标签体内容
  • 写法:{{xxx}},xxx是js表达式,且可以直接读取到data中的所有属性

指令语法:

  • 功能:用于解析标签(包括标签属性、标签体内容、绑定事件等)
  • 写法:v-xxx,如v-bindv-modelv-on
<!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><!-- 引入Vue --><script src="../js/vue.js"></script></head><body><div id="app"><!-- 插值语法,{{js表达式}} --><h3>{{message.toUpperCase()}}</h3><!-- 指令语法,v-xxx --><a v-bind:href="url">百度链接</a></div><script>new Vue({el: "#app",data: {message: "hello world",url: "https://www.baidu.com/"}});</script></body>
</html>

运行结果:
在这里插入图片描述

4. 数据绑定

Vue中有两种数据绑定的方式:

  • 单向绑定(v-bind):数据只能从data流向页面
  • 双向绑定(v-model):数据不仅能从data流向页面,还可以从页面流向data

4.1 v-bind单向数据绑定

v-bind:用于单向数据绑定,该指令也可以简写为 :

<!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="../js/vue.js"></script></head><body><div id="app"><!-- 普通写法 -->单向数据绑定:<input type="text" v-bind:value="name" /> <br /><!-- 简写 -->单向数据绑定:<input type="text" :value="name" /></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {name: "hello"}});</script></body>
</html>

验证数据能从data流向页面:打开控制台,输入 vm.name="hello123"并回车,可以发现页面中的数据也显示成了hello123

在这里插入图片描述

验证页面的数据无法流向data:在文本框中输入hello1234,随后在控制台输入vm.name,得到的结果依然是hello123,说明vue实例中的data数据未发生改变

在这里插入图片描述

4.2 v-model双向数据绑定

v-model:用于双向数据绑定,双向绑定只能应用在表单类元素(输入类元素)上,如:input、select等

注:v-model:value 可以简写为 v-model,因为v-model默认收集的就是value值。

<!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="../js/vue.js"></script></head><body><div id="app"><!-- 普通写法 -->双向数据绑定:<input type="text" v-model:value="name" /> <br /><!-- 简写 -->双向数据绑定:<input type="text" v-model="name" /></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {name: "hello"}});</script></body>
</html>

验证数据能从data流向页面:打开控制台,输入 vm.name="hello123"并回车,可以发现页面中的数据也显示成了hello123

在这里插入图片描述

验证页面的数据也能流向data:在文本框中输入hello1234,随后在控制台输入vm.name,得到的结果是hello1234,说明vue实例中的data数据随页面数据的改变而改变

在这里插入图片描述

5. 事件处理

5.1 v-on绑定事件

事件的基本使用:

  • 使用v-on:xxx="yyy" 指令用于绑定事件,其中v-on:可以简写为@xxx是事件名,yyy是回调函数名(也可以是简单的语句,如isShow=!isShow
  • methods对象用于配置vm的方法,事件的回调函数需要配置在methods对象中
  • methods中配置的函数,this指向的是vm或组件实例对象,且配置的函数不能使用箭头函数,否则this指向的是window对象
  • @click="demo"@click="demo($event)" 效果一致,但后者可以传参

1.绑定事件,且回调函数不传参

<!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="../js/vue.js"></script></head><body><div id="app"><!-- 普通写法 --><button v-on:click="showInfo">按钮1</button><!-- 简写 --><button @click="showInfo">按钮2</button></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",// 配置方法methods: {// 事件回调函数showInfo() {alert("Hello World!");}}});</script></body>
</html>

2.绑定事件,且给回调函数传参

<!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="../js/vue.js"></script></head><body><div id="app"><button @click="showInfo">按钮1</button><!-- $event为占位符,表示此时第一个参数为事件对象 --><button @click="showInfo1($event,'Jack')">按钮2</button></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",// 配置方法methods: {// 不传参时,函数的第一个参数代表事件对象showInfo(e) {console.log(e.target); // 触发事件的对象console.log(e.type); // 事件的类型console.log(this); // this指向vm},// 传参时,根据$event占位符的位置确定哪个参数代表事件对象showInfo1(e, name) {console.log(e.target);console.log(e.type);console.log(`Hello ${name}`);}}});</script></body>
</html>

运行结果:

在这里插入图片描述

5.2 事件修饰符

Vue中的事件修饰符:

  • prevent:阻止默认事件(常用)
  • stop:阻止事件冒泡(常用)
  • once:事件只触发一次(常用)
  • capture:使用事件的捕获模式
  • self:只有event.target是当前操作的元素时才触发事件
  • passive:事件的默认行为立即执行,无需等待事件回调执行完毕

注:修饰符可以连续写,如@click.prevent.stop="showInfo"

1.prevent:阻止事件的默认行为(常用)

同js事件对象中的e.preventDefault()方法,用于阻止事件的默认行为

<!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="../js/vue.js"></script></head><body><div id="app"><!-- 阻止链接跳转 --><a href="https://www.baidu.com/" @click.prevent="showInfo">百度链接</a><!-- 阻止表单提交 --><form action="https://www.baidu.com/"><input type="submit" value="提交" @click.prevent="showInfo" /></form></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",methods: {showInfo() {console.log("已阻止事件的默认行为");}}});</script></body>
</html>

运行结果:点击百度链接和表单提交按钮,都不发生页面跳转,因为跳转的默认行为被阻止了

2.stop:阻止事件冒泡(常用)

同js事件对象中的e.stopPropagation()方法,用于阻止事件冒泡

<!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="../js/vue.js"></script><style>.father {position: relative;width: 200px;height: 200px;background-color: #666;margin: 30px;}.son {position: absolute;width: 100px;height: 100px;background-color: orange;margin: auto;top: 0;left: 0;right: 0;bottom: 0;}</style></head><body><div id="app" class="father" @click="showInfo1"><!-- 阻止事件冒泡 --><div class="son" @click.stop="showInfo2"></div></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",methods: {showInfo1() {alert("father");},showInfo2() {alert("son");}}});</script></body>
</html>

运行结果:点击子元素 ,只弹出警示框“son”,没有后续弹出“father”
(释义:点击子元素son以后,阻止冒泡,因此没有冒泡到父元素,父元素的事件行为不执行)

在这里插入图片描述

3.once:事件只触发一次(常用)

<!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="../js/vue.js"></script></head><body><div id="app"><!-- 此按钮只在第一次点击时,触发事件 --><button @click.once="showInfo">点击按钮</button></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",methods: {showInfo() {alert("Hello World!");}}});</script></body>
</html>

运行结果:第一次点击按钮时,弹出警示框,后续再点击无法弹出

4.capture:使用事件的捕获模式

注:js中addEventListener(type, listener, useCapture)useCapturefalse或者忽略时,事件处于冒泡阶段;为true时,事件处于捕获阶段

<!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="../js/vue.js"></script><style>.father {position: relative;width: 200px;height: 200px;background-color: #666;margin: 30px;}.son {position: absolute;width: 100px;height: 100px;background-color: orange;margin: auto;top: 0;left: 0;right: 0;bottom: 0;}</style></head><body><!-- 绑定事件到父元素father,为捕获阶段 --><div id="app" class="father" @click.capture="showInfo1"><div class="son" @click="showInfo2"></div></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",methods: {showInfo1() {alert("father");},showInfo2() {alert("son");}}});</script></body>
</html>

运行结果:点击橘色的子元素div,先弹出警示框 “father”,后弹出警示框 “son”
(释义:捕获从上往下传递,点击子元素son以后,会先找到父元素并执行它的事件,再往下找到子元素后,执行子元素的事件)

在这里插入图片描述

5.self:只有event.target是当前操作的元素时才触发事件

注:通过这种方式,也能阻止事件冒泡

<!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="../js/vue.js"></script><style>.father {position: relative;width: 200px;height: 200px;background-color: #666;margin: 30px;}.son {position: absolute;width: 100px;height: 100px;background-color: orange;margin: auto;top: 0;left: 0;right: 0;bottom: 0;}</style></head><body><!-- 只有当e.target是当前操作的元素时才触发事件,即只有点击该父元素才触发父元素的事件 --><div id="app" class="father" @click.self="showInfo1"><!-- <div id="app" class="father" @click="showInfo1"> --><div class="son" @click="showInfo2"></div></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",methods: {showInfo1() {alert("father");},showInfo2() {alert("son");}}});</script></body>
</html>

运行结果:只有点击灰色的父元素div时,才弹出警示框 “father”

在这里插入图片描述

5.3 键盘事件

Vue中常用的按键别名:

  • 回车 => enter
  • 删除 => delete (捕获“删除”和“退格”键)
  • 退出 => esc
  • 空格 => space
  • 换行 => tab (特殊,必须配合keydown去使用)
  • 上 => up
  • 下 => down
  • 左 => left
  • 右 => right

注:
1.Vue未提供别名的按键,可以使用按键原始的key值去绑定,但注意要转为kebab-case(短横线命名,如caps-lock)
2.可以使用keyCode去指定具体的按键(不推荐),如e.keyCode===13代表回车键
3.Vue.config.keyCodes.自定义键名 = 键码,可以去定制按键别名,如Vue.config.keyCodes.huiche=13,此时别名huiche代表回车键
4.系统修饰键(用法特殊):ctrl、alt、shift、meta,

  • 配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。
  • 配合keydown使用:正常触发事件。
<!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="../js/vue.js"></script></head><body><div id="app"><!-- 按下回车键松开时触发事件 --><input type="text" placeholder="输入完成后请按回车" @keyup.enter="showInfo" /></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",methods: {showInfo(e) {alert(e.target.value);}}});</script></body>
</html>

运行结果:输入“123456”,再按下回车后松开

在这里插入图片描述

6. 计算属性

6.1 姓名案例

要求:一个input框输入“姓”,另一个input框输入“名”,生成“姓-名”

解题方法有三种:

  • 使用插值语法{{}}实现
  • 使用methods方法实现
  • 使用computed计算属性实现(推荐)

1.使用插值语法{{}}实现姓名案例,通过直接在模板里进行字符串拼接

<!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="../js/vue.js"></script></head><body><div id="app">姓:<input type="text" v-model="firstName" /> <br />名:<input type="text" v-model="lastName" /> <br />全名:<span>{{firstName}}-{{lastName}}</span></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {firstName: "张",lastName: "三"}});</script></body>
</html>

运行结果如下:在两个输入框中分别输入“姓”和“名”,得到全名为“姓-名”

在这里插入图片描述

2.使用methods方法实现姓名案例,通过调用方法,将方法的返回值渲染到模板中

<!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="../js/vue.js"></script></head><body><div id="app">姓:<input type="text" v-model="firstName" /> <br />名:<input type="text" v-model="lastName" /> <br />全名:<span>{{fullName()}}</span></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {firstName: "张",lastName: "三"},methods: {fullName() {return this.firstName + "-" + this.lastName;}}});</script></body>
</html>

3.使用computed计算属性实现,通过计算原有的属性,得到新的属性,并将其渲染到模板中

<!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="../js/vue.js"></script></head><body><div id="app">姓:<input type="text" v-model="firstName" /> <br />名:<input type="text" v-model="lastName" /> <br />全名:<span>{{fullName}}</span></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {firstName: "张",lastName: "三"},computed: {fullName: {get() {return this.firstName + "-" + this.lastName;}}}});</script></body>
</html>

6.2 computed计算属性

计算属性:

  • 定义:要用的属性不存在,要通过已有属性计算得来,计算属性最终会出现在vm上,直接读取使用即可
  • 原理:底层借助了Objcet.defineproperty方法提供的gettersetter
  • 优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便
  • 计算属性中的getset函数:
    • 使用计算属性时,初次读取会执行一次get函数,当依赖的数据发生改变时也会再次调用get函数
    • 修改计算属性时,会调用set函数
  • 当计算属性中,只有get函数时,可以简写计算属性

1.计算属性中的getset函数的使用

<!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="../js/vue.js"></script></head><body><div id="app">姓:<input type="text" v-model="firstName" /> <br />名:<input type="text" v-model="lastName" /> <br />全名:<span>{{fullName}}</span></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {firstName: "张",lastName: "三"},computed: {fullName: {// 使用fullName时,返回全名get() {console.log("get被调用了");return this.firstName + "-" + this.lastName;},// 修改fullName时,修改firstName和lastName属性set(value) {console.log("set被调用了");arr = value.split("-");this.firstName = arr[0];this.lastName = arr[1];}}}});</script></body>
</html>

运行结果:
由于模板中使用了fullName属性,先调用了一次get,然后在输入修改名后,fullName依赖的lastName属性发生了改变,再次调用了get;

在这里插入图片描述
控制台中输入vm.fullName='张-三丰',fullName属性被修改,调用了set,又因为set函数修改了fullName所依赖的firstName 和lastName,所以再次触发调用了get

在这里插入图片描述

2.简写计算属性

当计算属性中,只有get函数时,代码可以进行如下简写:

// 普通写法
computed: {fullName: {get() {return this.firstName + "-" + this.lastName;}}
}
// 简写
computed: {fullName() {return this.firstName + "-" + this.lastName;}
}

7. 监视属性

7.1 天气案例

要求:点击按钮时,天气在炎热和凉爽之间切换,初始值默认为炎热。

实现如下:

<!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="../js/vue.js"></script></head><body><div id="app"><h1>今天天气很{{info}}</h1><button @click="changeWeather">点击切换天气</button></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {isHot: true // 默认天气为炎热},computed: {info() {return this.isHot ? "炎热" : "凉爽";}},methods: {changeWeather() {this.isHot = !this.isHot; // 每次调用方法时,isHot取反}}});</script></body>
</html>

注:由于methods中的changeWeather方法逻辑简单,因此也可以将methods去掉,并把@click="changeWeather"改为@click="isHot = !isHot",这样就简化了代码。

运行结果:点击按钮,天气在炎热和凉爽之间切换

在这里插入图片描述

7.2 watch监视属性

监视属性watch

  • 监视的属性必须存在,才能进行监视
  • 当被监视的属性变化时, handler回调函数自动调用
  • 监视属性有两种写法,一是通过watch属性配置,二是通过vm.$watch()方法
  • 深度监视属性:
    • 当被监视的属性有多层结构时,默认不监测对象内部值的改变(一层)
    • 通过配置deep:true可以监测对象内部值改变(多层)
  • 当监视属性中,只有handler函数时,可以监视计算属性

1.监视属性的基本用法(通过watch属性配置)

<!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="../js/vue.js"></script></head><body><div id="app"><h1>今天天气很{{info}}</h1><button @click="isHot = !isHot">点击切换天气</button></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {isHot: true // 默认天气为炎热},computed: {info() {return this.isHot ? "炎热" : "凉爽";}},methods: {changeWeather() {this.isHot = !this.isHot; // 每次调用方法时,isHot取反}},watch: {// 当isHot属性发生变化时,会调用handler函数isHot: {immediate: true, //初始化时会调用一下handler函数handler(newValue, oldValue) {console.log(`isHot被修改,原来的值是${oldValue},现在是${newValue}`);}}}});</script></body>
</html>

点击按钮,运行结果如下:

在这里插入图片描述

2.可以通过vm.$watch()方法,进行属性监视

// watch属性配置的写法
watch: {isHot: {immediate: true, handler(newValue, oldValue) {console.log(`isHot被修改,原来的值是${oldValue},现在是${newValue}`);}}
}
// vm.$watch()的写法
vm.$watch("isHot", {immediate: true, handler(newValue, oldValue) {console.log(`isHot被修改,原来的值是${oldValue},现在是${newValue}`);}
});

3.deep:true 用于深度监视属性

  • 深度监视单个属性:监视的属性写为"numbers.a",表示监视numbers属性中的a属性
  • 深度监视所有属性: 监视的属性写为numbers,再配置deep:true,表示监视numbers属性中的所有属性
<!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="../js/vue.js"></script></head><body><div id="app"><h3>a的值是:{{numbers.a}}</h3><button @click="numbers.a++">点我让a+1</button><h3>b的值是:{{numbers.b}}</h3><button @click="numbers.b++">点我让b+1</button></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {// numbers属性有多层结构numbers: {a: 1,b: 1,c: {d: {e: 100}}}},watch: {//监视多级结构中某个属性的变化"numbers.a": {handler() {console.log("a发生了改变");}},//监视多级结构中所有属性的变化numbers: {deep: true,handler() {console.log("numbers发生了改变");}}}});</script></body>
</html>

分别点击上下两个按钮,使a、b值增加,运行结果如下:

在这里插入图片描述

4.简写监视属性

当监视属性中,只有handler函数时,代码可以进行如下简写:

// 普通写法
watch: {isHot: {handler(newValue, oldValue) {console.log(`isHot被修改,原来的值是${oldValue},现在是${newValue}`);}}
}
// watch属性配置简写
watch: {isHot(newValue, oldValue) {console.log(`isHot被修改,原来的值是${oldValue},现在是${newValue}`);}
}// vm.$watch()方法简写
vm.$watch("isHot", function (newValue, oldValue) {console.log(`isHot被修改,原来的值是${oldValue},现在是${newValue}`);
});

5.计算属性与监视属性的区别

computedwatch之间的区别:

  • computed能完成的功能,watch都可以完成
  • watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作
  • computed的写法更加的简洁,因此能用 computed完成的功能,不要用watch完成

注:Vue中有关函数的两个重要的小原则:
1.所有被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象
2.所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数),最好写成箭头函数,这样this的指向才是vm 或 组件实例对象。

8. 绑定样式

8.1 绑定class样式

绑定class样式有三种方式,分别适用于不同的场景:写法为:class="xxx"

  • 字符串写法:适用于样式的类名不确定,需要动态指定
  • 对象写法:适用于要绑定的样式个数确定、名字也确定,但要动态决定用不用
  • 数组写法:适用于要绑定的样式个数不确定、名字也不确定

1.绑定class样式,字符串写法:适用于样式的类名不确定,需要动态指定

<!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="../js/vue.js"></script><style>/* basic为固定样式,happy和sad为需要动态绑定的样式 */.basic {width: 200px;height: 100px;border: 1px solid black;}/* 快乐情绪 */.happy {border: 4px solid red;background-color: orangered;background: linear-gradient(30deg, yellow, pink, orange, yellow);}/* 悲伤情绪 */.sad {border: 4px dashed rgb(2, 197, 2);background-color: gray;}</style></head><body><div id="app"><!-- 字符串写法,适用于:样式的类名不确定,需要动态指定 --><div class="basic" :class="mood"></div><br /><button @click="changeMood">点击切换情绪</button></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {mood: "happy" // 属性值为字符串},methods: {// 改变情绪changeMood() {if (this.mood == "happy") {this.mood = "sad";} else {this.mood = "happy";}}}});</script></body>
</html>

运行结果:点击按钮,盒子样式发生改变(盒子的样式是动态的)

在这里插入图片描述在这里插入图片描述

2.绑定class样式,对象写法:适用于要绑定的样式个数确定、名字也确定,但要动态决定用不用

动态切换单个 class样式:

<!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="../js/vue.js"></script><style>.basic {width: 200px;height: 100px;border: 1px solid black;}.a1 {background-color: yellowgreen;}</style></head><body><div id="app"><!-- 对象写法,适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用 --><div class="basic" :class="{a1:isActive}">归海一刀</div><button @click="isActive=!isActive">添加/删除样式</button></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {isActive: true}});</script></body>
</html>

运行结果:点击按钮,选择添加或者删除样式.

在这里插入图片描述

动态切换多个 class样式:

<!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="../js/vue.js"></script><style>.basic {width: 200px;height: 100px;border: 1px solid black;}.a1 {background-color: yellowgreen;}.a2 {font-size: 30px;text-shadow: 2px 2px 10px red;}.a3 {border-radius: 20px;}</style></head><body><div id="app"><!-- 对象写法,适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用 --><div class="basic" :class="classObj">归海一刀</div><button @click="classObj.a1=!classObj.a1">添加/删除样式a1</button><button @click="classObj.a2=!classObj.a2">添加/删除样式a2</button></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {classObj: {a1: false,a2: false}}});</script></body>
</html>

运行结果:点击按钮,选择添加或者删除样式

在这里插入图片描述

3.绑定class样式,数组写法:适用于要绑定的样式个数不确定、名字也不确定

<!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="../js/vue.js"></script><style>.basic {width: 200px;height: 100px;border: 1px solid black;}.a1 {background-color: yellowgreen;}.a2 {font-size: 30px;text-shadow: 2px 2px 10px red;}.a3 {border-radius: 20px;}</style></head><body><div id="app"><!-- 数组写法,适用于:要绑定的样式个数不确定、名字也不确定 --><div class="basic" :class="classArr">归海一刀</div></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {classArr: ["a1", "a2"] // 属性值为数组}});</script></body>
</html>

运行结果:可以通过对数组进行操作,从而对样式进行添加和删除

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

8.2 绑定style样式

绑定style样式有两种方式:

  • 对象写法::style="{fontSize: xxx}"其中xxx是动态值
  • 数组写法::style="[a,b]"其中a、b是样式对象

1.绑定style样式,对象写法

注:在style样式绑定中,CSS中的样式名要改为小驼峰写法,如:font-size 要改为 fontSize

<!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="../js/vue.js"></script><style>.basic {width: 200px;height: 100px;border: 1px solid black;margin-bottom: 20px;}</style></head><body><div id="app"><!-- 绑定style样式,对象写法 --><div class="basic" :style="{fontSize: `${fsize}px`}">归海一刀</div><div class="basic" :style="styleObj">归海一刀</div></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {fsize: 30,styleObj: {// 小驼峰写法fontSize: "30px",color: "red",backgroundColor: "orange"}}});</script></body>
</html>

运行结果:

在这里插入图片描述

2.绑定style样式,数组写法

<!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="../js/vue.js"></script><style>.basic {width: 200px;height: 100px;border: 1px solid black;margin-bottom: 20px;}</style></head><body><div id="app"><!-- 绑定style样式,数组写法 --><div class="basic" :style="styleArr">归海一刀</div></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {styleArr: [{fontSize: "30px",color: "red"},{backgroundColor: "orange"}]}});</script></body>
</html>

运行结果:

在这里插入图片描述

9. 条件渲染

9.1 v-show

v-show

  • 写法:v-show="表达式"
  • 适用于:切换频率较高的场景
  • 特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉(设置为display:none
<!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="../js/vue.js"></script></head><body><div id="app"><h1 v-show="isActive">Hello World</h1><button @click="isActive=!isActive">显示/隐藏元素</button></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {isActive: true}});</script></body>
</html>

运行结果:点击按钮之后,元素被隐藏,再查看DOM结构,发现元素样式上多了个style="display: none;"

在这里插入图片描述
在这里插入图片描述

9.2 v-if、v-else与v-else-if

v-if

  • 写法:v-if="表达式"v-else="表达式"v-else-if="表达式"
  • 适用于:切换频率较低的场景
  • 特点:不展示的DOM元素直接被移除

1.使用v-if会把DOM元素直接被移除

<!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="../js/vue.js"></script></head><body><div id="app"><h1 v-if="isActive">Hello World</h1><button @click="isActive=!isActive">显示/隐藏元素</button></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {isActive: true}});</script></body>
</html>

运行结果:点击按钮之后,元素被隐藏,再查看DOM结构,发现元素直接被移除了

在这里插入图片描述

2.v-ifv-elsev-else-if配合使用

<!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="../js/vue.js"></script></head><body><div id="app"><h2>当前n的值是{{n}}</h2><button @click="n++">点击n+1</button><h3 v-if="n===1">Angular</h3><h3 v-else-if="n===2">React</h3><h3 v-else-if="n===3">Vue</h3><h3 v-else>不是前端三大框架</h3></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {n: 0}});</script></body>
</html>

运行结果:点击按钮增加n的值,当n达到对应值时,分别展示对应的元素
在这里插入图片描述

注:v-if可以和v-else-ifv-else一起使用,但要求结构不能被“打断”

打断的结构示例如下:

<h3 v-if="n===1">Angular</h3>
<h3 v-else-if="n===2">React</h3>
<h3>打断结构</h3> 
<h3 v-else-if="n===3">Vue</h3>
<h3 v-else>不是前端三大框架</h3>

3.v-iftemplate的配合使用:当几个v-if的条件一样时,可以配合template,将多个条件简写为一个

注:使用template标签,不会影响结构,而且只能和v-if配合使用,不能和v-show配合

<!-- 简写前 -->
<h3 v-if="n===1">Angular</h3>
<h3 v-if="n===1">React</h3>
<h3 v-if="n===1">Vue</h3>
<!-- 简写后 -->
<template v-if="n===1"><h3>Angular</h3><h3>React</h3><h3>Vue</h3>
</template>

10. 列表渲染

10.1 v-for渲染列表数据

v-for指令:用于展示列表数据

语法:v-for="(item, index) in xxx" :key="yyy"

  • xxx为可遍历对象,包括数组、对象、字符串等
  • item为可遍历对象的每一项数据,index为每一项数据的索引值
  • key属性为每项数据的唯一标识

1.使用v-for遍历数组(常用)

<!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="../js/vue.js"></script></head><body><div id="app"><!-- 遍历数组 --><ul><!-- p为数组成员,index为数组下标 --><li v-for="(p,index) in persons" :key="index">{{index}}:{{p.name}}-{{p.age}}</li></ul></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {// id为每项数据的唯一标识persons: [{ id: "001", name: "张三", age: 18 },{ id: "002", name: "李四", age: 19 },{ id: "003", name: "王五", age: 20 }]}});</script></body>
</html>

注:由于数组下标indexid都是唯一标识,而key只要作为唯一标识就可以,因此以上代码中的:key="index"也可以改为:key="p.id"

运行结果:

在这里插入图片描述

2.使用v-for遍历对象(常用)

<!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="../js/vue.js"></script></head><body><div id="app"><!-- 遍历对象 --><ul><!-- v为对象的属性值(value),k为对象的属性名(key) --><li v-for="(v,k) in car" :key="k">{{k}}-{{v}}</li></ul></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {// 对象是一个键值对,属性名就是键(key),可以作为唯一标识car: {name: "奥迪A6L",price: "70万",color: "黑色"}}});</script></body>
</html>

运行结果:

在这里插入图片描述

3.使用v-for遍历字符串(用的少)

<!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="../js/vue.js"></script></head><body><div id="app"><!-- 遍历字符串 --><ul><!-- item为每个字符,index为字符串下标 --><li v-for="(item,index) in str" :key="index">{{index}}-{{item}}</li></ul></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {str: "Hello"}});</script></body>
</html>

运行结果:

在这里插入图片描述

4.使用v-for遍历指定的次数(用的少)

<!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="../js/vue.js"></script></head><body><div id="app"><!-- 遍历指定的次数 --><ul><!-- 遍历5次 --><li v-for="(number,index) in 5" :key="index">{{number}}-{{str}}</li></ul></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {str: "Hello World"}});</script></body>
</html>

运行结果:

在这里插入图片描述

10.2 key的作用与原理

1.key作为数据的唯一标志,选择原则遵循如下:

  • 最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
  • 如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的。

2.用index作为key可能会引发的问题:

  • 若对数据进行:逆序添加、逆序删除等破坏顺序操作,会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。
  • 如果结构中还包含输入类的DOM:会产生错误DOM更新 ==> 界面有问题。
<!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="../js/vue.js"></script></head><body><div id="app"><!-- 遍历数组 --><button @click.once="add">添加一个老刘</button><ul><!-- p为数组成员,index为数组下标 --><li v-for="(p,index) in persons" :key="index">{{p.name}}-{{p.age}} <input type="text" /></li></ul></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {// id为每项数据的唯一标识persons: [{ id: "001", name: "张三", age: 18 },{ id: "002", name: "李四", age: 19 },{ id: "003", name: "王五", age: 20 }]},methods: {// 对数据进行逆序添加,破坏原有顺序add() {const p = { id: "004", name: "老刘", age: 40 };this.persons.unshift(p);}}});</script></body>
</html>

运行结果如下:在输入框中输入内容,然后再点击按钮,发现输入框中的数据显示有问题

在这里插入图片描述

在这里插入图片描述

当把以上代码的:key="index"改为:key="p.id",数据则显示正常了

在这里插入图片描述

原理如下:

  • 虚拟DOM中key的作用:key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】
  • 随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:
    • 旧虚拟DOM中找到了与新虚拟DOM相同的key:若虚拟DOM中内容没变, 直接使用之前的真实DOM;若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM。
    • 旧虚拟DOM中未找到与新虚拟DOM相同的key:创建新的真实DOM,随后渲染到到页面

在这里插入图片描述

在这里插入图片描述

10.3 列表过滤

列表过滤:对列表的数据进行筛选,筛选后的数据再渲染到页面中。

1.使用监视属性,实现列表过滤

<!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="../js/vue.js"></script></head><body><div id="app">人员列表:<input type="text" placeholder="请输入名字" v-model="keyWord" /><ul><!-- 展示过滤后的数组 --><li v-for="(p,index) of filPerons" :key="index">{{p.name}}-{{p.age}}-{{p.sex}}</li></ul></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {keyWord: "", // 关键词,用于模糊搜索persons: [{ id: "001", name: "马冬梅", age: 19, sex: "女" },{ id: "002", name: "周冬雨", age: 20, sex: "女" },{ id: "003", name: "周杰伦", age: 21, sex: "男" },{ id: "004", name: "温兆伦", age: 22, sex: "男" }],filPerons: [] // 用于存放过滤后的数组,避免改动原数组},watch: {// 监视keyWord属性,当keyWord属性值发生变化时,调用handler函数进行模糊搜索keyWord: {immediate: true, // 初始化时调用handler,空字符串会匹配所有数据,首次展示为完整数据handler(val) {this.filPerons = this.persons.filter(p => {return p.name.includes(val); // 判断输入框中的值是否出现在姓名中});}}}});</script></body>
</html>

运行结果:

在这里插入图片描述

在这里插入图片描述

2.使用计算属性,实现列表过滤

<!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="../js/vue.js"></script></head><body><div id="app">人员列表:<input type="text" placeholder="请输入名字" v-model="keyWord" /><ul><!-- 展示过滤后的数组 --><li v-for="(p,index) of filPerons" :key="index">{{p.name}}-{{p.age}}-{{p.sex}}</li></ul></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {keyWord: "", // 关键词,用于模糊搜索persons: [{ id: "001", name: "马冬梅", age: 19, sex: "女" },{ id: "002", name: "周冬雨", age: 20, sex: "女" },{ id: "003", name: "周杰伦", age: 21, sex: "男" },{ id: "004", name: "温兆伦", age: 22, sex: "男" }]},computed: {// 计算属性filPerons依赖于keyWord属性,当keyWord发生改变时,会重新计算属性filPerons() {return this.persons.filter(p => {return p.name.includes(this.keyWord);});}}});</script></body>
</html>

注:使用computed还是watch的原则
1.computed 的写法更加的简洁(推荐使用),能用 computed 完成的功能,不要用 watch 完成
2.computed 无法完成的功能才用 watch 实现,例如:watch 可以进行异步操作

10.4 列表排序

列表排序:对列表数据进行排序,排序后的数据再渲染到页面中

  • 可以对完整的列表数据进行排序
  • 也可以配合列表过滤,对筛选后的列表数据进行排序。
<!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="../js/vue.js"></script></head><body><div id="app">人员列表:<input type="text" placeholder="请输入名字" v-model="keyWord" /><button @click="sortType = 2">年龄升序</button><button @click="sortType = 1">年龄降序</button><button @click="sortType = 0">原顺序</button><ul><!-- 展示过滤后的数组 --><li v-for="(p,index) of filPerons" :key="index">{{p.name}}-{{p.age}}-{{p.sex}}</li></ul></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {keyWord: "",sortType: 0, // 0原顺序、1降序、2升序persons: [{ id: "001", name: "马冬梅", age: 30, sex: "女" },{ id: "002", name: "周冬雨", age: 31, sex: "女" },{ id: "003", name: "周杰伦", age: 18, sex: "男" },{ id: "004", name: "温兆伦", age: 19, sex: "男" }]},computed: {// 计算属性filPerons依赖于keyWord和sortType属性,依赖的这两个属性任何一个发生变化,都会引起重新计算属性filPerons() {// 对列表数据进行筛选const arr = this.persons.filter(p => {return p.name.includes(this.keyWord);});// 判断一下是否需要排序if (this.sortType) {arr.sort((p1, p2) => {return this.sortType === 1 ? p2.age - p1.age : p1.age - p2.age;});}return arr;}}});</script></body>
</html>

运行结果:在输入框中输入关键词,可以对数据进行筛选,再点击按钮可以对筛选后的数据再进行排序

在这里插入图片描述

11. 收集表单数据

v-model用于收集表单数据,且在收集表单数据时,根据表单控件类型的不同,默认收集的值也不同。

v-model需要注意的点如下:

  • 若表单控件为文本框或密码框,即 <input type="text"/><input type="password"/>,则v-model收集的是value值,用户输入的就是value值。
  • 若表单控件为单选框,即<input type="radio"/>,则v-model收集的是value值,需要给标签配置value值。
  • 若表单控件为复选框,即<input type="checkbox"/>,则有以下两种情况:
    • 没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值)
    • 配置了input的value属性,当v-model的初始值是非数组时,那么收集的就是checked;是数组时,那么收集的的就是value组成的数组

注:v-model的三个修饰符
1.lazy:失去焦点时,再收集数据
2.number:输入字符串转为有效的数字
3.trim:清除文本框首尾空格

<!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="../js/vue.js"></script></head><body><div id="app"><!-- 阻止表单默认跳转行为 --><form @submit.prevent="demo">账号:<input type="text" v-model.trim="userInfo.account" /> <br /><br />密码:<input type="password" v-model="userInfo.password" /> <br /><br />年龄:<input type="number" v-model.number="userInfo.age" /> <br /><br />性别: 男<input type="radio" name="sex" v-model="userInfo.sex" value="male" /><input type="radio" name="sex" v-model="userInfo.sex" value="female" /> <br /><br />爱好: 学习<input type="checkbox" v-model="userInfo.hobby" value="study" /> 打游戏<input type="checkbox" v-model="userInfo.hobby" value="game" /> 吃饭<inputtype="checkbox"v-model="userInfo.hobby"value="eat"/><br /><br />所属校区<select v-model="userInfo.city"><option value="">请选择校区</option><option value="beijing">北京</option><option value="shanghai">上海</option><option value="shenzhen">深圳</option><option value="wuhan">武汉</option></select><br /><br />其他信息:<textarea v-model.lazy="userInfo.other"></textarea> <br /><br /><input type="checkbox" v-model="userInfo.agree" />阅读并接受<a href="http://www.baidu.com">《用户协议》</a><button>提交</button></form></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {userInfo: {account: "",password: "",age: 18,sex: "female",hobby: [],city: "beijing",other: "",agree: ""}},methods: {demo() {console.log(JSON.stringify(this.userInfo));}}});</script></body>
</html>

运行结果如下:输入内容,勾选单选和复选框等控件,再点击提交按钮,可以看到控制台打印了表单提交的信息。

在这里插入图片描述

12. 内置指令

目前已经学过的内置指令有:v-bindv-modelv-onv-showv-ifv-elsev-for

12.1 v-text 解析普通文本

v-text指令:用于解析普通文本,向其所在的节点中渲染文本内容。

v-text与插值语法的区别:v-text会替换掉节点中的内容,而{{xxx}}则不会,因此{{xxx}}更加灵活,用的更多。

<!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="../js/vue.js"></script></head><body><div id="app"><!-- 插值语法相对v-text更加灵活 --><div>Hello, {{name}}</div><!-- v-text会替换掉节点中的内容 --><div v-text="name">Hello</div></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {name: "Jack"}});</script></body>
</html>

运行结果:

在这里插入图片描述

12.2 v-html 解析html标签

v-html指令:用于解析html标签,向其所在的节点中渲染包含html结构的内容。

v-html与插值语法的区别:v-html会替换掉节点中的内容,而{{xxx}}则不会。

注:v-html有安全性问题
1.在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击
2.一定要在可信的内容上使用v-html,永不要用在用户提交的内容上(如表单的输入框等)

<!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="../js/vue.js"></script></head><body><div id="app"><!-- v-text只能解析普通文本,无法解析html标签 --><div v-text="str"></div><!-- v-html可以解析html标签 --><div v-html="str"></div></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {str: `<h3>Hello World</h3>`}});</script></body>
</html>

运行结果:

在这里插入图片描述

12.3 v-cloak 隐藏模板

v-cloak指令:

  • 本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性
  • 该指令可以配合css属性选择器,解决网速慢时页面展示出{{xxx}}的问题
<!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="../js/vue.js"></script><style>/* 使用该属性的元素被隐藏 */[v-cloak] {display: none;}</style></head><body><div id="app"><!-- 初始时,v-cloak属性存在,但由于属性选择器的作用,会将h2标签隐藏;等到vue接管容器后,会移除掉h2上的v-cloak属性,此时会显示h2标签--><h2 v-cloak>{{name}}</h2></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {name: "Jack"}});</script></body>
</html>

12.4 v-once 仅渲染一次

v-once指令:

  • v-once所在节点在初次动态渲染后,就视为静态内容
  • 以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能
<!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="../js/vue.js"></script></head><body><div id="app"><h2 v-once>初始化的n值是:{{n}}</h2><h2>当前的n值是:{{n}}</h2><button @click="n++">点我n+1</button></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {n: 1}});</script></body>
</html>

运行结果:点击按钮,只有下面的n值发生变化,而上面的n值不变化

在这里插入图片描述

12.5 v-pre 跳过元素编译

v-pre指令:

  • 跳过其所在节点的编译过程
  • 可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译
<!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="../js/vue.js"></script></head><body><div id="app"><!-- 该标签未用到指令语法和插值语法,可以使用v-pre加快编译 --><h2 v-pre>Vue其实很简单</h2><h2>当前的n值是:{{n}}</h2><button @click="n++">点我n+1</button></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示const vm = new Vue({el: "#app",data: {n: 1}});</script></body>
</html>

13. 自定义指令

13.1 函数式和对象式

自定义指令有两种定义方式:

  • 函数式定义
  • 对象式定义

1.函数式定义

例:定义一个 v-big 指令,和 v-text 功能类似,但会把绑定的数值放大10倍

<!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="../js/vue.js"></script></head><body><div id="app"><h2>当前的n值是:<span v-text="n"></span></h2><h2>放大10倍后的n值是:<span v-big="n"></span></h2><button @click="n++">点我n+1</button></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示new Vue({el: "#app",data: {n: 1,},// 自定义指令directives: {// element表示真实的dom元素, binding表示绑定的对象big(element, binding) {element.innerText = binding.value * 10;},},});</script></body>
</html>

big函数被调用的条件:
1.指令与元素成功绑定时(一上来)
2.指令所在的模板被重新解析时

运行结果:点击按钮,上面的n值+1,下面的n值+1后乘以10倍

在这里插入图片描述

2.对象式定义

配置对象中常用的三个回调:

  • bind:指令与元素成功绑定时调用
  • inserted:指令所在元素被插入页面时调用
  • update:指令所在模板结构被重新解析时调用

对象式定义与函数式定义的区别:函数式定义写法等于对象式定义中的 bind + update 回调函数,而对象式定义还有inserted回调函数,可以实现函数式定义无法实现的细节操控。

例:定义一个 v-fbind 指令,和 v-bind 功能类似,但可以让其所绑定的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>Document</title><script src="../js/vue.js"></script></head><body><div id="app"><h2>当前的n值是:<span v-text="n"></span></h2><button @click="n++">点我n+1</button><br /><input type="text" v-fbind:value="n" /></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示new Vue({el: "#app",data: {n: 1,},// 自定义指令directives: {fbind: {//指令与元素成功绑定时(一上来)bind(element, binding) {element.value = binding.value;},//指令所在元素被插入页面时inserted(element, binding) {element.focus();},//指令所在的模板被重新解析时update(element, binding) {element.value = binding.value;},},},});</script></body>
</html>

运行结果:刷新页面后,文本框默认获取焦点,点击按钮后失去焦点

在这里插入图片描述

13.2 局部指令和全局指令

自定义指令分为两类:

  • 局部指令
  • 全局指令

1.局部指令写法

// 函数式定义new Vue({															directives:{指令名:回调函数}   }) 	// 对象式定义	new Vue({															directives:{指令名:配置对象}   }) 		
new Vue({// 局部自定义指令directives: {// 函数式定义big(element, binding) {element.innerText = binding.value * 10;},// 对象式定义fbind: {bind(element, binding) {element.value = binding.value;},inserted(element, binding) {element.focus();},update(element, binding) {element.value = binding.value;},},},
});

2.全局指令写法

// 函数式定义
Vue.directive(指令名, 回调函数)
// 对象式定义
Vue.directive(指令名, 配置对象)
 // 函数式定义Vue.directive("big", function (element, binding) {element.value = binding.value;});// 对象式定义Vue.directive("fbind", {bind(element, binding) {element.value = binding.value;},inserted(element, binding) {element.focus();},update(element, binding) {element.value = binding.value;},});

自定义指令注意事项:
1.指令定义时不加v-,但使用时要加v-;
2.指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名。

new Vue({directives: {"big-number"(element, binding) {element.innerText = binding.value * 10;},},
});

14. Vue的生命周期

14.1 生命周期概念

Vue的生命周期:又称生命周期回调函数、生命周期函数、生命周期钩子,是Vue在关键时刻帮我们调用的一些特殊名称的函数。

生命周期函数中的this指向是vm 或 组件实例对象

vue的生命周期分为以下四个流程:每个流程对应两个函数,其中最重要的是mountedbeforeDestroy

  • 创建流程:
    • beforeCreate:此时无法通过vm访问到data中的数据和methods中的方法。
    • created:此时可以通过vm访问到data中的数据和methods中配置的方法。
  • 挂载流程:
    • beforeMount:此时页面呈现的是未经Vue编译的DOM结构,所有对DOM的操作,最终都不奏效。
    • mounted:此时页面呈现的是经过Vue编译的DOM,对DOM的操作均有效(尽可能避免)。至此初始化过程结束,一般在此阶段:开启定时器、发送网络请求、订阅消息以及绑定自定义事件等初始化操作
  • 更新流程:
    • beforeUpdate:此时数据是新的,但页面是旧的,即页面尚未和数据保持同步。
    • updated:此时数据是新的,页面也是新的,即页面尚未和数据保持同步。
  • 销毁流程
    • beforeDestroy:此时vm中所有的data、methods和指令等等,都处于可用状态,马上要执行销毁过程。一般在此阶段:关闭定时器、取消订阅消息以及解绑自定义事件等收尾操作
    • destroyed:此时vm已完成销毁。

Vue的生命周期流程图:
在这里插入图片描述

14.2 生命周期演示

1.生命周期钩子函数的调用顺序

<!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="../js/vue.js"></script></head><body><!-- 准备好一个容器--><div id="app"><h2>当前的n值是:{{n}}</h2><button @click="add">点我n+1</button><button @click="bye">点我销毁vm</button></div><script>Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示new Vue({el: "#app",data: {n: 1,},methods: {add() {this.n++;},bye() {this.$destroy();},},beforeCreate() {console.log("beforeCreate");},created() {console.log("created");},beforeMount() {console.log("beforeMount");},mounted() {console.log("mounted");},beforeUpdate() {console.log("beforeUpdate");},updated() {console.log("updated");},beforeDestroy() {console.log("beforeDestroy");},destroyed() {console.log("destroyed");},});</script></body>
</html>

在这里插入图片描述

2.生命周期的常用应用场景

常用的生命周期钩子:

  • mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等(初始化操作)
  • beforeDestroy: 清除定时器、解绑自定义事件、取消订阅消息等(收尾操作)

关于销毁Vue实例:

  • 销毁后借助Vue开发者工具看不到任何信息
  • 销毁后自定义事件会失效,但原生DOM事件依然有效
  • 一般不会在beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程了
<!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="../js/vue.js"></script></head><body><!-- 准备好一个容器--><div id="app"><h2 :style="{opacity}">欢迎学习Vue</h2><button @click="opacity = 1">透明度设置为1</button><button @click="stop">点我停止变换</button></div><script>Vue.config.productionTip = false; //阻止 vue 在启动时生成生产提示。new Vue({el: "#app",data: {opacity: 1,},methods: {stop() {this.$destroy(); // 销毁vm},},//Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mountedmounted() {// 初始化操作:启动定时器console.log("mounted", this);this.timer = setInterval(() => {console.log("setInterval");this.opacity -= 0.01;if (this.opacity <= 0) this.opacity = 1;}, 16);},beforeDestroy() {// 收尾操作:清除定时器clearInterval(this.timer);},});</script></body>
</html>

运行结果:
未点击按钮停止变换前,点击设置透明度有效;点击按钮停止变换后,再点击设置透明度则无效,因为vm被销毁了。
在这里插入图片描述

15. Vue的组件化编程

15.1 模块与组件

1.模块与模块化:

  • 模块:一个模块就是一个js文件,向外提供特定功能的 js 程序,作用是可以复用 js、简化 js 的编写、提高 js 运行效率。
  • 模块化:当应用中的 js 都以模块来编写的, 那这个应用就是一个模块化的应用。

2.组件与组件化:

  • 组件:用来实现局部(特定)功能效果的代码集合(html/css/js/image……),作用是复用编码、简化项目编码、提高运行效率。
  • 组件化:当应用中的功能都是多组件的方式来编写的, 那这个应用就是一个组件化的应用。

传统方式编写应用:

在这里插入图片描述

组件化方式编写应用:

在这里插入图片描述

15.2 非单文件组件

组件的分类:

  • 非单文件组件:模板编写没有提示, 没有构建过程,无法将 ES6 转换,不支持组件的 CSS,真正开发中几乎不用。
  • 单文件组件:单文件组件为 .vue 文件,由<template> 模板页面、<script> JS模块对象和 <style> 样式组成。

虽然非单文件组件在开发中几乎不用,但是要想学会单文件组件( .vue) ,必须先从非单文件组件开始入手。

15.2.1 组件的基本使用

Vue中使用组件的三大步骤:

  • 创建组件
  • 注册组件
  • 使用组件

1.创建组件:

  • 使用 Vue.extend(options) 创建组件
  • Vue.extend(options)new Vue(options) 时传入的 options 几乎一样,但有区别如下:
    • el 不能写,因为最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器
    • data 必须写成函数,为了避免组件被复用时,数据存在引用关系

注:使用template可以配置组件结构

2.注册组件

  • 局部注册:靠 new Vue 的时候传入 components 配置项
  • 全局注册:靠 Vue.component('组件名',组件)

3.使用组件:编写组件标签,使用组件

组件示例如下:

<!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="../js/vue.js"></script></head><body><!-- 准备好一个容器--><div id="app"><!-- 第三步:使用student组件 --><student></student></div><script>Vue.config.productionTip = false; //阻止 vue 在启动时生成生产提示。// 第一步:创建student组件const student = Vue.extend({template: `<div><h2>学生姓名:{{name}}</h2><h2>学生年龄:{{age}}</h2><button @click="showName">点我提示姓名</button>	</div>`,// 组件定义时,一定不要写el配置项,因为最终所有的组件都要被一个vm管理,由vm决定服务于哪个容器data() {return {name: "张三",age: 18,};},methods: {showName() {alert(this.name);},},});// 第二步:注册student组件(局部注册)new Vue({el: "#app",components: {student,},});</script></body>
</html>

以上局部注册也可改为全局注册:

// 第二步:注册student组件
Vue.component("student", student);new Vue({el: "#app",
});

15.2.2 组件的注意事项

1.组件名的取名:

  • 组件名由一个单词组成:
    • 第一种写法(首字母小写):school
    • 第二种写法(首字母大写):School(推荐)
  • 组件名由多个单词组成:
    • 第一种写法(kebab-case命名):my-school
    • 第二种写法(CamelCase命名):MySchool (推荐,且该写法需要Vue脚手架支持)

2.组件标签的两种写法

  • 双标签:<school></school>
  • 单标签:school/>

备注:不用使用脚手架时,<school/> 会导致后续组件不能渲染

3.Vue.extend()可以简写:const school = Vue.extend(options) ,可简写为 const school = options

<!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="../js/vue.js"></script></head><body><!-- 准备好一个容器--><div id="app"><!-- 第三步:使用student组件 --><Student /></div><script>Vue.config.productionTip = false; //阻止 vue 在启动时生成生产提示。// 第一步:创建student组件,简写省略了Vue.extend()const Student = {template: `<div><h2>学生姓名:{{name}}</h2><h2>学生年龄:{{age}}</h2><button @click="showName">点我提示姓名</button>	</div>`,// 组件定义时,一定不要写el配置项,因为最终所有的组件都要被一个vm管理,由vm决定服务于哪个容器data() {return {name: "张三",age: 18,};},methods: {showName() {alert(this.name);},},};// 第二步:注册student组件new Vue({el: "#app",components: {Student,},});</script></body>
</html>

15.2.3 组件的嵌套

组件的嵌套:
在这里插入图片描述

<!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="../js/vue.js"></script></head><body><!-- 准备好一个容器--><div id="root"></div><script>Vue.config.productionTip = false; //阻止 vue 在启动时生成生产提示。//定义student组件const student = Vue.extend({name: "student",template: `<div><h2>学生姓名:{{name}}</h2>	<h2>学生年龄:{{age}}</h2>	</div>`,data() {return {name: "张三",age: 18,};},});//定义school组件const school = Vue.extend({name: "school",template: `<div><h2>学校名称:{{name}}</h2>	<h2>学校地址:{{address}}</h2>	<student></student></div>`,data() {return {name: "北京大学",address: "北京",};},//注册组件(局部),school中嵌套studentcomponents: {student,},});//定义hello组件const hello = Vue.extend({template: `<h1>{{msg}}</h1>`,data() {return {msg: "欢迎来到北京!",};},});//创建vmnew Vue({template: `<div><hello></hello>	<school></school>	</div>`,el: "#root",//注册组件(局部)components: {hello,school,},});</script></body>
</html>

组件之间结构如下:

在这里插入图片描述

15.2.4 VueComponent

关于VueComponent:

1.school 组件本质是一个名为 VueComponent 的构造函数,且不是程序员定义的,是 Vue.extend 生成的

2.我们只需要编写 <school/><school></school>,Vue解析时会帮我们创建school组件的实例对象,即Vue帮我们执行了 new VueComponent(options)

3.特别注意,每次调用 Vue.extend,返回的都是一个全新的 VueComponent

4.关于this指向:

  • 组件配置中的this指向:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是 VueComponent 实例对象
  • new Vue(options)配置中的this指向:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是 Vue 实例对象

15.2.5 一个重要的内置关系

一个重要的内置关系:VueComponent.prototype.__proto__ === Vue.prototype,这个关系可以让VueComponent组件实例对象访问到 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="../js/vue.js"></script></head><body><div id="root"></div><script>Vue.config.productionTip = false; //阻止 vue 在启动时生成生产提示。Vue.prototype.x = 99;//定义school组件const school = Vue.extend({name: "school",template: `<div><h2>学校名称:{{name}}</h2>	<h2>学校地址:{{address}}</h2>	<button @click="showX">点我输出x</button></div>`,data() {return {name: "北京大学",address: "北京",};},methods: {showX() {alert(this.x);},},});new Vue({template: `<school></school>`,el: "#root",components: { school },});</script></body>
</html>

15.3 单文件组件

15.3.1 单文件组件的组成

单文件组件:即一个 .vue 文件,由以下三部分组成

  • <template> : 模板页面
  • <script> :JS模块对象
  • <style> : 样式

1.模板页面

<template>
页面模板
</template>

2.JS模块对象

<script>export default {data() {return {};},methods: {},computed: {},components: {},};
</script>

3.样式

<style>
样式定义
</style>

15.3.2 单文件组件的示例

本节仅展示代码和文件之间的关联逻辑,此处的代码无法直接运行,需要搭建脚手架环境以后才能运行。

示例:有以下文件结构,作为单文件组件的实际开发使用

在这里插入图片描述

文件之间关系如下:

  • index.html :主页面
  • main.js :程序入口
  • App.vue :汇总所有组件,此处包括School和Student组件
  • School.vue :学校组件
  • Student.vue :学生组件

index.html

<!DOCTYPE html>
<html><head><meta charset="UTF-8" /><title>Document</title></head><body><!-- 准备一个容器 --><div id="root"></div><script type="text/javascript" src="../js/vue.js"></script><script type="text/javascript" src="./main.js"></script></body>
</html>

main.js

import App from './App.vue'new Vue({el:'#root',template:`<App></App>`,components:{App},
})

App.vue

<template><div><School></School><Student></Student></div>
</template><script>
//引入组件
import School from "./School.vue";
import Student from "./Student.vue";export default {name: "App",components: {School,Student,},
};
</script>

School.vue

<template><div class="demo"><h2>学校名称:{{name}}</h2><h2>学校地址:{{address}}</h2><button @click="showName">点我提示学校名</button>	</div>
</template><script>export default {name:'School',data(){return {name:'北京大学',address:'北京'}},methods: {showName(){alert(this.name)}},}
</script><style>.demo{background-color: orange;}
</style>

Student.vue

<template><div><h2>学生姓名:{{name}}</h2><h2>学生年龄:{{age}}</h2></div>
</template><script>export default {name:'Student',data(){return {name:'张三',age:18}}}
</script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/731992.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

typescript学习(更新中)

目录 开发环境搭建类型如何声明有哪些类型编译配置文件 开发环境搭建 npm i -g typescripttsc检查是否安装成功 类型如何声明 // 先声明再赋值 let a: number a 1// 直接赋值 let b 1function sum(a: number, b: number): number {return a b } console.log(sum(1, 2))有…

leetcode72. 编辑距离

leetcode72. 编辑距离 题目 思路 dp[i][j] 代表 word1 到 i 位置转换成 word2 到 j 位置需要最少步数&#xff0c;所以&#xff0c; 当 word1[i] word2[j]&#xff0c;dp[i][j] dp[i-1][j-1]&#xff1b; 当 word1[i] ! word2[j]&#xff0c;dp[i][j] 1 min(dp[i-1][j-1]…

Ubantu 18.04 如何映射IP到公网,外网可以访问

介绍一种简单的方式&#xff0c;就是通过路由侠 inux 系统安装路由侠&#xff0c;可通过两种方式进行&#xff0c;一种是通过直接脚本安装&#xff0c;一种是通过 Docker 安装。 windows下载地址&#xff1a;路由侠-局域网变公网 方式一&#xff1a;通过脚本安装 1、获取安…

java算法第十七天 | ● 110.平衡二叉树 ● 257. 二叉树的所有路径 ● 404.左叶子之和

110.平衡二叉树 leetcode链接 思路&#xff1a; 使用后序遍历分别求左右子树的高度&#xff0c;若高度只差大于一&#xff0c;则返回-1&#xff0c;否则返回当前节点的最大高度。 /*** Definition for a binary tree node.* public class TreeNode {* int val;* Tree…

【数据分享】2013-2022年全国范围逐日SO2栅格数据

空气质量数据是在我们日常研究中经常使用的数据&#xff01;之前我们给大家分享了2013-2022年全国范围逐月SO2栅格数据和逐年SO2栅格数据&#xff08;均可查看之前的文章获悉详情&#xff09;。 本次我们给大家带来的是2013-2022年全国范围的逐日的SO2栅格数据&#xff0c;原始…

阿里云几核服务器够用?内存多少合适?

阿里云服务器配置怎么选择&#xff1f;CPU内存、公网带宽和系统盘怎么选择&#xff1f;个人开发者或中小企业选择轻量应用服务器、ECS经济型e实例&#xff0c;企业用户选择ECS通用算力型u1云服务器、ECS计算型c7、通用型g7云服务器&#xff0c;阿里云服务器网aliyunfuwuqi.com整…

OJ_二叉排序树

题干 C实现 循环双指针法(一个指向父亲&#xff0c;一个指向待插入结点) #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <queue> using namespace std;struct TreeNode {char data;TreeNode* left;TreeNode* right; };void InsertBST(TreeNode* …

C# OpenCvSharp DNN FreeYOLO 人脸检测

目录 效果 模型信息 项目 代码 下载 C# OpenCvSharp DNN FreeYOLO 人脸检测 效果 模型信息 Inputs ------------------------- name&#xff1a;input tensor&#xff1a;Float[1, 3, 192, 320] --------------------------------------------------------------- Outp…

每日OJ题_链表⑤_力扣25. K 个一组翻转链表

目录 力扣25. K 个一组翻转链表 解析代码 力扣25. K 个一组翻转链表 25. K 个一组翻转链表 难度 困难 给你链表的头节点 head &#xff0c;每 k 个节点一组进行翻转&#xff0c;请你返回修改后的链表。 k 是一个正整数&#xff0c;它的值小于或等于链表的长度。如果节点总…

音视频按照时长分类小工具

应某用户的需求&#xff0c;编写了这款根据音视频时长分类小工具。 实际效果如下&#xff1a; 显示的是时分秒&#xff1a; 核心代码&#xff1a; MediaInfo MI; if (MI.Open(strPathInput.c_str()) 0){return -1;}_tstring stDuration MI.Get(stream_t::Stream_Audio,0,_T…

GitHub和Gitee的基本使用和在IDEA中的集成

文章目录 【1】GitHub1.创建仓库2.增加和修改文件3.创建分支4.删除仓库5.远程仓库下载到本地 【2】Gitee1.创建仓库2.远程仓库下载到本地. 【3】IDEA集成GitHub【4】IDEA集成Gitee1.在Gitee中修改&#xff0c;同步到本地2.从Gitee中下载项目 【1】GitHub 1.创建仓库 先登陆这…

阿里云99计划优惠:云服务器租用价格61元、99元、165元

阿里云99计划还有谁不知道么&#xff1f;阿里云不杀熟&#xff0c;新老用户同享&#xff0c;阿里云服务器99元一年&#xff0c;续费也是99元&#xff0c;续费不涨价家人们&#xff0c;2024年阿里云把云服务器价格打下来了&#xff0c;2核2G、2核4G、4核8G、4核16G、8核16G、8核…

【无标题】带大家做一个,易上手的家常西芹牛肉丸

这里 我准备的是 潮汕手工牛肉丸 都是弄好 里面有盐的 先拿出来清水化冰 准备一些西芹 切小段 一根胡萝卜 萝卜切片 和西芹段装在一起 调一碗料汁 两勺胡椒粉 一勺淀粉 一点清水 然后拿勺子搅拌均匀 三瓣大蒜 切成蒜末 导入 西芹段 萝卜片 高过菜的清水 一小勺食用油 小…

Web APIs 4 日期对象、节点操作

Web APIs 4 一、日期对象实例化日期对象方法案例&#xff1a;页面显示时间 时间戳 二、节点操作查找结点①父节点查找②子节点查找③兄弟节点查找 增加节点克隆节点删除节点 三、M端事件四、JS插件 一、日期对象 学习路径&#xff1a;实例化、日期对象方法、时间戳 实例化 …

【MySQL 系列】MySQL 语句篇_DML 语句

DML&#xff08;Data Manipulation Language&#xff09;&#xff0c;即数据操作语言&#xff0c;用于操作数据库对象中所包含的数据。常用关键字包括&#xff1a;插入&#xff08;INSERT&#xff09;、更新&#xff08;UPDATE&#xff09;、删除&#xff08;DELETE&#xff09…

Linux命令详解——mkdir创建文件夹与touch创建文件

在windows图形化系统中想要通识创建多个文件夹似乎是一件比较困难的事情&#xff0c;但在linux系统下&#xff0c;这将变得简单 mkdir参数&#xff0c;-p&#xff0c;递归创建文件夹 mkdir创建多个文件 touch可以创建文件&#xff0c;以及修改文件时间

idea远程服务器debug

前提 本地代码和服务器代码一致 idea中创建远程服务 一般只需要修改ip&#xff0c;注意这边的端口是监听Socket的端口&#xff0c;不是服务的端口 然后把运行参数复制一下 -agentlib:jdwptransportdt_socket,servery,suspendn,address5005 tomcat启动 在tomcat的lib下的c…

Pytorch学习 day07(神经网络基本骨架的搭建、2D卷积操作、2D卷积层)

神经网络基本骨架的搭建 Module&#xff1a;给所有的神经网络提供一个基本的骨架&#xff0c;所有神经网络都需要继承Module&#xff0c;并定义_ _ init _ _方法、 forward() 方法在_ _ init _ _方法中定义&#xff0c;卷积层的具体变换&#xff0c;在forward() 方法中定义&am…

HTML入门:属性

你好&#xff0c;我是云桃桃。今天来聊一聊 HTML 属性写法和特点。 HTML 属性是用于向 HTML 标签&#xff08;也叫 HTML 元素&#xff09;提供附加信息或配置的特性。 如果说&#xff0c;把HTML 标签比作一个房子&#xff0c;HTML 标签定义了房子的结构和用途&#xff0c;比如…

FPGA高端项目:FPGA基于GS2971的SDI视频接收+HLS图像缩放+多路视频拼接,提供4套工程源码和技术支持

目录 1、前言免责声明 2、相关方案推荐本博已有的 SDI 编解码方案本方案的SDI接收转HDMI输出应用本方案的SDI接收图像缩放应用本方案的SDI接收纯verilog图像缩放纯verilog多路视频拼接应用本方案的SDI接收OSD多路视频融合叠加应用本方案的SDI接收HLS多路视频融合叠加应用本方案…