Vue
# Vue基础知识
# 基本语法
# el挂载点:
1.Vue实例的作用范围是什么呢?
ans:Vue会管理el选项命中的元素及其内部的后代元素
2.是否可以使用其他的选择器?
ans:可以使用其他的选择器,但是建议使用ID选择器
3.是否可以设置其他的dom元素?
ans:可以使用其他的双标签,不能使用HTML和BODY
# v-text
1.作用:设置标签的内容
2.默认写法会替换全部内容,使用差值表达式{{}}可以替换指定内容
# v-show
1.作用:根据真假切换元素的显示状态
2.原理是修改元素的display,实现显示隐藏
3.指令后面的内容,最终都会解析为布尔值
4.值为true元素显示,值为false元素隐藏
5.数据改变之后,对应元素的显示状态会同步更新
# v-if
1.作用:根据表达式的真假切换元素的显示状态
2.本质:通过操作dom元素来切换显示状态
3.值为true元素元素存在dom树中,值为false,从dom树中移除
4.频繁的切换v-show,反之使用v-if,前者的切换消耗小
# v-for
1.作用:根据数据生成列表结构
2.数组经常和for结合使用
3.语法是(item,index) in 数据
4.item和index可以结合其他指令一起使用
5.数组的更新会同步到页面上,是响应式的。
# detailes
事件修饰符
@click.prevent
==> 阻止事件默认行为@click.stop
==> 阻止冒泡@click.trim
==> 不保留行前行后空格
# 过滤器相关(Vue3已经废弃)
作用
- 筛选加工
使用方式
<h1>\{\{ msg | filterA \}\}</h1>
双括号插值内。<h1 v-bind:id=" meg | filterA">\{\{ msg \}\}</h1>
v-bind绑定的值的地方.(msg为需要filter处理的值,filterA为过滤器。)
过滤器的例子
点击查看例子
<div id="app">
<p>电脑价格:{{price | addPriceIcon}}</p>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
price:200
},
filters:{
//处理函数
addPriceIcon(value){
console.log(value)//200
return '¥' + value
}
}
})
</script>
点击查看例子
<div id="app">
//输入框
<input type="text" v-model="content" @change="changeEvent">
//显示层,后边加一个过滤器处理函数,把英文首字母变为大写
<h3>{{viewContent | changeCapitalLetter}}</h3>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
viewContent:"",
content:""
},
methods:{
changeEvent(){
this.viewContent = this.content;
}
},
filters:{
changeCapitalLetter(value){//value是输入框的内容,也是要显示的内容
if(value){
let str = value.toString();
//获取英文,以空格分组把字符串转为数组,遍历每一项,第一项转为大写字母
let newArr = str.split(" ").map(ele=>{
return ele.charAt(0).toUpperCase() + ele.slice(1)
});
return newArr.join(" ") //数组转字符串 以空格输出。。。
}
}
}
})
</script>
过滤器的注意点
- 要定义到filters节点下,本质是一个函数
- 在过滤函数中,一定要有return值
- 在过滤器的形参中,就可以获取到“管道符”前面待处理的那个值
- 如果全局过滤器和私有过滤器名字一致,此时按照“就近原则”,调用的是“私有过滤器”
# 路由
路由的概念和原理
- 什么是路由
路由(英文:router)就是对应关系。
- SPA 与前端路由
SPA 指的是一个 web 网站只有唯一的一个 HTML 页面,所有组件的展示与切换都在这唯一的一个页面内完成。
此时,不同组件之间的切换需要通过前端路由来实现。
结论:在 SPA 项目中,不同功能之间的切换,要依赖于前端路由来完成!
- 什么是前端路由
通俗易懂的概念:Hash 地址与组件之间的对应关系。
- 前端路由的工作方式
① 用户点击了页面上的路由链接
② 导致了 URL 地址栏中的 Hash 值发生了变化
③ 前端路由监听了到 Hash 地址的变化
④ 前端路由把当前 Hash 地址对应的组件渲染都浏览器中
结论:前端路由,指的是 Hash 地址与组件之间的对应关系!
路由的简易实现
location.hash
拿到锚链接的值- 绑定
onhashchange
事件「使用箭头函数确保this的指向」 - 然后一个swich case实现就好了。
路由的小规则
- redirect:重定向跳转
- children:子路由规则---“不要加'/'”
默认子路由:如果children数组中,某个路由规则的Path值为空字符串,则为默认子路由
动态路由
- 动态路由是指把Hash地址中可变的部分定义为参数项,从而提高规则的复用性
# axios
axios的挂载
// (main.js)把axios挂载为$http的一个属性
Vue.prototype.$http = axios
// 今后,在每个vue组件中要发起请求,直接调用 this.$http.xxx
// 但是,把axios挂载到Vue原型上,有一个缺点:“不利于API接口的复用”
# 动态组件
<component is=""></component>
- component本质上是一个占位符
- is的值是要渲染的组件的名称
- 如果想要缓存这个组件,可以使用
<keep-alive></keep-alive>
,keep-alive有include 和 excluede 两种属性,不可以同时使用 - keep-alive的生命周期有两个,第一个是deactivated,第二个是activated。
- 如果在”声明组件“的时候没有name属性,则属性的名称默认为注册时的名称(一般用在标签里)。
# 插槽
- slot,插槽是为Vue的封装者提供的,作用是吧内容填充到指定名称的插槽中
- 在使用有具体名称的插槽时,需要在外层套一个
<template>
,在template中填入插槽的名字,v-slot
的简写是#
。 - 作用域插槽:封装时为既留的slot提供属性对应的值,例如
<template #content="scope">
<slot>
</slot>
</template>
- 一般自定义的属性都在scope作用域里,可以这样访问到。
- 作用域插槽可以解构赋值。
# Promise
- 回调地狱
多层回调函数的相互嵌套,就形成了回调地狱。
- 基本概念
- Promise是一个构造函数「可以new一个实例出来」
new出来的Promise实例对象,代表一个异步操作。
const p = new Promise()
- Promise.prototype上包含一个
.then()
方法
每一次
new Promise()
构造函数得到的实例对象都可以通过原型链的方式访问到.then()
方法,例如p.then()
.then()
方法用来预先指定成功和失败的回调函数
p.then(成功的回调函数,失败的回调函数)
p.then(result=>{},error=>{})
成功的回调函数必选,失败的回调函数必选
- Promise细化学习
.then()
方法的特性
如果上一个
.then()
方法返回了一个新的Promise实例对象,则可以通过下一个.then()
继续进行处理。通过.then()
方法的链式调用,就解决了回调地狱的问题。
- 基于Promise按顺序读取文件的内容
点击查看例子
import thenFs from 'then-fs'
thenFs.readFile('./files/1.txt/','utf8')
.then((r1) => {
console.log(r1)
return thenFs.readFile('./files/2.txt/','utf8')
})
.then((r2) => {
console.log(r2)
return thenFs.readFile('./files/3.txt/','utf8')
})
.then((r3) => {
console.log(r3)
})
.catch
捕获错误
在Promise的链式操作中发生了错误,可以使用Promise.prototype.catch 方法进行捕获和处理
点击查看例子
import thenFs from 'then-fs'
thenFs.readFile('./files/1.txt/','utf8')
.then((r1) => {
console.log(r1)
return thenFs.readFile('./files/2.txt/','utf8')
})
.then((r2) => {
console.log(r2)
return thenFs.readFile('./files/3.txt/','utf8')
})
.then((r3) => {
console.log(r3)
})
.catch(err => {
console.log(err.message)
})
如果不希望前面的错误导致后续的
.then
无法正常执行,则可以将.catch
的调用提前
点击查看例子
import thenFs from 'then-fs'
thenFs.readFile('./files/11.txt/','utf8')
.catch(err => {
console.log(err.message)
})
.then((r1) => {
console.log(r1)
return thenFs.readFile('./files/2.txt/','utf8')
})
.then((r2) => {
console.log(r2)
return thenFs.readFile('./files/3.txt/','utf8')
})
.then((r3) => {
console.log(r3)
})
- Promise.all()方法
Promise.all()方法会发起并行的Promise异步操作,等所有的异步操作全部结束后才会执行下一步的
.then
操作(等待机制)。
点击查看例子
import thenFs from 'then-fs'
const promiseArr = [
thenFs.readFile('./files/1.txt/','utf8'),
thenFs.readFile('./files/2.txt/','utf8'),
thenFs.readFile('./files/3.txt/','utf8'),
]
// 实例顺序就是结果顺序
Promise.all(promiseArr).then(([r1,r2,r3]) => {
console.log(r1,r2,r3)
})
.catch(err => {
console.log(err.message)
})
- Promise.race()方法
Promise.all()方法会发起并行的Promise异步操作,只要任何一个异步操作完成,就执行下一步的
.then
操作(赛跑机制)。
点击查看例子
import thenFs from 'then-fs'
const promiseArr = [
thenFs.readFile('./files/1.txt/','utf8'),
thenFs.readFile('./files/2.txt/','utf8'),
thenFs.readFile('./files/3.txt/','utf8'),
]
Promise.race(promiseArr).then(result) => {
console.log(result)
})
.catch(err => {
console.log(err.message)
})
- 基于Promise封装读文件的方法
import fs from 'fs'
function getFile(fpath){
return new Promise(function(resolve,reject){
fs.readFile(fpath,'utf8',(err,dataStr) => {
if(err) return reject(err)
resolve(dataStr)
})
})
}
# async/await
async/await是ES8引入的新语法,用来简化Promise异步操作。在async/await出现之前,开发者只能通过链式.then()的方式处理Promise异步操作。
import thenFs from 'then-fs'
async function getAllFile() {
const f1 = await thenFs.readFile('./files/1.txt','utf8');
console.log(f1);
const f2 = await thenFs.readFile('./files/2.txt','utf8');
console.log(f2);
const f3 = await thenFs.readFile('./files/3.txt','utf8');
console.log(f3);
}
- 注意事项
- 有await必须要async修饰。
- 在async方法中,第一个await之前的代码会同步执行,await之后的代码会异步执行。
console.log('A')
async function getAllFile(){
console.log('B')
const r1 = await thenFs.readFile('./file/1.txt','utf8');
console.log(r1);
const r2 = await thenFs.readFile('./file/2.txt','utf8');
console.log(r2);
const r3 = await thenFs.readFile('./file/3.txt','utf8');
console.log(r3);
console.log('D');
}
getAllFile()
console.log('C')
// 执行顺序
// A
// B
// C
// r1 r2 r3
// D
# EventLoop
- JavaScript 是一门单线程执行的编程语言。也就是说,同一时间只能做一件事。
单线程的问题:如果前一个任务非常耗时,则后续任务就不得不一直等待,从而导致程序假死的问题。
- 同步任务和异步任务
同步任务
- 又叫非耗时任务,指的是在主线程上排队执行的那些任务。
- 只有前一个任务执行完毕,才能执行后一个任务
异步任务
又叫耗时任务,异步任务由JavaScript委托给宿主环境进行执行。 当异步任务执行完成后,会通知JavaScript主线程执行异步任务的回调函数。
# 组件通信
一般有如下情况:
- 父子组件通信
- 兄弟组件通信
- 跨多层级组件通信
- 任意组件
# 生命周期
在
beforeCreate
钩子函数调用的时候,是获取不到props
或者data
中的数据的,因为这些数据的初始化都在initState
中。
然后会执行
created
钩子函数,在这一步的时候已经可以访问到之前不能访问到的数据,但是这时候组件还没被挂载,所以是看不到的。
接下来会先执行
beforeMount
钩子函数,开始创建VDOM
,最后执行mounted
钩子,并将VDOM
渲染为真实DOM
并且渲染数据。组件中如果有子组件的话,会递归挂载子组件,只有当所有子组件全部挂载完毕,才会执行根组件的挂载钩子。
接下来是数据更新时会调用的钩子函数
beforeUpdate
和updated
,这两个钩子函数没什么好说的,就是分别在数据更新前和更新后会调用。
另外还有
keep-alive
独有的生命周期,分别为activated
和deactivated
。用keep-alive
包裹的组件在切换时不会进行销毁,而是缓存到内存中并执行deactivated
钩子函数,命中缓存渲染后会执行actived
钩子函数。
最后就是销毁组件的钩子函数
beforeDestroy
和destroyed
。前者适合移除事件、定时器等等,否则可能会引起内存泄露的问题。然后进行一系列的销毁操作,如果有子组件的话,也会递归销毁子组件,所有子组件都销毁完毕后才会执行根组件的destroyed
钩子函数。