当前位置: 首页 > news >正文

【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>

相关文章:

【Web前端】Vue核心基础

文章目录 1. Vue简介2. Vue官网使用指南3. 初识Vue3.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…...

Linux操作系统项目上传Github代码仓库指南

文章目录 1 创建SSH key2.本地git的用户名和邮箱设置3.测试连接4.创建仓库5.终端项目上传 1 创建SSH key 1.登录github官网,点击个人头像,点击Settings,然后点击SSH and GPG keys,再点击New SSH key。 Title 可以随便取&#xff0c;但是 key 需要通过终端生成。 Linux终端执行…...

机器学习--循环神经网路(RNN)2

在这篇文章中&#xff0c;我们介绍一下其他的RNN。 一.深层RNN 循环神经网络的架构是可以任意设计的&#xff0c;之前提到的 RNN 只有一个隐藏层&#xff0c;但 RNN 也可以是深层的。比如把 xt 丢进去之后&#xff0c;它可以通过一个隐藏层&#xff0c;再通过第二个隐藏层&am…...

sheng的学习笔记-AI-多分类学习:ECOC,softmax

目录&#xff1a;sheng的学习笔记-AI目录-CSDN博客 基本术语&#xff1a; 若我们欲预测的是离散值&#xff0c;例如“好瓜”“坏瓜”&#xff0c;此类学习任务称为“分类”(classification)&#xff1b; 若欲预测的是连续值&#xff0c;例如西瓜成熟度0.95、0.37&#xff0c;…...

ChatGPT Plus 支付出现「您的银行卡被拒绝/your card has been declined」怎么办?

ChatGPT Plus 支付出现「您的银行卡被拒绝/your card has been declined」怎么办&#xff1f; 在订阅 ChatGPT Plus 或者 OpenAI API 时&#xff0c;有时候会出现已下报错 &#xff1a; Your card has been declined. 您的银行卡被拒绝 出现这种错误&#xff0c;有以下几个解…...

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))有…...

T2 小美的平衡矩阵(25分) - 美团编程题 题解

考试平台&#xff1a; 牛客网 题目类型&#xff1a; 30道单选题&#xff08;60分&#xff09; 2 道编程题 &#xff08;15分 25分&#xff09; 考试时间&#xff1a; 2024-03-09 &#xff08;两小时&#xff09; 题目描述 小美拿到了一个n*n的矩阵&#xff0c;其中每个元素是…...

13:大数据与Hadoop|分布式文件系统|分布式Hadoop集群

大数据与Hadoop&#xff5c;分布式文件系统&#xff5c;分布式Hadoop集群 Hadoop部署Hadoop HDFS分布式文件系统HDFS部署步骤一&#xff1a;环境准备HDFS配置文件 查官方手册配置Hadoop集群 日志与排错 mapreduce 分布式离线计算框架YARN集群资源管理系统步骤一&#xff1a;安装…...

前端知识点、技巧、webpack、性能优化(持续更新~)

1、 请求太多 页面加载慢 &#xff08;webpack性能优化&#xff09; 可以把 图片转换成 base64 放在src里面 减少服务器请求 但是图片会稍微大一点点 以上的方法不需要一个一个自己转化 可以在webpack 进行 性能优化 &#xff08;官网有详细描述&#xff09;...

红队专题-开源漏扫-巡风xunfeng源码剖析与应用

开源漏扫-巡风xunfeng 介绍主体两部分:网络资产识别引擎,漏洞检测引擎。代码赏析插件编写JSON标示符Python脚本此外系统内嵌了辅助验证功能文件结构功能 模块添加IP三. 进行扫描在这里插入图片描述 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/de587a6f6f694…...

统计接口调用耗时情况设计思路(大厂面试题)

gateway统计接口调用耗时情况设计思路&#xff08;大厂面试题&#xff09; 详情视频可以去看尚硅谷2024周阳老师的springCloud P86 知识出处自定义全局过滤器官网https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-combined-global-filter-…...

Elasticsearch:什么是 DevOps?

DevOps 定义 DevOps 是一种现代软件开发方法&#xff0c;它将公司软件开发 (Dev) 和 IT 运营 (Ops) 团队的工作结合起来并实现自动化。 DevOps 提倡这样一种理念&#xff1a;这些传统上独立的团队在协作方面比在孤岛中更有效。 理想情况下&#xff0c;DevOps 团队共同努力改进…...

C语言基础练习——Day03

