内容不全,发现看官方文档效果更好。
介绍 — Vue.js
API — Vue.js
二、Vue指令
2.1 内容渲染指令 v-text,v-html
内容渲染指令用来辅助开发者渲染DOM元素的文本内容,常用的内容渲染指令有如下2个:
- v-text(类似innerText)
使用语法:<p v-text="uname">hello</p>,意思是将uname值渲染到p标签中
类似innerText,使用该语法,会覆盖p标签原有内容
- v-html(类似innerHTML)
使用语法:<p v-html="intro">hello</p>,意思是将intro值渲染到p标签中
类似innerHTML,使用该语法,会覆盖p标签原有内容,能够将HTML标签的样式呈现出来
2.2 条件渲染指令 v-show,v-if,v-else,v-else-if
条件判断指令,用来辅助开发者按需控制DOM的显示与隐藏。条件渲染指令有如下两个,分别是:
- v-show
作用:控制元素显示隐藏
语法:v-show=“表达式” 表达式值为true显示,false隐藏
原理:切换display:none控制显示隐藏
场景:频繁切换显示隐藏的场景
- v-if
作用:控制元素显示隐藏
语法:v-if=“表达式” 表达式值为true显示,false隐藏
原理:基于条件判断,是否创建或移除元素节点
场景:要么显示,要么隐藏,不频繁切换的场景
2.3 事件绑定指令 v-on (@)
为DOM注册事件,语法如下:
- <button v-on:事件名=“内联语句”>按钮
- <button v-on:事件名=“处理函数”>按钮
- <button v-on:事件名=“处理函数(实参)”>按钮
- v-on 简写为 @
- v-on:click 可以缩写为 @click,其中@代表v-on:
2.4 属性绑定指令 v-bind (:)
- 作用:动态设置html的标签属性,比如:src、url、title
- 语法:v-bind:属性名=“表达式”
- v-bind 缩写为 :
- v-bind:href 可以缩写为 :href
2.5 v-bind对样式控制的增强
2.5.1 操作class
为了方便开发者进行样式控制,Vue扩展了v-bind的语法,可以针对class类名和style行内样式进行控制。
语法
-
普通形式:
<div> :class = "对象/数组">这是一个div</div>
- 对象语法:
<div class="box" :class="{ 类名1: 布尔值, 类名2: 布尔值 }"></div>
当class动态绑定的是对象时,键就是类名,值就是布尔值,如果值是true,就有这个类,否则没有这个类
适用场景:一个类名来回切换
- 数组语法:
<div class="box" :class="[ 类名1, 类名2, 类名3 ]"></div>
当class动态绑定的是数组时,数组中所有的类都会添加到盒子上,本质就是一个class列表
使用场景:批量添加或删除类
2.5.2 切换高亮
li a.active {
background-color: #e01222;
color: #fff;
}
<body>
<div id="app">
<ul>
<li v-for="(item,index) in list" :key="item.id" @click="activeIndex=index">
<a :class="{active:index==activeIndex?true:false}" href="#">{{item.name}}</a>
</li>
</ul>
</div>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
activeIndex: 0,
list: [
{ id: 1, name: '京东秒杀' },
{ id: 2, name: '每日特价' },
{ id: 3, name: '品类秒杀' }
]
}
})
</script>
</body>
2.5.3 操作style
<div class="box" :style="{ CSS属性名1: CSS属性值, CSS属性名2: CSS属性值 }"></div>
2.6 列表渲染指令
Vue提供了v-for列表渲染指令,用来辅助开发者基于一个数组来循环渲染一个列表结构。
v-for指令需要使用(item , index) in arr
形式的特殊语法,其中:
- item是数组中的每一项
- index是每一项的索引,不需要可以省略
- arr是被遍历的数组
2.6.1 v-for中的key
语法:key=“唯一值”
作用:给列表项添加唯一的标识。便于Vue进行列表项的正确排序复用
为什么加key:Vue的默认行为会尝试原地修改元素(就地复用)
注意:
- key的值只能是字符串或数字类型
- key的值必须具有唯一性
- 推荐使用id作为key(唯一),不推荐使用index作为key(会变化,不对应)
2.9 双向绑定指令 v-model
所谓双向绑定就是:
- 数据改变后,呈现的页面结果会更新
- 页面结果更新后,数据也会随之改变
语法:v-model=“变量”
作用:给表单元素(input、radio、select)使用,双向绑定数据,可以快速获取或设置表单元素内容
2.10 v-model在其它表单元素的使用
常见的表单元素都可以用v-model绑定关联,快速获取或设置表单元素的值
它会根据控件类型自动选取正确的方法来更新元素
输入框 input:text ——> value
文本域 textarea ——> value
复选框 input:checkbox ——> checked
单选框 input:radio ——> checked
下拉菜单 select ——> value
<div id="app">
<h3>小黑学习网</h3>
姓名:
<input type="text" v-model="username">
<br><br>
是否单身:
<input type="checkbox" v-model="isSingle">
<br><br>
<!--
前置理解:
1. name: 给单选框加上 name 属性 可以分组 → 同一组互相会互斥
2. value: 给单选框加上 value 属性,用于提交给后台的数据
结合 Vue 使用 → v-model
-->
性别:
<input v-model="gender" type="radio" name="gender" value="1">男
<input v-model="gender" type="radio" name="gender" value="2">女
<br><br>
<!--
前置理解:
1. option 需要设置 value 值,提交给后台
2. select 的 value 值,关联了选中的 option 的 value 值
结合 Vue 使用 → v-model
-->
所在城市:
<select v-model="city">
<option value="101">北京</option>
<option value="102">上海</option>
<option value="103">成都</option>
<option value="104">南京</option>
</select>
<br><br>
自我描述:
<textarea v-model="desc"></textarea>
<button>立即注册</button>
</div>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
username: '',
isSingle: false,
gender: 1,
city: '102',
desc: "暂无"
}
})
</script>
2.11 指令修饰符
什么是指令修饰符?
所谓指令修饰符就是通过“.”指明一些指令后缀,不同的后缀封装了不同的处理操作 ->简化代码
按键修饰符
- @keyup.enter:当点击enter键的时候才触发
v-model修饰符
- v-model.trim:去除首位空格
- v-model.number:转数字
事件修饰符
- @事件名.stop:阻止冒泡
- @事件名.prevent:阻止默认行为
- @事件名.stop.prevent:可以连用,即阻止事件冒泡也阻止默认行为
三、computed与methods属性
3.1基础语法
computed概念
基于现有的数据,计算出来的新属性。依赖的数据变化,自动重新计算。
3.2 computed计算属性 VS methods方法
computed计算属性
作用:封装了一段对于数据的处理,求得一个结果
methods计算属性
作用:给Vue实例提供一个方法,调用以处理业务逻辑
总结
- computed有缓存特性,methods没有缓存
- 当一个结果依赖其他多个值时,推荐使用计算属性
- 当处理业务逻辑时,推荐使用methods方法,比如事件的处理函数
3.3 计算属性的完整写法
计算属性默认的简写,只能读取访问,不能“修改”,如果要修改,需要写计算属性的完整写法。
四、watch侦听器(监听器)
4.1 基础语法
作用:
监视数据变化,执行一些业务逻辑或异步操作
语法:
- watch同样声明在跟data同级的配置项中
- 简单写法:简单类型数据直接监视
- 完整写法:添加额外配置项
data: {
words: '苹果',
obj: {
words: '苹果'
}
},
watch: {
// 该方法会在数据变化时,触发执行
数据属性名 (newValue, oldValue) {
一些业务逻辑 或 异步操作。
},
'对象.属性名' (newValue, oldValue) {
一些业务逻辑 或 异步操作。
}
}
4.3 完整写法
语法
完整写法,添加额外的配置项
- deep:true 对复杂类型进行深度监听
- immediate:true 初始化立即执行一次
<template>
<div>
<!-- 条件选择框 -->
<div class="query">
<span>翻译成的语言:</span>
<select v-model="obj.lang">
<option value="italy">意大利</option>
<option value="english">英语</option>
<option value="german">德语</option>
</select>
</div>
<!-- 翻译框 -->
<div class="box">
<div class="input-wrap">
<span><i>⌨️</i>文档翻译</span>
</div>
<div class="input-wrap">
<textarea v-model="obj.words"></textarea>
</div>
<div class="Qinput-wrap">
<textarea v-model="words"></textarea>
</div>
<div class="output-wrap">
<div class="transbox">{{result}}</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
words:'',
obj: {
words: '',
lang: 'english',
},
result: '',//翻译结果
timer: null//延时器i
}
},
watch: {
// //该方法在数据变化时调用执行
// words(newValue, oldValue) {
// console.log("", newValue, oldValue)
// clearTimeout(this.timer)
// this.timer = setTimeout(async () => {
// var num = newValue.length + 101;
// this.result = Math.floor(Math.random() * num);
// }, 300)
// },
// 'obj.words'(newValue) {
// //防抖:延迟执行
// clearTimeout(this.timer)
// this.timer = setTimeout(async () => {
// var num = newValue.length + 101;
// this.result = Math.floor(Math.random() * num);
// }, 300)
// },
words: {
handler(newValue, oldValue) {
console.log("words handler", newValue, oldValue)
clearTimeout(this.timer)
this.timer = setTimeout(async () => {
var num = newValue.length + 101;
this.result = Math.floor(Math.random() * num);
}, 300)
},
immediate: true,
},
obj: {
deep: true,
immediate: true,
handler(newValue, oldValue) {
console.log("1:", newValue, oldValue)
clearTimeout(this.timer)
this.timer = setTimeout(async () => {
var num = newValue.words.length + 101;
this.result = Math.floor(Math.random() * num);
}, 300)
}
},
},
}
</script>
九、组件
9.1 组件的三大组成部分
9.1.1 scoped解决样式冲突
默认情况写在组件中的样式会全局生效,因此很容易造成多个组件之间的样式冲突问题。
- 全局样式:默认组件中的样式会作用到全局,任何一个组件中都会受到此样式的影响。
- 局部样式:可以给组件加上scoped属性,可以让样式只作用于当前组件。
<style scoped></style>
9.1.2 data必须是一个函数
一个组件的data选项必须是一个函数。目的是为了:保证每个组件实例,维护独立的一份数据对象。
每次创建新的组件实例,都会执行一次data函数,得到一个新对象。
<script>
export default {
data: function () {
return {
count: 100,
}
},
}
</script>
9.2组件通信
9.2.1父子通信
什么是组件通信
组件通信,就是指组件与组件之间的数据传递
- 组件的数据是独立的,无法直接访问其他组件的数据。
- 想使用其他组件的数据,就需要组件通信
组件关系分类
- 父子关系
- 非父子关系
通信解决方案
父子关系:props 和 $emit
非父子关系:provide & inject 和 eventbus
通用解决方案:Vuex
父子通信流程
- 父组件通过props将数据传递给子组件
- 子组件利用$emit通知父组件修改更新
父向子传值步骤
- 给子组件以添加属性的方式传值
- 子组件内部通过props接收
- 模板中直接使用props接收的值
子向父传值步骤
- $emit触发事件,给父组件发送消息通知
- 父组件监听$emit触发的事件
- 提供处理函数,在函数的形参中获取传过来的参数
9.2.2 props
9.2.2.1 什么是props
props是组件上注册的一些自定义属性
可以向子组件传递数据
特点:
- 可以传递任意数量的prop
- 可以传递任意类型的prop
9.2.2.2 props校验
作用:为组件的prop指定验证要求,不符合要求,控制台就会有错误提示,帮助开发者快速发现错误
语法:
- 类型校验
- 非空校验
- 默认值
- 自定义校验
9.2.2.3 props校验完整写法
props: {
校验的属性名: {
type: 类型, // Number String Boolean ...
required: true, // 是否必填
default: 默认值, // 默认值
validator (value) {
// 自定义校验逻辑
return 是否通过校验
}
}
},
9.2.2.4 props和data、单向数据流
共同点:都可以给组件提供数据
区别:
- data的数据是自己的,可以随便改
- prop的数据是外部的,不能直接改,要遵循单向数据流
单向数据流:父级props的数据更新,会向下流动,影响子组件。这个数据流动是单向的
9.2.3非父子通信 略
9.2.3.1 event bus事件总线 略
9.2.3.2 provide&inject 略
十、进阶语法
10.1 v-model原理
作用
提供数据的双向绑定
- 数据变,视图跟着变 :value
- 视图变,数据跟着变 @input
语法
v-model本质上是一个语法糖。例如应用在输入框上,就是value属性和input事件的合写
<template>
<div id="app" >
<input v-model="msg" type="text">
<input :value="msg" @input="msg = $event.target.value" type="text">
<input v-bind:value="msg" v-on:input="msg = $event.target.value" type="text">
</div>
</template>
注意
$event用于在模板中,获取事件的形参
:model是Element属性
:model相当于v-bind:model的缩写—— 对model属性 绑定对应的data
10.2 v-model简化代码
目标
父组件通过v-model简化代码,实现子组件和父组件数据双向绑定
如何简化
v-model其实就是:value和@input事件的简写
- 子组件:props通过value接收数据,事件触发input
- 父组件:v-model直接绑定数据
父组件
<BaseSelect v-model="selectId"></BaseSelect>
子组件
<select :value="value" @change="handleChange">...</select>
props: {
value: String
},
methods: {
handleChange (e) {
this.$emit('input', e.target.value)
}
}
10.3 表单类组件封装
需求目标
实现子组件和父组件数据的双向绑定
App.vue
<template>
<div class="app">
<BaseSelect :cityId="selectId" @changeId="selectId = $event"></BaseSelect>
</div>
</template>
<script>
import BaseSelect from './components/BaseSelect.vue'
export default {
data() {
return {
selectId: '102',
}
},
components: {
BaseSelect,
}
}
</script>
<style></style>
BaseSelect.vue
<template>
<div>
<select :value="cityId" @change="handleChange">
<option value="101">北京</option>
<option value="102">上海</option>
<option value="103">武汉</option>
<option value="104">广州</option>
<option value="105">深圳</option>
</select>
</div>
</template>
<script>
export default {
props: {
cityId: String
},
methods: {
handleChange(e) {
this.$emit('changeId', e.target.value)
}
}
}
</script>
<style></style>
10.4 .sync修饰符
作用
可以实现子组件与父组件数据的双向绑定,简化代码
简单理解:子组件可以修改父组件传过来的props值
场景
封装弹框类的基础组件,visible属性true显示false隐藏
本质
.sync修饰符就是 :属性名 和 @update:属性名 合写
语法
父组件
//.sync写法
<BaseDialog :visible.sync="isShow" />
--------------------------------------
//完整写法
<BaseDialog :visible="isShow" @update:visible="isShow = $event" />
子组件
props: {
visible: Boolean
},
this.$emit('update:visible', false)
10.5 ref 和 $refs
作用
利用 ref 和 $refs 可以用于获取dom元素或组件实例
特点
查找范围在当前组件内(更精确稳定)
10.5.1 获取dom语法
-
给要获取的盒子添加ref属性
<div ref="mychart" class="base-chart-box">子组件</div>
-
获取时通过$refs获取
const myChart = echarts.init(this.$refs.mychart)
注意
之前只用document.querySelect(‘.base-chart-box’)获取的是整个页面中的盒子
10.5.2 获取组件语法
- 目标组件添加ref属性
<BaseForm ref="baseForm"></BaseForm>
- 恰当时机,通过this.$refs.xxx,获取目标组件,就可以调用组件对象里面的方法
this.$refs.baseForm.组件方法()
10.6 异步更新、&nextTick
需求
编辑标题,编辑框自动聚焦
- 点击编辑,显示编辑框 2 .让编辑框立刻获取焦点
问题
“显示之后”,立刻获取焦点是不能成功的 原因:Vue是异步更新DOM(提升性能)
解决方案
$nextTick : 等DOM更新后,才会触发执行此方法里的函数体
this.$nextTick(() => {
this.$refs.inp.focus()
})
十一、自定义指令 略
十二、插槽
12.1 默认插槽
作用
让组件内部的一些结构支持自定义
语法
使用slot
子
<template>
<div>
<slot></slot>
</div>
</template>
父
<template>
<div>
<AppSon>slot中显示内容</AppSon>
</div>
</template>
显示效果
12.3 具名插槽
作用
多个slot使用name属性区分名字
语法
v-slot简写
v-slot写起来太长,vue给我们提供了一个简单写法 #
在vue2.6.0之前使用slot="插槽名"
定义。
子
<template>
<div>
<slot name="head">默认数据</slot>
<slot name="content"></slot>
<slot name="footer"></slot>
</div>
</template>
父
<template>
<div>
<AppSon >
<template v-slot:head>slot head中显示内容</template>
<template v-slot:content>slot content中显示内容</template>
<template v-slot:footer>slot footer中显示内容</template>
</AppSon>
--------------------------
<AppSon >
<template #head>slot head中显示内容</template>
<template #content>slot content中显示内容</template>
<template #footer>slot footer中显示内容</template>
</AppSon>
--------------------------
<AppSon >
<template #head></template>
<template #content>slot content中显示内容</template>
<template #footer>slot footer中显示内容</template>
</AppSon>
</div>
</template>
显示效果