认识Vue
- Vue是一套用于构建用户界面的渐进式JS框架
- 渐进式框架: 表示我们可以在项目中一点点来引用和使用Vue, 而不是需要全部使用Vue来开发整个项目
Vue初体验
-
案例: 计数器
-
当前计数: {{counter}}
+ -
声明式和命令式
- 命令式编程关注的是“how to do” 自己完成整个how的过程
- 声明式编程关注的是“what to do” 由框架完成how的过程
- 早期JS是命令式编程
- 我们每完成一个操作,都需要通过JS代码编写一条代码,来给浏览器一个指令
- Vue是声明式编程
- 在createApp传入的对象中声明需要的内容:
- data(){} 数据
- methods:{} 方法
- template:{} 模板
- 在createApp传入的对象中声明需要的内容:
MVVM模型
- MVC和MVVM都是一种软件的体系结构
- MVC是Model-View-Controller
- MVVM是Model-View-ViewModel
- Vue虽然没有完全遵守MVVM的模型, 但是整个设计是受它的启发
属性
- data属性
- data属性是传入一个函数, 并且该函数需要返回一个对象
- data中返回的对象会被Vue的响应式系统劫持, 之后对该对象的修改或者访问都会在劫持中被处理
- 所以我们在template或者app中通过 {{counter}} 访问counter, 可以从对象中获取到数据
- 所以我们修改counter值时, app中的 {{counter}} 也会发生改变
- methods属性
- methods属性是一个对象, 我们在这个对象中定义很多方法
- 这些方法被绑定在 模板中
- 在该方法中, 我们可以使用this来直接访问到data函数中返回的对象的属性
- 两个问题
- 问题一: 为什么不能使用箭头函数?
- 我们在methods中要使用data返回对象中的数据, 那么这个this是必须有值的, 并且应该可以通过this获取到data返回对象中的数据
- 这个this不能是window, 因为window无法获取到data返回对象中的数据
- 问题二: this到底指向什么?
- 事实上源码当中就是对methods中的所有函数进行了便利, 并且通过bind绑定了this
- 问题一: 为什么不能使用箭头函数?
- methods属性是一个对象, 我们在这个对象中定义很多方法
Mustache双大括号语法
- 如果我们希望把数据显示到模板(template)中, 使用最多的语法是“Mustache”语法的文本插值
- 正确的用法
- 基本用法: {{message}}
- JS表达式: {{counter * 2}}
- 调用一个methods中的函数: {{reverse(message)}}
- 错误的用法
- 这是一个赋值语句,不是表达式: {{var name = “Hello”}}
- 控制流的if语句不支持, =可以用三元运算符
v-once指令(了解)
- v-once用于指定元素或组建只渲染一次
- 当数据发生改变时, 元素或组件以及其所有的子元素将视为静态内容并且跳过
v-text指令(了解)
-
用于更新元素的textContent(下面两个表达式等价)
-
{{msg}}
v-html
-
默认情况下, 如果我们展示的内容本身是html的, 那么vue并不会对其进行特殊的解析, 如果我们希望这个内容被vue解析出来, 可以用v-html来展示
v-pre
- v-pre用于跳过元素和它的子元素的编译过程, 显示原始的Mustache标签
v-cloak
- 这个指令保持在元素上直到关联组件实例结束编译
v-bind (:)
绑定class介绍
-
在开发中, 有时候我们的元素class也是动态的, 比如
- 当数据为某个状态时, 字体显示红色
- 当数据另一个状态时, 字体显示黑色
-
绑定class有两种方法
-
对象语法
-
普通的绑定方式:
{{message}} -
对象绑定:
{{message}} -
绑定对象:
{{message}} -
从methods中获取:
{{message}}
-
-
数组语法
-
直接传入一个数组:
{{message}} -
数组中也可以使用三元运算符:
{{message}} -
数组中也可以使用对象语法:
{{message}}
-
-
绑定style介绍
-
我们可以利用 v-bind:style 来绑定一些CSS内联样式
-
CSSproperty名可以用驼峰式或横线分隔来命名
-
绑定class有两种方法
-
对象语法
-
基本使用: 传入一个对象, 并且对象内容都是确定的
{{message}} -
变量数据: 传入一个对象, 值会来自于data
{{message}} -
对象数据: 直接在data中定义好对象在这里使用
{{message}}
-
-
数组语法
-
:style的数组语法可以将多个样式对象应用到同一个元素上
{{message}}
-
-
动态绑定属性
-
前端我们无论绑定src、href、class、style, 属性名称都是固定的
-
如果属性名称不是固定的, 我们可以使用: [属性名]=“值” 的格式来定义
-
这样的绑定方式称为动态绑定属性
{{message}}
绑定一个对象
-
如果我们希望将一个对象的所有属性, 绑定到元素上的所有属性, 可以直接使用v-bind绑定一个对象
{{message}}
v-on (@)
-
使用v-on监听用户发生的事件, 比如点击、拖拽、键盘事件等等
-
基本用法
- @click=“btn” 点击
- @mousemove=“abc” 移动
-
一个元素绑定多个事件, 这时候可以传入一个对象(不能使用语法糖)
-
v-on参数传递
- 当通过methods中定义方法, 以供@click调用时, 需要注意
- 情况一: 如果该方法不需要额外参数, 那么方法后的()可以不添加
- 如果方法本身中有一个参数, 那么会默认将原生事件event参数传递进去
- 情况二: 如果需要同时传入某个参数, 同时需要event时, 可以通过$event传入事件
- 理解成@click=“函数名”(调用函数), 这个函数在methods中定义, 不需要参数时可以省略(), 需要参数时不能省略
- v-on的修饰符.stop、.self、.once、.left、.right...
条件渲染
- v-if、v-else、v-else-if
- 作为元素指令添加到元素上, 当条件为true时, 元素和内容才会被渲染出来
- v-if=“判断语句” 其他同理
- template元素
- 因为v-if是一个指令, 所以必须将其添加到一个元素上
- 但是如果我们希望切换的是多个元素呢
- 此时我们渲染div, 但是我们并不希望div这种元素被渲染
- 这个时候, 我们可以选择使用template
- template元素可以当作不可见的包裹元素, 并且在v-if上使用, 但是最终template不会被渲染出来
- 简单来说template元素可以使它的子元素全部统一拥有v-if, 并且自己不会成为一个盒子
- 因为v-if是一个指令, 所以必须将其添加到一个元素上
- v-show
- v-show和v-if的用法区别
- v-show不支持template
- v-show不能和v-else一起使用
- v-show和v-if的本质区别
- v-show元素无论是否需要显示到浏览器上, 它的DOM实际都是存在的, 只是通过CSS的display属性来进行切换
- v-if当条件为false时, 其对应的原生压根不会被渲染到DOM上
- 如何选择
- 如果只是需要在显示和隐藏之间频繁切换, v-show
- 如果不会频繁切换, v-if
- v-show和v-if的用法区别
v-for
-
通过v-for实现列表渲染
-
v-for基本使用
- v-for的格式是“item in 数组”
- 数组通常来自data或者prop, 也可以是其他方式
- item自定义名字
- 一个数组的遍历经常需要拿到数组的索引
- 索引格式: “(item, index) in 数组”
- 注意顺序: 数组元素项item是在前面的, 索引项index是在后面的
- v-for=“item in 数组”、v-for=“(item, index) in 数组”, 拿到item和index后可以通过Mustache语法在元素内容中展示
- v-for的格式是“item in 数组”
-
v-for支持的类型
-
支持遍历对象
{{index}}-{{key}}-{{value}} -
支持遍历数字
{{index}} -
也可以遍历其他可迭代对象
-
-
templqte元素
- 和v-if一样, 如果想包裹元素又不想渲染
复杂data的处理方式
- 在模板template中可以通过差值语法显示一些data中的数据
- 但是在某些情况, 我们可能需要对数据进行一些转化后再显示、或者需要将多个数据结合起来进行显示
- 模板中使用表达式只用于简单计算, 放入太多难以维护, 有可能大量重复代码
- 方法
- 将逻辑抽取到一个methods中, 放到methods的options中, 弊端是所有data使用过程中都会编程一个方法的调用
- computed
计算属性computed
-
案例:
- 案例一: 我们有两个变量: firstName和lastName, 希望它们拼接之后在界面上显示
- 案例二: 当score大于60显示及格、当score小于60显示不及格
- 案例三: 一个变量message某些情况直接显示这段文字、某些情况需要对这段文字进行反转
-
实现思路一: 模板语法 (多次执行不缓存、重复代码、不易维护)
-
实现思路二: methods (显示结果都变成方法调用、没有缓存)
methods: { getFullName() { return this.firstName + "" + this.lastName }, getResult() { return this.score >= 60 ? "及格": "不及格" }, getReverseMessage() { return this.message.split(" ").reverse().join(" ") } } -
实现思路三: (有缓存、使用不用加())
computed: { getFullName() { return this.firstName + "" + this.lastName }, getResult() { return this.score >= 60 ? "及格": "不及格" }, getReverseMessage() { return this.message.split(" ").reverse().join(" ") } } -
计算属性的setter和getter
-
计算属性大多数情况下, 只需要一个getter方法即可, 所以我们会将计算属性直接写成一个函数
-
但是我们想设置计算属性的值呢 -> setter
-
computed: { fullName: { get() { return this.firstName + "" + this.lastNam }, set(value) { const names = value.split(" ") this.firstName = names[0] this.lastname = names[1] } } }
-
认识监听器watch
- 开发中我们在data返回的对象中定义了数据, 这个数据通过插值语法等方式绑定到template中
- 当数据变化时, template会自动进行更新来显示最新的数据
- 但是某些情况下, 我们希望在代码逻辑中监听某个数据的变化, 这个时候就需要用监听器watch来完成了
- Watch里面放函数, 函数名是data返回对象中的属性名
- 函数默认有两个参数: newValue/oldValue
- 深度监听info: {handler(newValue, oldValue){}},deep: true
- 在深度监听的对象中增加 immediate:true , 第一次也会渲染
- 监听的第二种方式, 在create(){}里放入this.$watch(“监听对象”, (newValue,oldValue)) => {},{deep:true}
书籍购物车案例
v-modol
-
表单提交是开发中常见的功能, 也是和用户交互的重要手段
- 比如用户在登录、注册时需要提交账号密码
- 比如用户在检索、创建、更新信息时, 需要提交一些数据
-
这些都要求我们可以在代码逻辑中获取到用户提交的数据, 我们通常会使用v-model指令来完成
-
v-model指令可以在表单input、textarea以及select元素上创建双向数据绑定
-
它会根据控件类型自动选取正确的方法来更新元素
-
尽管有些神奇, 但v-model本质上不过是语法糖, 它负责监听用户的输入事件来更新数据, 并在某种极端场景下进行一些特殊的处理
-
-
v-model原理
-
v-bind绑定value属性的值
-
v-on绑定input事件监听到函数中, 函数会获取最新的赋值到绑定的属性中
<input :value="searchText" @input="searchText = $event.target.value" />
-
-
v-model绑定表单类型
-
textarea
article当前的值是: {{article}}
-
checkbox
-
单选框
- v-model即为布尔值
- 此时input的value属性并不影响v-model的值
同意协议isAgree当前的值是: {{isAgree}}
-
多选框
- 当是多个复选框时, 因为可以选中多个, 所以对应的data中的属性是一个数组
- 当选中某一个时, 就会将input的value添加到数组中
篮球 足球 网球hobbies当前的值是: {{hobbies}}
-
-
radio
男 女gender当前的值是: {{gender}}
-
select
-
单选
- v-model绑定的是一个值
- 当我们选中option中的一个时, 会将它对应的value赋值到fruit
苹果 橘子 香蕉fruit当前的是: {{fruit}}
-
多选
-
v-model绑定的是一个数组
-
当选中多个值时, 就会将选中的option对应的value添加到数组fruit中
苹果 橘子 香蕉fruit当前的是: {{fruit}}
-
-
-
-
v-model修饰符
- v-model.lazy
- 一般情况下, v-model在进行双向绑定时, 绑定的是input事件, 那么会在每次内容输入后就将最新的值和绑定的属性进行同步
- 如果我们在v-model后跟上lazy修饰符, 那么会将绑定的事件切换为change事件, 只有在提交时(回车)才会出发
- v-model.number
- message总是string类型, 这个可以转换为number类型
- v-model.trim
- 自动过滤掉用户输入的首尾空格
- v-model.lazy
认识组件化开发
-
将页面拆分成一个个小的功能块, 每个功能块完成属于自己这部分独立的功能
-
注册全局组件
- 全局组件需要使用我们全局创建的app来注册组件
- 通过component方法传入组件名称、组件对象即可注册一个全局组件
- 之后, 我们可以在App组件的template中直接使用这个全局组件, 把组件当成元素使用
- app.component(“组件名称”, {template: “组件名称”})
-
注册局部组件
-
通过components属性选项来进行注册
-
比如之前的App组件中, 我们有data、computed、methods等选项了, 事实上还可以有一个components选项
-
该components选项对应的是一个对象, 对象中的键值对是 组件名称: 组件对象
{{message}}
-
Vue CLI 安装和使用
- 安装cnpm: sudo npm install -g cnpm --registry=registry.npm.taobao.org
- 全局安装: sudo npm install @vue/cli -g
- 升级: npm update @vue/cli -g
- 创建项目: vue create 项目名称
- 项目依赖: vue install
组件的拆分
- App
- Header
- Main
- Banner
- ProducList
- Footer
组件的通信
-
上面的嵌套逻辑
- App是Header、Main、Footer的父组件
- Main是Banner、ProductList的父组件
-
组件通信的方式
- 父组件传递给子组件: 通过props属性(在子组件中写)
- 子组件传递给父组件: 通过$emit触发事件
-
props
-
props的数组用法
-
props的对象用法
- type类型有哪些: String、Number、Boolean、Array、Object、Date、Function、Symbol
-
prop大小写细节: 浏览器会把所有大写解释为小写, 所以驼峰命名的prop需要使用等价的短横线分隔命名
-
插槽Slot
- 定义
- 插槽的使用过程其实是抽取共性、预留不同
- 我们会将共同的元素, 内容依然在组件内进行封装
- 同时我们会将不同的元素使用slot作为占位, 让外部决定到底显示什么样的元素
- 如何使用slot
- Vue中将元素作为承载分发内容的出口
- 在封装组件中, 使用特殊的元素就可以为封装组件开启一个插槽
- 该插槽插入什么内容取决于父组件如何使用
- 父组件的元素用分隔线命名法, 子元素.vue文件名用对应的驼峰命名法, 在子组件的template中使用即可显示父组件中的对应元素
- 父组件的slot元素可以写html元素和组件元素和其他内容
- 具名插槽
- 父组件:
- 子组件:
- 动态插槽名
- 通过v-slot:[dynamicSlotName]方式绑定一个名称, 在data()中return一个name
- v-slot的缩写: #
- 独占默认插槽的缩写
- 如果我们的插槽是默认插槽default, 那么在使用的时候 v-slot;default="slotProps" 可以简写为 v-slot="slotProps"
- 并且如果我们的插槽只有默认插槽时, 组件的标签可以被当作插槽的模板来使用, 这样, 我们就可以将 v-slot 直接用在组件上
- 但是, 如果我们有默插槽和具名插槽, 那么按照完整的template来编写
- 只要出现多个插槽, 请始终为所有的插槽完整的基于