目录 选择题 编程题 记负均正 旋转数组的最小数字 选择题 1、已知函数的原型是&#xff1a;int fun(char b[10], int *a);&#xff0c;设定义&#xff1a;char c[10];int d;&#xff0c;正确的调用语句是 A fun(c,&d);B fun(c,d);C fun(&c,&d);D fun(&c,d); 答…...

膜厚测量仪在半导体应用中及其重要

随着科技的不断发展&#xff0c;半导体行业已成为当今世界的核心产业之一。在这个领域中&#xff0c;半导体膜厚测量仪作为关键设备&#xff0c;其精度和可靠性对于产品质量和生产效率具有至关重要的作用。本文将详细介绍半导体膜厚测量仪的工作原理、应用领域以及其在半导体制…...

【前端】-初始前端以及html的学习

&#x1f496;作者&#xff1a;小树苗渴望变成参天大树&#x1f388; &#x1f389;作者宣言&#xff1a;认真写好每一篇博客&#x1f4a4; &#x1f38a;作者gitee:gitee✨ &#x1f49e;作者专栏&#xff1a;C语言,数据结构初阶,Linux,C 动态规划算法&#x1f384; 如 果 你 …...

uni-app navigateTo路由传参传递对象

传递参数 先通过JSON.stringify将对象转成字符串 toNextPage(obj) {uni.navigateTo({url:/pages/nextpage/index?obj${JSON.stringify(obj)}}); },接收参数 再通过JSON.parse将传递过来的字符串转成对象 onLoad(options) {this.obj JSON.parse(options.obj) }...

99 centos 7 服务器上面 增加了 2181 的防火墙配置, 但是客户端连接不上

呵呵 最近部署 zookeeper 的时候出现这样的一个问题 centos 7 服务器上面 增加了 2181 的防火墙配置, 但是客户端连接不上 # 但是再 另外的一个虚拟机环境, ubuntu 16 的环境, docker 启动 2181 的服务, 然后 安装 firewalld, 配置 开放 2181 的 tcp 服务, 客户端能够正常连接…...

云计算科学与工程实践指南--章节引言收集

云计算科学与工程实践指南–章节引言收集 //本文收集 【云计算科学与工程实践指南】 书中每一章节的引言。 我已厌倦了在一本书中阅读云的定义。难道你不失望吗&#xff1f;你正在阅读一个很好的故事&#xff0c;突然间作者必须停下来介绍云。谁在乎云是什么&#xff1f; 通…...

探索Web中的颜色选择:不同取色方法的实现

在Web开发中&#xff0c;提供用户选择颜色的功能是很常见的需求。无论是为了个性化UI主题&#xff0c;还是为了图像编辑工具&#xff0c;一个直观且易用的取色器都是必不可少的。本文将介绍几种在Web应用中实现取色功能的方法&#xff0c;从简单的HTML输入到利用现代API的高级技…...

突破编程_C++_设计模式(策略模式)

1 策略模式的概念 策略模式&#xff08;Strategy Pattern&#xff09;是 C 中常用的一种行为设计模式&#xff0c;它能在运行时改变对象的行为。在策略模式中&#xff0c;一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为模式。 在策略模式中&#xff0c;需…...

vscode里如何用git

打开vs终端执行如下&#xff1a; 1 初始化 Git 仓库&#xff08;如果尚未初始化&#xff09; git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

SciencePlots——绘制论文中的图片

文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了&#xff1a;一行…...

React第五十七节 Router中RouterProvider使用详解及注意事项

前言 在 React Router v6.4 中&#xff0c;RouterProvider 是一个核心组件&#xff0c;用于提供基于数据路由&#xff08;data routers&#xff09;的新型路由方案。 它替代了传统的 <BrowserRouter>&#xff0c;支持更强大的数据加载和操作功能&#xff08;如 loader 和…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

【位运算】消失的两个数字(hard)

消失的两个数字&#xff08;hard&#xff09; 题⽬描述&#xff1a;解法&#xff08;位运算&#xff09;&#xff1a;Java 算法代码&#xff1a;更简便代码 题⽬链接&#xff1a;⾯试题 17.19. 消失的两个数字 题⽬描述&#xff1a; 给定⼀个数组&#xff0c;包含从 1 到 N 所有…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解

本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码

目录 一、&#x1f468;‍&#x1f393;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站效果 五、&#x1fa93; 代码实现 &#x1f9f1;HTML 六、&#x1f947; 如何让学习不再盲目 七、&#x1f381;更多干货 一、&#x1f468;‍&#x1f…...

C++.OpenGL (14/64)多光源(Multiple Lights)

多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...