1、淘宝镜像
1: 解释一下 npm 为什么要配置淘宝镜像
原因:因为node.js 默认使用的是国外的网站 。国内访问有一个跨国内局域网的操作。所以就会有时候很慢。这就跟为什么网站的静态资源有些会使用CDN 加速一样的
淘宝镜像是什么?就是npm 很多的插件淘宝已经下载好了放在公共的网站上 我们需要的时候去淘宝网上下载 和 国外的是一样 这样使用是提升了我们的下载速度。所以淘宝镜像其实是一个国外插件的 国内版本
2:安装命令
npm config set registry https://registry.npm.taobao.org
3:查看是否安装成功
npm info express
4:使用命令
npm install -g cnpm --registry=https://registry.npm.taobao.org
cnpm install <插件名>
3、安装vue的调试工具
1、插件已经下载好,直接拖着往谷歌浏览器的扩展程序里面,记得是开发者模式(教学案例)
1、理解什么是Vue
0:官网https://cn.vuejs.org/guide/introduction.html
https://cdn.jsdelivr.net/npm/vue@2 压缩版
https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js 生产版
1、Vue.js是目前最火的框架,是前端的主流框架之一,和Angular。js和React.js
并称为三大主流框架
2、Vue.js是一套构建用户界面的框架,只关注图层,不仅易于上手,HIA方便与第三方库或既有项目整合(有配套的第三方类库,可以整合起来做大型项目的开发
3、使用vue往html页面中填充数据,非常的方便。框架都是现成的解决方案,按照框架的规范,去便携自己的业务功能
4、主要就是学习vue的指令、组件、路由、vuex
5、vue的特性:
1、数据驱动视图
2、双向数据绑定
2、如何学习Vue
1、能够使用Vue的指令完成页面结构的渲染
2、能够使用Vue的调试工具辅助Vue的开发
3、了解什么是过滤器和侦听器,能够在实际开发中解决问题
4、什么是计算属性以及计算属性的用法
5、axios的基本用法,使用axios发起ajax请求
6、vue-cli,脚手架的安装和使用,生成工程化的Vue项目
7、组件的注册与使用,掌握vue单文件组件的基本用法
8、组件的props自定义属性
9、解决组件样式冲突
10、学习组件的生命周期,掌握组件声明周期的执行顺序和应用场景
11、组件之间的通讯(数据共享),组件之间通讯的三种方式
12、学习ref应用DOM元素和组件实例,能够使用ref获取页面上的DOM、或组件的引用
13、$nxtTick的基本使用,能够知道$nxtTick的应用场景并合理的使用
14、学习动态组件的使用,能够使用keep-alive实现组件的缓存
15、自定义指令
16、学习ESLint的使用,能够了解ESLint的语法规则
17、学习使用(默认插槽、具名插槽、作用域插槽),能够使用插槽提高组件的复用性
18、学习路由的基本配置与使用,能够在项目中安装和配置路由
19、路由重定向
20、嵌套路由、动态路由
21、编程式导航、路由导航守卫,能够使用路由实现单页面程序的开发。使用导航收尾控制路由的访问权限
22、学习Vant,掌握Vant组件库的基本使用,知道如何封装axios请求模块
3、数据驱动视图
1、在vue的页面中,vue会监听数据的变化,从而自动重新渲染页面的结构
页面结构<-vue(监听数据的变化,数据发生改变)<-页面发生变化
好处:当页面数据发生变化时,页面会自动重新渲染,只需要管理好数据
注意:数据驱动视图是单向的数据绑定
总结:数据的变化会驱动视图自动更新,
3-1、数据代理
1、数据代理:通过一个对象代理另一个对象中属性的操作
2、vue中采用数据代理Object.defineProperty中的setter和getter进行数据代理和数据的响应
3-2、VueComponent
1、整个项目只会有一个Vue实例对象vm,其他的都是VueComponent实例对象,
2、VueComponent的实例对象,简称为vc,也称为组件实例对象,Vue的实例对象只有一个,称为vm
3、VueComponent可以通过Vue.extend()方法创建个很多个vc。在项目里面的组件实例对象就是通过这种方式创建的。就是vc
4、vm和vc很多东西都一样,但是vc可以有很多个,vm只能有一个,而且vm可以设置el指定渲染的容器,vc不行。
4、双向数据绑定
1、填写表单的时候,双向绑定可以在不操作DOM的前提下,自动把用户填写的内容同步到数据中。
页面结构<->vue(监听数据的变化,数据发生改变)<->页面发生变化
form表单负责采集数据,ajax负责提交数据
用户不需要手动操作dom元素,来获取表单数据
页面上表单采集的数据发生变化的时候,会被vue自动获取到,并更新到js数据中。
4-MVVM核心原理(数据驱动和双向绑定的原理)
1、MVVM是vue实现数据驱动视图和双向数据绑定的核心原理。MVVM指的 是Model、View、ViewModel,把每个页面都拆分成了这三个部分。
Model表示当前页面渲染时所以来的数据源
View表示当前页面所渲染的DOM解构
ViewModel表示Vue的实例,是MVVM的核心。就是vue
2、ViewModel作为MVVM的核心,是把当前页面的数据源和页面的结构连接在了一起。
view 《--(自动更新,监听DOM变化)--》ViewMOdel《---(监听数据变化,自动同步)--》Model
当数据源发生变化是,会被ViewModel监听到,VM会根据最新的数据源自动更新页面的结构。
当表单的值发生变化时,也会被VM监听到,VM会把变化过的最新的值自动同del数据源中
5、Vue的版本
1.0版本基本被淘汰,
2.x版本是目前企业级项目开发中的主流版本
3.x的与2020年-09发布,现在已经是默认版本了,但是还没有普遍使用
vue的作者:尤雨溪,是中国人开发的前端框架
react和angular都是外国人开发
比较简单
6、Vue的基本使用
1、导入vue.js的script脚本文件
2、在页面中声明一个将要被vue所控制的DOM区域
3、创建一个vue实例
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>
<!-- 1、引入vue的js文件,有vue这个构造函数 -->
<script src="../lib/vue.js"></script>
</head>
<body>
<!-- div控制页面,需要被vue控制 -->
<!-- 数据渲染:插值语法,可以把数据渲染到页面 -->
<div id="app">{{username}}</div>
<script>
// 2、创建一个vue实例对象
const vm = new Vue({
// 3、el属性是固定的写法,表示vm实例要控制页面上的
// 哪一个区域,接收的值是一个选择器
el:'#app',
// data是数据,所有用到的边浪在data里面定义
// 然后渲染到页面上去
// 这里是对象形式
data:{
username:'xiaohong'
}
})
</script>
</body>
</html>
el指向的选择器选择的div就是view视图区域,data指向的对象就是MOdel数据源,new Vue是构造函数,创造了一个vm实例对象,就是viewModel。
7、配置Chrome浏览器的vue-devtools
1、插件已经下载好。可以直接使用
8、Vue的指令和过滤器
1、指令是VUe为开发者提供的模板语法,辅助开发者渲染页面的基本结构
2、指令按照不同的用途,分为六大类
1、内容渲染指令
2、属性绑定指令
3、事件绑定指令
4、双向绑定指令
5、条件渲染指令
6、列表渲染指令
8-1、内容渲染指令
1、内容渲染指令用来辅助开发者渲染DOM元素的文本内容,常用的内容渲染指令有3个
1、v-text:会覆盖元素内部原有的内容,实际开发用的不多
2、{{}}:插值表达式,不会覆盖默认文本,解决v-text的问题,可以在括号里面加点空格,内容占位符,只能用在内容节点,不能用在元素的属性节点。还
3、v-html:其他两种只能渲染纯文本内容,该指令能把包含html标签的字符串渲染为页面的html元素,
2、总结:v-html渲染html标签,v-text和{{}}渲染纯文本,但是v-text会覆盖原本的内容,用的最多的是{{}}
<!-- 1、插值语法 -->
<!-- 纯文本 -->
<div>{{username}}你好</div>
<!-- 2、v-text -->
<div v-text="username"> 你好</div>
<!-- 3、v-html -->
<div v-html="username">你好</div>
<!-- 渲染html标签 -->
<div v-html="ht"></div>
8-2、属性绑定指令(v-bind)
1、插值表达式只能用在内容节点中,不能用在元素节点中
2、v-bind: 给元素的属性动态绑定属性值,可以省略v-bind,保留 :
<input type="text" placeholder="{{info}}">
<!-- 在这里就表示给默认值绑定info -->
<input type="text" v-bind:placeholder="info" >
<img v-bind:src="photo" alt="">
<!-- 简写方式:省略v-bind -->
<img :src="photo" alt="">
3、注意:如果要用v-bind进行字符拼接,记得给字符串加上''
4、v-bind里面是js语句,
使用javascript表达式
1、在vue提供的模板渲染语法中,除了支持简单的数据值之外,还可以可以进行javascript表达式的运算
<!-- 内容绑定指令 -->
<!-- 1、加法 -->
<div>{{ num +6 }}</div>
<!-- 2、三元表达式 -->
<div>{{ 5 > 4 ? 6 : 10}}</div>
<!-- 3、字符串运算 -->
<div>{{str.split("").reverse().join("")}}</div>
<!-- 4、属性绑定指令 -->
<!-- 字符串拼接 -->
<div :id="'list-'+'h'"></div>
8-3、事件绑定指令
1、v-on事件绑定:为DOM元素绑定事件监听,
语法格式 v-on:事件名称="事件函数的名字"
<button v-on:click="add">按钮</button>
2、绑定事件并传参:绑定方法的时候可以加小括号,可以不加,如果要传递参数,就加小括号
<div id="app">
<div>{{ num }}</div>
<button v-on:click="add(5)">按我+5</button>
</div>
<script>
const vm = new Vue({
el: "#app",
data:function(){
return {
num: 5,
}
},
methods: {
add(n){
this.num+=n
}
},
})
</script>
3、v-on的简写形式:@
语法格式 @事件名称="事件函数的名字"
4、其他事件把原生事件的on去掉
kyeup click
5、如果没有传递参数,那么我们默认可以接收到一个事件对象:e
<!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="../lib/vue.js"></script>
</head>
<body>
<div id="app">
<button @click="add">按我输出事件对象</button>
</div>
<script>
const vm = new Vue({
el: "#app",
data:function(){
return {
num: 5,
}
},
methods: {
add(e){
console.log(e);
}
},
})
</script>
</body>
</html>
6、可以通过这个事件对象获取到绑定事件的元素,然后对该元素进行修改
<div id="app">
<button @click="add">按我输出事件对象</button>
</div>
<script>
const vm = new Vue({
el: "#app",
data:function(){
return {
num: 5,
}
},
methods: {
// 如果没有传递参数,那么我们默认可以接收到一个事件对象:e
// 可以通过这个事件对象获取到绑定事件的元素,然后对该元素进行修改
add(e){
e.target.style.backgroundColor="red"
e.target.style.fontSize="50px"
}
},
})
</script>
7、但是这样写太复杂了,所以vue给我们提供了一个内置变量:$event,就是原生的事件对象
通过绑定函数的时候传递进去,函数就会接收到这个事件对象,固定写法
<button @click="add(1,$event)">按我输出事件对象</button>
8、事件修饰符:阻止默认事件的发生
以前:在函数里面写
e.preventDefault()
现在:在绑定事件的后面写 .prevent
1、
<a href="https://www.baidu.com" @click="run">阻止跳转</a><br>
run(e){
e.preventDefault();
console.log("阻止成功");
},
2、
<a href="https://www.baidu.com" @click.prevent="run">事件修饰符阻止跳转</a>
jump(){
console.log("阻止成功");
}
9、因为调用e.preventDefault和e.stopPropagation是常见需求,所以vue提供了事件修饰符的概念,来帮助程序员更方便的对事件的触发进行控制。常见的5个事件修饰符如下:
.prevent:阻止默认行为
.stop:阻止事件冒泡
.once:只触发一次
.self:只有在触发对象是当前元素自身触发时触发事件处理函数
.caputre:以捕获模式触发当前的事件处理函数
10、按键修饰符:在监听键盘事件的时候,我们经常需要判断详细的按键,可以为键盘相关的时间添加按键修饰符,例如:
<!-- 在key表示是”enter的时候,调用 .-->
<input type="text" @keyup.enter="ll($event)" >
<!-- 在key表示是”esc"的时候,调用 .-->
<input type="text" @keyup.esc="gg($event)" >
8-4、双向绑定指令
1、vue提供了v-model双向数据绑定指令,快速获取表单的数据
2、双向绑定之后,vue的数据会随着表单的改变发生改变
<input type="text" v-model="username">
<div>{{username}}</div>
3、v-model指令只能和表单元素进行使用
1、input输入框
2、select
3、textrea
4、为了方便对用户输入的内容进行处理,vue为v-model提供了3个修饰符
.number:将用户的输入值转为数值类型
<input type="text" v-model.number="n">+ <input type="text" v-model="s">={{n+s}}
.trim:自动过滤用户的收尾空白字符
<input type="text" v-model="search" @keyup.enter="ff">
<input type="text" v-model.trim="search" @keyup.enter="ff">
.lazy:在change时而非input时更新,在中间更新的时候不会改变,用的很少
8-5、条件渲染指令
1、条件渲染指令用来控制DOM的显示与隐藏。有两个条件渲染指令:
v-if
v-show
<!-- v-if控制是否显示:满足条件 -->
<span v-if="s==6">6</span>
<span v-if="s==5">5</span>
<br><br>
<!-- v-show控制是否显示 -->
<span v-show="s==6">6</span>
<span v-show="s==5">5</span>
2、v-if 是通过让元素下树,隐藏该元素。动态的添加或移除元素,而v-show是通过style样式的display来隐藏或显示元素,如果要频繁的切换元素的显示形态,用v-show更好,如果有些元素不需要被展示,那么就用v-if。
3、 在实际开发中,不用考虑性能问题,直接使用v-if
4、还有一个v-else-if、v-else指令,v-else-if必须个v-if搭配使用,不然不会被识别
插件
1、vue 3 sinppets:
2、vetur:
8-6、列表渲染指令
1、v-for:列表渲染指令,基于一个数组来循环渲染一个列表结构,v-for需要用到iteminitems形式的特殊语法
items是循环的数组
item是循环数组的每一项元素
<li v-for="item in arr">{{item}}</li>
arr:["xiao","hong","lan","ming"]
2、谁在循环就给谁加v-for。
3、v-for还支持一个可选的第二参数,即当前项的索引,语法格式为(item,index) in items.
<!-- 3、索引。(item,index) in items. -->
<ul>
<li v-for="(item,index) in arr2">
索引{{index}}
{{item.name}}
</li>
</ul>
4、官方建议,如果用到了v-for指令,那么一定要绑定一个 :key 属性,可以把index作为key值。必须是字符串或者数字类型,而且key值不允许重复,不然会报错,最好是把id值作为key值,因为key值要求具有唯一性
<!-- 4、 :key属性 -->
<ul>
<li v-for="(item,index) in arr2" :key="index">
索引{{index}}
{{item.name}}
</li>
</ul>
5、56-62跳过
9、过滤器
9-1、了解过滤器
1、过滤器(Filters):用于文本的格式化,可以用在两个地方,插值表达式和v-bind属性绑定,只能在vue3里面使用
2、过滤器应该被添加在javascript表达式的尾部,由管道符进行调用,管道符就是竖线 |
3、过滤器函数必须被定义在filters这个节点下面,这个节点对象和data平级,过滤器本质是一个函数,自己定义。过滤器中一定要有一个返回值。主要是为了进行文本的格式化,所以过滤器函数的传递的参数都是管道符前面那个值
<span>
{{ msg | capi }}
</span>
<script>
// 过滤器函数必须被定义在filters这个节点下面,
// 这个节点对象和data平级,
filters:{
// 过滤器本质是一个函数,自己定义。过滤器中一定要有一个返回值
capi(val){
// 主要是为了进行文本的格式化
//在进行文本的首字母大写
return val.charAt(0).toUpperCase()+val.slice(1);
}
},
</script>
4、注意点:
1、要定义到filters节点下,本质是一个函数
2、在过滤器函数中,一定要有return,也就是返回值
9-2、全局过滤器和私有过滤器
1、定义在vue中的filters是私有过滤器,只能在当前的vue实例中使用
<body>
<div id="app">
<span>
{{ msg | capi }}
</span>
</div>
<div id="app2">
<span>
//使用不了这个capi过滤器,因为是定义在vm里面的,属于私有过滤器
{{ msg | capi }}
</span>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
msg: "hello world",
arr: []
},
// 过滤器函数必须被定义在filters这个节点下面,
// 这个节点对象和data平级,
filters: {
// 过滤器本质是一个函数,自己定义。过滤器中一定要有一个返回值
capi(val) {
// 主要是为了进行文本的格式化
return val.charAt(0).toUpperCase() + val.slice(1);
}
},
methods: {
add() {
this
}
},
})
const vm2 = new Vue({
el: "#app2",
data: {
msg: "hello world",
arr: []
},
})
</script>
</body>
2、被定义在vm实例里面的过滤器只能在当前所控制的el区域使用,如果希望在多个vue实例之间共享过滤器,则
可以按照下面面的格式定义全局过滤器
Vue.filter()方法接收两个参数,
1):是全局过滤器的名字
2):全局过滤器的处理函数
<body>
<div id="app">
<span>
{{ msg | capi }}
</span>
</div>
<div id="app2">
<span>
{{ msg | capi }}
</span>
</div>
<script>
// 首先,这个全局过滤器应该定义在vm实例前面,
// 然后使用Vue。filter定义全局过滤器
Vue.filter('capi', (val) => {
return val.charAt(0).toUpperCase() + val.slice(1)
})
const vm = new Vue({
el: "#app",
data: {
msg: "hello"
}
})
const vm2 = new Vue({
el: "#app2",
data: {
msg: "hello world",
arr: []
},
})
</script>
</body>
3、如果全局过滤器和私有过滤器名字冲突,按照就近原则,优先使用私有过滤器
4、可以连续的使用多个过滤器
{{ msg | capi | capi2 }}
表示递增使用,后面一个过滤器使用前面一个过滤器使用后的结果
5、因为过滤器是函数,可以接收参数,但要注意,接收参数的时候要从第二个位置开始,因为第一个是接收的管道符的文本
6、vue3是没有过滤器的
10、侦听器
10-1、侦听器了解
1、侦听器:watch,监听数据的变化,针对数据的变化做特定的操作,侦听器本质上也是一个函数,监听谁就去watch里面定义一个和变量名字一样的函数,并做出响应。watch和data、methods是平级关系,表示
监听数据的变化
<body>
<div id="app">
<div>
{{num}}
</div>
<button @click="num++">num++</button>
</div>
<script>
const vm = new Vue({
el: "#app",
data: {
num:5
},
// 监听器,监视数值的变化
watch:{
num(){
console.log("num发生变化");
}
}
})
</script>
</body>
2、侦听器的函数里面可以有两个参数,分别是变量的新值和旧值
watch:{
num(newval,oldval){
console.log("num发生变化");
console.log(oldval);
console.log(newval);
}
}
3、侦听器的格式分为:
1)、方法格式的侦听器
缺点:无法在刚进入页面的时候,自动触发
如果侦听的是一个对象,对象的属性发生变化不会触发监听
2)、对象格式的侦听器
优点:可以通过immediate选项让侦听器自动触发一次
可以通过deep选项深度监听
<script>
watch:{
// 对象格式的侦听器
// 有一个handler的处理函数
num:{
handler(){
console.log("num发生变化");
},
// 默认值是false
// ,控制监听器是否触动触发一次
immediate:true
},
}
</script>
4、最好使用方法格式的,简单一点
10-2、深度监听
1、 对象格式的监听器可以通过deep:true这个属性监听对象的属性的改变,任何一个对象的属性发生改变都会触发这个监听器。而这是方法格式的监听器是做不到的
<body>
<div id="app">
<input type="text" v-model="student.name">
</div>
<script>
const vm = new Vue({
el: "#app",
data: {
student:{
name:"小红",
age:18,
score:99
}
},
watch:{
// 对象格式的监听器可以通过deep:true这个属性
// 监听对象的属性的改变
student:{
handler(){
console.log("student发生变化");
},
deep:true
},
}
})
</script>
</body>
2、方法格式监听对象的子属性的变化,必须包裹一层单引号。
'student.name'(){
console.log("'student.name'发生变化");
}
11、计算属性
11-1、了解计算属性
1、计算属性是指通过一系列的运算后,最终得到一个属性值。这个动态计算出来的属性值可以被模板结构或methods方法使用
2、computed和el,data都是平级,都是属于vm这个实例对象的。是以对象的形式书写的。所有的计算属性都要定义到computed节点下面,计算属性在定义的时候,要定义成”方法格式”
3、使用说明:
1、这个计算属性是计算某个具体的变量,是一个函数方法,我们要把它定义在computed里面。
2、这个函数方法有一个返回值,
3、直接使用这个函数,把他当做一个变量来使用,它的返回值就是计算的那个变量的值
<body>
<div id="app">
{{gaibian }}
</div>
<script>
const vm = new Vue({
el: "#app",
data: {
num: 5
},
// 计算属性
computed: {
gaibian() {
return this.num * 5
}
}
})
</script>
</body>
4、声明的时候是方法格式,使用的时候是变量格式
好处:1)、实现代码的复用,
2)、只要计算属性中的数据源发改变,使用到的计算属性也会改变
模板字符串
模板字符串语法:
es5写法:
需要使用大量的“”(双引号)和 + 来拼接才能得到我们需要的模版
实例:
"He is <b>" + person.name + "</b> and we wish to know his" + person.age + ".That is all"
es6写法:
用`(反引号)标识,用${}将变量括起来
实例:
`He is <b> ${person.name} </b> and we wish to know his ${person.age} .that is all`
就是说,用``反引号将整句话包裹进去,然后把变量用${}包裹
{{`He is ${age}`}}
<br>
<br>
{{ `${name} 已经 ${age} ,她的身高 ${h}` }}
<!-- 属性渲染 -->
<div :style="`background:rgb(${r},${g},${b})`"></div>
12、axios
1、axios是一个专注于数据请求的库,就是简化封装了ajax和promise的一个库,vue和react都会用这个
<body>
<div id="app">
<button @click="fn">按我获取数据</button>
{{res}}
</div>
<script>
const vm = new Vue({
el: "#app",
data: {
res:{}
},
methods: {
async fn() {
const p = await axios.get('http://182.92.193.159:5050/allcmc')
this.res=p.data
}
},
})
</script>
</body>
2、axios请求数据时,可以通过传递的参数获取自己想要的数据,传递参数使用data:{}
const res = await axios.get("http://www.zt-it.com:5000/student", {
params:{}
})
3、axios的方法:axios.get() ,axios.post(),axios.delete(),axios.put()
13、Vue-cli
13-1、单页面应用程序
1、单页面就是一个Web网站里面只有一个唯一的一个html页面,素有的功能与交互都在这个唯一的一个页面内完成。
2、vue-cli是vue.js开发的标准工具,简化了程序员基于webpack创建工程化的vue项目的过程
3、中文官网地址:https://cli.vuejs.org/zh/
4、vue-cli是npm上的一个全局包,可以使用npm install命令安装
5、通过 vue create 项目的名称 就可以创建项目,最后一个表示让你自己手动选择需要的环境,然后进入下一步,*表示已经选择,第一项必须选择,表示vue的版本。按下空格键选择。eslint规定格式很严格,最好别选,bavel选择在独立的配置文件中
13-2、项目文件结构
git: 是一个为git客户端增加git工具,用于存储自己的版本库(或者叫.svn根据自己的配置会有不同名字的版本库)
|- biuld: vue2.0的配置,项目打包时候的配置文件(现如今的vue项目,可使用vue.config.js进行打包配置)
|- node_modules: node的一些基础依赖包,可能还有拓展的安装的别的插件(npm install下载的依赖包,主要是根据package.json获取对应的依赖包)
|- public: 存放一些主要的打包文件,如index.html等等,可以放置一些需要在index.html配置的文件
|- src:项目的主文件夹(vue是SPA单页面应用,可以看做是一个主页面的应用里面的内容组件详情可看vue 代码格式解析)
|- assets: 资源文件,用于存放一些静态文件,如字体、图片、css样式之类的
|- components: vue主要内容的公共组件,可以进行复用
|- router: 设置路由,指定路由对应的组件
|- route: main.js中的router是通过router文件映射,而router下的index.js是项目链接的关键,通过设置路径将views中的vue文件关联起来
|- main.js:项目的主js,全局使用的各种变量、js、插件都在此定义和引入;整个项目先加载src里的main.js,通过里面的app元素生成vue对象,再将router里面的路由加载进去,结果在app的vue中呈现
|- app.vue: 项目的入口文件
|- store:放置vuex需要的状态关联文件,设置公共的state等,是公共数据管理器,关联页面都可随时访问数据,是一个专为vue.js应用开发的状态管理模式,集中式存储管理应用的所有组件的状态
|- test: 测试文件目录
|- .editorconfig: 是用来帮助开发者定义和维护代码风格(行尾结束符、缩进风格等)editorconfig配置文件网
|- .env: 全局默认配置文件,无论什么环境都会加载合并
.env.development:开发环境下的配置文件
.env.development: 开发环境下的配置文件
npm run serve(或者npm run dev 主要看 package.json) 会合并 .env 文件
.env.production: 生产环境下的配置文件
npm run build 会合并 .env 文件
|- .eslintignore: 指定忽略的文件,不需要eslint校验文件; eslint校验对不符合规范代码报错
|- .eslintrc.js: eslintrc的配置文件,vue项目自带的文件,各个eslint配置项的作用;ESlint是一个检查代码的工具
|- .gitignore: 可以避免在提交代码时把我们不想上传的文件提交到git中; LICENSE:开源协议的说明
|- package.json: 记录作者、项目入口、项目描述、项目依赖等相关信息
|- pnpm-lock.yaml: 记录详细的依赖版本
|- postcss.config.js:插件,利用js插件对CSS进行转换
|- prettier.config.js: 配置文件,保持代码风格统一
|- README.md: 项目用的到的所有插件的json格式
|- stylelint.config.js:让CSS样式代码在编辑、保存、提交git的时候按规范进行检查及美化
|- tsconfig.json: 配置文件
13-2-1、项目外部文件
1、.gitignore:不接受git管理的文件或文件夹
2、babel.config.js:babel的控制文件。
3、package.json:配置的各种信息,依赖、各种信息。
build:构建,最后一次编译,编译成html、js
lint:进行语法检查
4、package-lock.json:包版本控制文件。
13-2-2、src
1、assets:存放项目的静态资源文件夹,比如:css样式表、图片资源
2、components:程序员封装的、可复用的组件。
3、main.js是项目的入口文件,整个项目的运行,要先执行main.js
4、app.vue 项目的主页,被main.js渲染到public的index.html文件里面
13-2-3、main.js构成:项目最先运行,渲染App组件
1、导入vue,得到vue构造函数
import Vue from 'vue'
2、导入App.vue这个根组件,要把模板解构渲染到html页面中
这个组件是所有组件的父组件。受vm管理
import App from './App.vue'
3、关闭vue的生产提示
Vue.config.productionTip = false
4、创建Vue的实例对象
new Vue({
//把render函数指定的组件渲染到html文件中
//mounet是挂载,相当于:el:“#app”
render: h => h(App),
}).$mount('#app')
// 引入残缺版的vue,残缺版的vue不能自己渲染页面
// 只有完整版的vue能够渲染,
// vue由两部分组成:核心(生命周期、路由)+模板解析器
// 节省空间,残缺版去掉了模板解析器,通过render函数
// 去渲染页面
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
//render:渲染
// h是一个函数,
// h去渲染元素
render: h => h(App),
}).$mount('#app')
13-2-4、App.vue
1、所有组件的根组件
2、整个项目只有一个vm实例,就在app.vue创建。
3、用来编写待渲染的模板结构,index.html中预留一个el区域,让main.js把app.vue渲染到了index.html预留的区域中
13-2-5、index.html配置
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<!-- 针对IE浏览器的一个特殊配置,让IE浏览器以最高的渲染级别渲染页面-->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- 开启移动端的理想视口 -->
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<!-- 配置页签图标 ,<%= BASE_URL %>:路径的写法:相当于 ./ -->
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<!-- 配置网页的标题。找到package.json的name属性 -->
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<!-- noscript:如果浏览器不支持js,这里面的元素就会被渲染 -->
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<!-- 容器 -->
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
13-2-6、改变入口文件
1、 https://cli.vuejs.org/zh/config/#pages
2、 创建一个vue.config.js文件,然后再去官网的配置参考里面找到pages,选择代码
粘贴到创建的文件里面,去掉多余的
module.exports = {
pages: {
index: {
// page 的入口
entry: 'src/index/peiqi.js',
}
}
}
13-2-7、关掉语法检查
1、 https://cli.vuejs.org/zh/config/#pages
2、 创建一个vue.config.js文件,然后再去官网的配置参考里面找到lintOnSave,把配置拿过 lintOnSave:false
module.exports = {
pages: {
index: {
// page 的入口
entry: 'src/index/peiqi.js',
}
},
lintOnSave:false
}
13-2-8、vue单文件
1、组件化开发:根据封装的思想,把页面上可重用的UI结构封装为组件,方便项目的开发和维 护
2、vue是一个支持组件化开发的前端框架,组件的后缀名是.vue,
3、vue文件的组成部分,组件是对UI结构的复用
1、template:组件的模板结构,
2、script:组件的javascript行为
3、style:组件的样式
4、export defalut:默认导出,有引入就要有导出
5、组件中的data必须定义为函数类型,返回一个对象,因为每个组件都有属于自己的数据,避免数组重复,所以每个组件的数据通过data这个函数得到自己的数据
6、可以安装Vetur可以使用快捷键<得到vue文件的模板
7、组件必须只能由一个根节点。
13-3、组件之间的关系
1、组件在被封装好以后,没有引入关系的时候,是相互独立的,不存在父子关系
2、如果在使用组件的时候,根据彼此的嵌套关系,形成了父子关系、兄弟关系
3、父组件引入子组件的步骤
1:使用import语法导入需要的组件
2、使用compoents节点注册组件 键值一样可以简写
3、以标签的形式使用刚才注册的组件
4、通过components注册是私有子组件
5、使用 <右键可以直接生成vue组件
6、组件分为私有组件和全局祖册组件
13-3-1、使用@代替src的方法
1、下载一个插件 Path Autocomplete
2、选择 齿轮-设置-打开设置
3、复制代码到最前面
//导入文件时是否携带文件的扩展名
"path-autocomplete.extensionOnImport":true,
//配置@的路径提示
"path-autocomplete.pathMappings":{
"@":"${folder}/src"
}
4、然后就可以引入了
import Self from '@/components/Self.vue'
(案例:two)
13-3-2、注册全局组件
1、注册一次,全局都可以使用
2、在vue项目的main.js入口文件中,通过Vue.component()方法,可以注册全局组件
// 导入需要全局注册的组件
import Self from '@/components/Self.vue'
// 参数1:字符串格式,表示组件的”注册名称“
// 参数2:需要背全局注册的那个组件
Vue.component('MySelf',Self)
3、注册完以后就可以通过注册名称直接引入这个组件了
main.js文件
// 引入残缺版的vue,残缺版的vue不能自己渲染页面
// 只有完整版的vue能够渲染,
// vue由两部分组成:核心(生命周期、路由)+模板解析器
// 节省空间,残缺版去掉了模板解析器,通过render函数
// 去渲染页面
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
// 导入需要全局注册的组件
import Self from '@/components/Self.vue'
// 参数1:字符串格式,表示组件的”注册名称“
// 参数2:需要背全局注册的那个组件
Vue.component('MySelf',Self)
new Vue({
render:h=> h(App)
}).$mount('#app')
14、组件之间的通信(分享数据)
14-1、props(父组件给子组件传递数据->自定义属性)
1、props:是组件的自定义属性,在封装通用组件的时候,合理的使用props可以极大地提高组件的复用性(自我总结:就是说每个组件(vue文件)都有这个属性。但如果这些文件的初始值不一样,而且被映射到一个文件上面,就可以使用props)
(被引入的组件是子组件,引入组件的是父组件。在父组件里面把属性传给子组件,子组件使用 props接收)
2、props的语法格式:
props:["自定义属性1","自定义属性2"]
是一个数组,和data等平级关系,里面的属性用字符串包裹
3、子组件使用props接收父组件的步骤:(父组件是App.vue,子组件是father.vue)
1、在引入组件的时候,在父组件里面使用子组件的标签对里传值
<Father :count="count"></Father>
2、在子组件里面接收
props:['count']
3、使用这个属性
注意:子组件的这个属性改变不会影响到父组件的属性发生改变
4、 props可以传递具体的值,也可以传变量,是自定义属性。在传值的时候为当前组件指定初始值。这个自定义属性是封装者自己定义的。可以极大地提高组件的复用性
5、props传递变量的三种方式
1、传递的是字符串
<Son count="9"></Son>
2、传递的是数值
<Son :count="9" ></Son>
3、传递的是变量
<Son :count="count" ></Son>
因为 :代表v-bind,里面是js语句,相当于count=9
6、props的数据,可以直接在模板结构中被使用,并且,子组件不要修改props接收到的值,会报错。
7、vue规定,组件中封装的自定义属性是只读的,程序员不能直接修改props的值,不然会直接报错。
8、可以把props值传给data
num:this.count
9、props的default值,来定义属性的默认值。写成对象的形式,一般是在组件没有传递该属性时候,则默认值生效
props:{
count:{
default:5
}
}
10、props的type值类型,设置属性的类型,传入的值必须是该类型
props:{
count:{
default:5,
type:Number
}
}
11、props的required:必填,要求必须传递该属性的值
props:{
count:{
default:5,
required:true
}
}
12、简答类型复制的是值,复杂类型的是引用地址。
14-2、子组件向父组件传递数据(使用自定义事件)
1、子组件可以通过自定义时间向父组件传递数据。
1、在子组件中自定义一个事件,使用 this.$emit('btn-click', item)的语法,emit指代发射事件,btn-click是我们自定义的事件名,item是子组件中的数据。 注意::vue官方推荐你始终使用 kebab-case格式的事件名。
2、在父组件中使用v-on监听在子组件中我们自定义的数组,并为其在父组件中定义一个接收监听的事件
3、在父组件中接收数据
<button @click="add">点我传送数据给父组件App</button>
methods: {
add(){
this.$emit('num',this.message)
}
},
<Son @num="add"></Son>
methods: {
add(n){
console.log(n);
}
},
14-3、兄弟组件之间的数据共享(EventBus:全局事件总线,可实现任意组件通信)
1、创建一个eventBus.js模块,并向外共享一个Vue的实例对象
2、在数据发送方,调用bus.$emit("事件名称",要发送的数据)方法触发自定义事件
3、在数据接收方,调用bus.$on("事件名称",事件处理函数)方法注册一个自定义事件
1、自定义一个eventBus.js
import Vue from 'vue'
export default new Vue()
2、在数据发送方,引入这个文件。再定义一个事件,然后通过这个事件调用bus.$emit("事件名称",要发送的数据)方法触发自定义事件
<template>
<div>
<!-- 数据发送方 -->
<button @click="send">发送数据</button>
</div>
</template>
<script>
import bus from '@/components/eventBus.js'
export default {
data() {
return {
msg:"好好学习,天天向上"
}
},
methods: {
send(){
bus.$emit("num",this.msg)
}
},
}
</script>
3、在数据接收方,使用create生命周期函数调用bus.$on("事件名称",事件处理函数)方法注册一个自定义事件
<template>
<div>
<div>接收方{{str}}</div>
</div>
</template>
<script>
import bus from '@/components/eventBus.js'
export default {
data() {
return {
str:""
}
},
created() {
bus.$on("num",val=>{
this.str=val
})
},
}
</script>
14-4、vuex(状态管理)
vuex官方解释
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
14-4-1 、vuex的概念
1、概念:专门在vue中实现集中式状态(数据)管理的一个插件 Vue.use()。对vue应用中的多个组件的共享状态进行集中式状态 数据 管理(读/写)。也是一种组件间通信的方式,且适合用于任意组件间的通信
14-4-2、什么时候使用vuex(共享)
1、多个组件依赖于统一状态(多个组件需要用到同一个数据,就可以让vuex来管理这个护具)
2、来自不同组件的行为需要变更同一状态(需要改变这同一个数据)
14-4-3、vuex工作原理图
每一个 Vuex 应用的核心就是 store,里面又包括:
1. State(状态):用于数据的存储(对象类型数据),是store中唯一数据源
2. Actions(行为):类似于mutation,用于提交mutation来改变状态,而不直接变更状态,可以包含任意异步事件
3. Mutations(转变):类似函数,改变state数据的唯一途径,且不能用于处理异步事件。
Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type)和一个回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方
4. Getter(数据加工):如vue中的计算属性一样,基于state数据的二次包装,常用于数据的筛选和多个数据的相关计算
5. Module:类似于命名空间,用于项目中将各个模块的状态分开定义和操作,便于维护
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块。
vuex工作原理说明
1、,actions、mutations,state
2、actions:动作、行为
3、mutations:维修,加工
4、state:状态,把数据交给vuex的state对象进行保管。
5、dispatch:分发,派遣。
14-4-4、vuex的搭建环境
1、安装vuex
npm i vuex@3
2、在main.js里面设置vue.use(Vuex)
import Vuex from 'vuex'
//就可以配置store项
Vue.use(Vuex)
3、在src里面创建一个文件夹store,创建一个index.js
用于创建vuex中最核心的store,
在js文件里面创建三个对象
// 准备actions-用于响应组件中的动作
const actions={}
// 准备mutations-用于操作数据
const mutations={}
// 准备dtate-用于存储数据
const state={}
然后创建一个store对象来管理这几个对象
因为store是通过Vuex的Store创建的。所以我们要引入Vuex
// 引入Vuex创建store
import Vuex from 'vuex'
然后创建store
const store =new Vuex.Store({
actions,
mutations,
state
})
// 向外暴露,因为主要是要的是store,所以暴露的是store
export default store
4、在main.js引入这个store,所有的组件对象能看见这个 store
// 引入store
import store from './store'
//配置
new Vue({
el:"#app",
store,
//render:渲染
// h是一个函数,
// h去渲染元素
render:h=> h(App)
})
5、报错,现这样错误的原因是在创建store实例之前,没有调Vue.use(Vuex),但这个时候会有人说,已经调用了Vue.use(Vuex),还是会出现这样的错误。究其原因是因为Vue脚手架会解析文件中的所有import语句,然后把所有import语句按照编写代码的顺序全都汇总在最上方,之后才会解析文件中的其它代码,这就会使得Vue.use(Vuex)在store实例之后执行。
import引入最高级,会优先执行import的js,所以先创建store实例会报错。
6、解决:在store.js,引入Vue后,在使用Vue.use(Vuex)
import Vue from 'vue'
Vue.use(Vuex)
6、2022年7月,vue3成为了默认版本, 现在npm i vue,安装的就是vue3,vue3成为默认版本,vuex也更新到了4。4只能在vue3中使用,现在使用npm i vuex安装的是4版本
我们项目使用的是2版本,使用vuex4就会报错。所以我们要安装3版本
store.js
// 引入Vuex创建store
import Vuex from 'vuex'
// 准备actions-用于响应组件中的动作
const actions={}
// 准备mutations-用于操作数据
const mutations={}
// 准备dtate-用于存储数据
const state={}
// 创建store
// 因为store是管理
// const store =new Vuex.Store({
// actions,
// mutations,
// state
// })
// 向外暴露,因为主要是要的是store
// export default store
// 简写,创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state
})
main.js
// 引入残缺版的vue,残缺版的vue不能自己渲染页面
// 只有完整版的vue能够渲染,
// vue由两部分组成:核心(生命周期、路由)+模板解析器
// 节省空间,残缺版去掉了模板解析器,通过render函数
// 去渲染页面
import Vue from 'vue'
import App from './App.vue'
// 引入vuex
import Vuex from 'vuex'
// 引入store
import store from './store'
Vue.use(Vuex)
Vue.config.productionTip = false
new Vue({
store,
render:h=> h(App)
}).$mount('#app')
解决报错
store.js
// 引入Vuex创建store
import Vuex from 'vuex'
// 引入vue
import Vue from 'vue'
// 准备actions-用于响应组件中的动作
const actions={}
// 准备mutations-用于操作数据
const mutations={}
// 准备dtate-用于存储数据
const state={}
Vue.use(Vuex)
// 创建store
// 因为store是管理
// const store =new Vuex.Store({
// actions,
// mutations,
// state
// })
// 向外暴露,因为主要是要的是store
// export default store
// 简写,创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state
})
main.js
// 引入残缺版的vue,残缺版的vue不能自己渲染页面
// 只有完整版的vue能够渲染,
// vue由两部分组成:核心(生命周期、路由)+模板解析器
// 节省空间,残缺版去掉了模板解析器,通过render函数
// 去渲染页面
import Vue from 'vue'
import App from './App.vue'
// 引入vuex
import Vuex from 'vuex'
// 引入store
import store from './store'
Vue.config.productionTip = false
new Vue({
el:"#app",
store,
//render:渲染
// h是一个函数,
// h去渲染元素
render:h=> h(App)
})
// .$mount('#app')
14-4-5、vuex工作流程
1、state管理数据,所以把想让vuex管理的数据保存到state中。
2、当我们想改变state保管的数据的状态的时候。就使用action保管的函数方法,使用dispatch方法将执行那个函数方法拍给action执行。
this.$store.dispatch('函数方法',参与运算的数据参数)
this.$store.dispatch('Jia',this.num)
3、action函数里面响应这个方法,所以需要在action里面定义这个函数方法,使用对象格式,也可以简写,这个函数方法可以接收到两个参数,一个是context,这个上下文对象就包括了commit方法,可以
函数方法名(context,n){
函数体
}
4、action的这个函数方法可以接收到两个参数,一个是context,这个上下文对象就包括了commit方法,可以使用这个context对象调用commit方法,由 actions 提交一个 mutation。记住!!!这个函数方法名改为大写,为了区分mutation和action写的函数
函数方法名(context,n){
context.commit(‘函数方法名’,n){
}
5、在mutation里面准备定义这个函数,也有两个参数,a是state,b是传递的参数数据
就可以通过a.数据和数据进行处理
mutation={
大写的函数方法名(a,b){
}
}
6、展示state里面的数据的写法
$store.state.数据名
7、actions决定业务逻辑是否调用mutation的函数,包括发送异步请求
8、如果函数不需要什么业务逻辑,可以直接mutation对接,直接调用commit调用mutation里面的函数
this.$store.commit('大写的函数方法名',参数数据)
9、组件中地区vuex的数据,$stroe.state.sum
10、组件中使用actions的数据:$store.dispatch('action中的方法名',数据)
$store.commit('mutation中的方法名',数据)
(如果没有网络请求或起亚业务逻辑,可以绕过actions,直接commit)
工作流程
https://blog.csdn.net/JHY97/article/details/124045131?ops_request_misc=&request_id=&biz_id=102&utm_term=vuex%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86%E5%9B%BE&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-1-124045131.142^v87^control_2,239^v2^insert_chatgpt&spm=1018.2226.3001.4187
14-4-6、vuex的getters
1、getters其实就是store的计算属性,对state里面的状态进行过滤处理,用法与组件自身的计算属性一模一样。
2、使用,和actions一样定义,然后和计算属性一样在里面定义方法,方法返回一个数值
const getters={
}
然后把getters放到store里面
export default newVVuex.Store({
actions,
mutations,
state,
getters
}
3、当state中的数据需要经过加工后再使用时,可以使用getters加工
14-4-7、vuex的mapState
1、mapState是什么
用于帮助我们映射state中的数据为计算属性
因为我们可以在组件的计算属性的方法里面,直接返回state里面的数据,而
this.$store.state.数据 。如果返回state数据的函数方法太多,太麻 烦。mapState可以帮我们生成这种函数方法
使用:先在需要映射的组件里面引入这个组件
import {mapState} from 'vuex'
在computed里面使用mapState生成函数方法
mapState({方法名:"state里面的数据"})
如果方法过多,我们可以解构的形式
...mapState({方法名:"state里面的数据",方法名2:"state里面的数据2"})
简写,把数据名用字符串括起来放在数组里面
...mapState(['数据名1','数据名2'])
2、mapGetters方法:用于帮助我们映射getters中的数据为计算属性
和mapstate用法一致
3、mapMutations方法:用于帮助我们生成与mutations对话的方法,即:包含 $store.commit(xxx)的函数
和mapstate用法一致的话,会出错。传入的是鼠标事件,因为生成的函数没有参数,而mutation定义的参数里面是有value的,而默认是有一个事件对象,所以这个事件对象会在被作为value值传给mutations的value值
...mapMutations({方法名1:"mutations里面的方法1",方法名2:"mutations里面的方法12"})
解决方法:在调用的时候,把这个数传过去
方法名1(n)
4、mapActions方法:用于帮助我们生成与actions对话的方法,即:包含 $store.dispatch(xxx)函数
和mapMuatations用法一致
14-4-8、vuex模块化
1、因为会有不用的功能,比如订单模块,用户模块,可以把这些模块分成不同的对象,统一配置actions,state,mutations,
const 对象1={
const actions={},
const state={},
const mutations={},
const getters={}
},
const 对象2={
const actions={},
const state={},
const mutations={},
const getters={}
}
2、暴露store的时候,去掉actions,state,mutations,使用modules放置定义的对象,这里的a,b是别名
export default new Vuex.Store({
modules:{
a:配置对象1,
b:配置对象2
}
})
3、简写,这样写的话,可以输出this.$store看一下
export default new Vuex.Store({
modules:{
配置对象1,
配置对象2
}
})
4、计算属性使用的时候,这是将mapstate方法将a,b生成计算属性,将store的state下面的a,b作为计算属性的方法,返回这两个数据,因为它们是两个对象,所以可以使用a.属性名,b.属性名。
...mapState(['a','b'])
5、直接从配置对象里面拿到数据,表示从别名1里面拿去数据,但是只是这样肯定会报错,还需要给配置对象设置一个namespaced:true属性
...mapState(‘别名1’,['a','b'])
const 对象1={
namespaced:true,
const actions={},
const state={},
const mutations={},
const getters={}
},
6、方法也是一样
...mapMutations(‘别名1’,{方法名1:"mutations里面的方法1",方法名2:"mutations里面的方法1"})
就可以调用这个方法,记得传参
7、如果是直接调用commit方法,要找到具体的是哪一个配置对象的方法
this.$store.commit('配置别名/配置方法名',传入的参数)
8、获取配置对象的getters的方法
this.$store.getters['配置别名/配置方法名']
9、如果是直接调用dispatch方法,要找到具体的是哪一个配置对象的方法
this.$store.dispatch('配置别名/配置方法名',传入的参数)
10、模块化语法减少代码耦合,更好维护代码。让各种数据分类更加明确
14-4-9、vuex的详细用法
1、开启命名空间后,组件中读取state的数据
1—自己直接读取
this/$store.state.配置名.数据名
2-借助mapState读取
...mapState('配置别名',['数据名1','数据名2'])
2、开启命名空间后,组件中读取getters的数据
1—自己直接读取
this.$store.getters['配置别名/配置方法名']
2-借助mapGetters读取
...mapGetters('配置别名',['方法名1','方法名2'])
3、开启命名空间后,组件中调用dispatch
1—自己直接dispatch
this.$store.dispatch('配置别名/配置方法名',传入的参数)
2-借助mapActions生成方法,方法调用需要传递参数
...mapActions('配置别名',['方法名1','方法名2'])
或者
...mapActions('配置别名',{组件定义的方法名:'配置对象的方法名'})
4、开启命名空间后,组件中调用commit
1—自己直接commit
this.$store.commit('配置别名/配置方法名',传入的参数)
2-借助mapMutations生成方法,方法调用需要传递参数
...mapMutations('配置别名',['方法名1','方法名2'])
或者
...mapMutations('配置别名',{组件定义的方法名:'配置对象的方法名'})
14-5、消息订阅
个人省略
15、组件之间的样式冲突问题
1、默认情况下,写在.vue组件中的样式会全局生效,因此会很容易造成多个组件之间的样式冲突问题。原因是因为
1、单页面应用程序,多有组件的DOM结构,都是基于唯一的index.html进行呈现
2、每个组件中的样式,都会影响整个index.html中的DOM元素
2、解决样式冲突问题
在style里面加上scoped,vue会自动为该组件的元素生成私有属性
<style lang="less" scoped>
</style>
3、如果想在父组件里面改变子组件的样式,而其他引入了子组件的不会发生改变,那么,不仅要在该父组件定义scoped,还要在改变的样式前面加上一个前缀,这样的话就会变成一个后代选择器。
/deep/ div{
width: 200px;
height: 200px;
background-color: blue;
}
16、生命周期
16-1、简单介绍
官网:每一个vue实例从创建到销毁的过程,就是这个vue实例的生命周期。在这个过程中,他经历了从开始创建、初始化数据、编译模板、挂载Dom、渲染→更新→渲染、卸载等一系列过程。
1、生命周期:是一个vue组件从 创建 ->运行->销毁 的整个阶段,强调的是一个时间段
2、生命周期函数:是vue提供的内置函数,会伴随着组件的生命周期,自动按次序执行
3、生命周期强调的是时间段,生命周期函数强调的是时间点
4、组件创建阶段: beforeCreate(组件还没开始创建之前)、created(内存里面创建好,还没被渲染)、beforeMount(将要渲染的时候)、mounted(渲染好的时候,刚好看到组件的时候)
5、组件运行阶段:beforeupdate(组件更新前)、updated
6、created最重要,因为我们异步请求数据就是在这个周期函数里面
1、创建期间的生命周期函数:
1)beforeCreate:实例刚在内存中被创建出来
此时还未初始化完毕data和methods
2)created:实例已经在内存中创建完毕
此时 data和methods已经创建完毕 但此时还未开始编译模板
3)beforeMount:此时已经完成模板的编译
但是还未挂载到页面中
4)mounted:此时已将编译好的模板挂载到了页面指定的容器中显示
2、运行期间的生命周期函数:
1)beforeUpdate:状态更新之前执行此函数
此时data中的状态值是最新的 但界面上显示的数据还是旧的
因为此时还未开始重新渲染DOM节点
2)updated:实例更新完毕之后调用此函数
此时data中的状态值和界面上显示的数据都已完成了更新 界面已被重新渲染好了
3、销毁期间的生命周期函数:
1)beforeDestroy:实例销毁前调用
在这 实例仍然完全可用
2)destroyed:Vue实例销毁后调用
调用后 Vue实例指示的所有东西都会解除绑定 所有的事件监听器会被移除 所有的子实例 也会被销毁
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ISgI4l6Z-1686141820663)(C:\Users\Direct\Desktop\常用前端框架及工具\拓展学习资料\生命周期函数.png)]
组件创建阶段
<template>
<div id="app">
<h3></h3>
</div>
</template>
<script>
export default {
name: "App",
components: {
},
data() {
return {
count:5
}
},
beforeCreate(){
console.log(this.count);
},
created(){
//异步请求数据使用该函数
console.log(this.count);
console.log(document.querySelector("h3"));
// data和methods已经创建完毕 但此时还未开始编译模板,所以不能操作dom
// document.querySelector("h3").innerText="Hello"
},
beforeMount(){
//还没有渲染
// document.querySelector("h3").innerText="Hello"
},
mounted(){
//编译好已经挂载到页面上,最早操作dom元素
document.querySelector("h3").innerText="Hello"
}
};
</script>
组件运行阶段
<template>
<div id="app">
<h3>生命周期</h3>
<h4>{{ count }}</h4>
<button @click="count++">count++</button>
</div>
</template>
<script>
export default {
name: "App",
components: {
},
data() {
return {
count:5
}
},
beforeUpdate(){
// data中的状态值是最新的 但界面上显示的数据还是旧的
console.log(this.count);
console.log( "h4的值"+document.querySelector("h4").innerHTML);
},
updated() {
//数据和模板结构完成同步
//为了操作大哦最新的dom结构,必须写到upDate声明周期函数
console.log(this.count);
console.log( "h4的值"+document.querySelector("h4").innerHTML);
},
};
</script>
17、ref引用(Vue用来操作DOM元素的)
1、ref是用来辅助开发者在不依赖jquery的情况下,获取DOM元素或组件的引用
2、每个vue的组件实例上,都包含一个$refs对象,里面存储着对应的DOM元素激活组件的引用。默认情况下,组件的$refs指向一个空对象
3、给一个Dom元素定义一个ref属性,然后取一个名字,就可以通过$refs.名字对这个DOM元素进行操作
4、如果想要使用ref引用页面上的组件实例,还可以给组件使用ref。然后通过this.$refs.组件的ref的名字.fn(),就可以运行该组件的方法
<!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="../lib/vue.js"></script>
</head>
<body>
<div id="app">
<span ref="s">使用ref操作dom元素</span>
<button @click="fn">输出this</button>
</div>
<script>
const vm = new Vue({
el:"#app",
methods: {
fn(){
console.log(this.$refs.s);
}
},
})
</script>
</body>
</html>
根组件引用Ref组件过后,通过ref属性使用他的方法
<template>
<div id="app">
<button @click="fn">App:按我输出组件r的方法</button>
<br>
<br>
<Ref ref="r"></Ref>
</div>
</template>
<script>
import Ref from '@/view/Ref.vue'
export default {
name: "App",
components: {
Ref
},
data() {
return {
}
},
methods:{
fn(){
this.$refs.r.fn()
}
}
};
</script>
17-1、this.$nextTick()方法
1、this.$nextTick()方法主要是用在随数据改变而改变的dom应用场景中,
vue中数据和dom渲染由于是异步的,
所以,要让dom结构随数据改变这样的操作都应该放进this.$nextTick()的回调函数中。
2、created()中使用的方法时,dom还没有渲染,如果此时在该钩子函数中进行dom赋值数据(或者其它dom操作)时无异于徒劳,
所以,此时this.$nextTick()就会被大量使用,而与created()对应的是mounted()的钩子函数则是在dom完全渲染后才开始渲染数据,
所以在mounted()中操作dom基本不会存在渲染问题。
3、就是数据发生改变了,但是页面还没有反应过来,就需要使用这个this.$nextTick(),等待数据渲染后应用在dom里面,需要dom重新渲染的时候就需要用到这个方法。把回调推迟到下一个DOM更新周期之后执行
this.$nextTick(()=>{
函数体
})
18、动态组件
1、动态组件指的是动态切换组件的显示和隐藏
2、vue提供了一个内置的<component>组件,专门用来实现动态组件的渲染,作用:组件的占位符,is属性的值:表示要渲染的组件的名字。而且,is属性的值,应该是组件在components节点下的注册名称。也就是必须是引入的组件,注册过后,才能使用。
3、可以把这个<component>看做一个组件的占位符。但是直接使用会报错,未知的元素错误,因为这个元素还没有被定义。
4、在component组件里面使用is属性选择要渲染的组件
<component is="Hello"></component>
<component is="Hi"></component>
5、对于飘红线显示错误的情况,使用v-bind绑定is属性,然后使用反引号括起来组件名字
<component :is="`Hello`"></component>
<component :is="`Hi`"></component>
6、组件的切换,会不断的创建和销毁,字符串的值用单引号括起来,is属性绑定str
<div id="app">
<nav>App根组件
<button @click="str = 'Hello'">切换为Hello组件</button>
<button @click="str = 'Hi'">切换为Hi组件</button>
</nav>
<component :is="str"></component>
</div>
7、使用keep-alive保持让组件隐藏的时候不会被销毁,直接使用<keep-alive></keep-alive>标签将切换的动态组件括起来
<div id="app">
<nav>App根组件
<button @click="str = 'Hello'">切换为Hello组件</button>
<button @click="str = 'Hi'">切换为Hi组件</button>
</nav>
<keep-alive>
<component :is="str"></component>
</keep-alive>
</div>
8、打开vue调试工具,在切换inactive表示被缓存了,没有被销毁
9、如果想在组件被缓存的时候做什么,在组件被激活的时候做什么,有对应的生命周期函数
当组件被缓存的时候,会自动触发组件的deactivated生命周期函数
当组件被激活的时候,会自动触发组件的activated生命周期函数
created() {
console.log("Hello组件已经创建");
},
destroyed() {
console.log("Hello组件已经销毁");
},
deactivated() {
console.log("Hello组件缓存");
},
activated (){
console.log("Hello组件激活");
}
10、组件第一次被创建的时候,会激活created,也会激活activated生命周期,组件被激活的时候只会触发activated,不再触发created。
11、keep-alive的include属性:在component会把component包裹的组件都缓存起来。可以使用include属性用来指定。至于名称相匹配的组件会被缓存,多个组件名之间使用,就是说用它来指定哪些组件需要被缓存,多个组件名之间用,分隔。不被包含在里面的都不会被缓存,记住这个include指定的组件名是在组件里面的定义的name属性
//只有Hello组件可以被缓存
<keep-alive include="Hello">
<component :is="str"></component>
</keep-alive>
12、exclude属性:默认哪些组件不会被缓存,不能和include同时使用
13、在组件提供了name属性后,组件的名称就是name属性的值。如果在“声明组件”的时候,没有为组件指定name名称,则组件的名称默认就是“注册时候的名称”,
14、注册名称以标签的形式使用,把注册好的组件渲染和使用到页面结构中
name名称为了在调试工具里面看到组件名称,以及结合《keep-alive》实现组件缓存功能
Hello子组件
<template>
<div>
Hello组件
</div>
</template>
<script>
export default {
created() {
console.log("Hello组件已经创建");
},
destroyed() {
console.log("Hello组件已经销毁");
},
deactivated() {
console.log("Hello组件缓存");
},
activated (){
console.log("Hello组件激活");
}
}
</script>
<style lang="less" scoped>
div{
width: 100%;
height: 400px;
position: absolute;
top:58px;
background-color: rgb(248, 245, 49);
}
</style>
父组件
<template>
<div id="app">
<nav>App根组件
<button @click="str = 'Hello'">切换为Hello组件</button>
<button @click="str = 'Hi'">切换为Hi组件</button>
</nav>
<component :is="str"></component>
</div>
</template>
<script>
import Hello from './components/Hello.vue'
import Hi from './components/Hi.vue'
export default {
name: "App",
components: {
Hello,
Hi,
},
data() {
return {
str:""
}
}
};
</script>
<style lang="less" scoped>
* {
padding: 0;
margin: 0;
}
nav {
width: 100%;
height: 50px;
background-color: #eee;
}
</style>
Hi子组件
<template>
<div>
Hi组件
</div>
</template>
<script>
export default {
}
</script>
<style lang="less" scoped>
div {
width: 100%;
height: 400px;
background-color: orange;
}
</style>
19、插槽
19-1、插槽的基本用法
1、插槽(slot)是vue为组件的封装这提供的能力,允许开发者在封装组件的时候,把不确定、希望由用户指定的部分定义为插槽。
2、简单来说就是在使用注册过的组件时,如果要往那个标签对里面插入什么元素,但是不会显示出来,就可以往子组件里面写一个插槽,这样这个组件标签对里面写的东西就可以显示出来了
3、用户使用什么,插槽就渲染什么
4、vue官方规定,每一个插槽都应该有一个name名称,如果没有定义会有一个default的默认名称
<slot name="p"></slot>
5、如果插槽定义了name属性,那么我们要使用 v-slot:插槽的名字,去指定是哪一个插槽,而且要注意的是,这个被指定要使用插槽的元素要使用template包裹。
例如:根组件引用了Hello组件,在标签对里面使用了一个p标签,然后,在hello组件里面定义了一个name属性为p的插槽,然后根组件就需要将这个p标签用template包裹起来。然后在template里面定义v-slot:p
Hello组件
<slot name="p"></slot>
App组件
<Hello>
<template v-slot:p>
<p >你好,这是插槽内容</p>
</template>
</Hello>
6、注意:
1、如果要把内容填充到指定名称的插槽中,需要使用v-slot
2、v-slot值只能用在template身上,而且渲染的页面是看不见这个template元素的,只会看见被渲染的元素
3、v-slot:插槽的名字
4、插槽指令v-slot的简写形式是: #,就是一个#号
1、比如,在APP根组件里面引入了Hello组件,然后声明注册后以标签对的形式使用,在里面定义了一个p标签,但不会显示内容,只有在Hello里面定义一个slot插槽,接收到这个p标签,才能显示内容
普通的定义插槽
根组件
<template>
<div id="app">
<nav>App根组件
<Hello>
<p>你好,这是插槽内容</p>
</Hello>
</nav>
</div>
</template>
<script>
import Hello from './components/Hello.vue'
import Hi from './components/Hi.vue'
export default {
name: "App",
components: {
Hello,
Hi,
},
data() {
return {
str:""
}
}
};
</script>
<style lang="less" scoped>
* {
padding: 0;
margin: 0;
}
nav {
width: 100%;
height: 50px;
background-color: #eee;
}
</style>
Hello组件
<template>
<div>
Hello组件
<slot></slot>
</div>
</template>
<script>
export default {
}
</script>
<style lang="less" scoped>
div{
width: 100%;
height: 400px;
position: absolute;
top:58px;
background-color: rgb(248, 245, 49);
}
</style>
有名字的插槽
Hello组件
<template>
<div>
Hello组件
<slot name="p"></slot>
</div>
</template>
<script>
export default {
}
</script>
<style lang="less" scoped>
div{
width: 100%;
height: 400px;
position: absolute;
top:58px;
background-color: rgb(248, 245, 49);
}
</style>
App组件
<template>
<div id="app">
<nav>App根组件
<Hello>
<template v-slot:p>
<p >你好,这是插槽内容</p>
</template>
</Hello>
</nav>
</div>
</template>
<script>
import Hello from './components/Hello.vue'
import Hi from './components/Hi.vue'
export default {
name: "App",
components: {
Hello,
Hi,
},
data() {
return {
str:""
}
}
};
</script>
<style lang="less" scoped>
* {
padding: 0;
margin: 0;
}
nav {
width: 100%;
height: 50px;
background-color: #eee;
}
</style>
19-2、具名插槽和作用域插槽
1、带名字的插槽就是具名插槽,
2、slot插槽可以定义属性,在template里面用v-slot接收
子组件:
<slot name="p" msg="好好学习,天天向上"></slot>
根组件
<Hello>
<template #p="obj">
<p >你好,这是插槽内容</p>
{{ obj }}
</template>
</Hello>
3、在封装组件时,为预留的slot提供属性对象的值,这种用法叫做作用域插槽
4、这种作用域插槽也是具名插槽,用v-slot接收,v-slot可以用#来进行简写。数据对象可以用=来接收。对象的名字用scope定义
<Hello>
<template #p="scope">
<p >你好,这是插槽内容</p>
{{ obj }}
</template>
</Hello>
5、作用域插槽可以使用解构接收数据对象
写法:可以直接使用这个msg
#p="{msg}"
也可以通过scope直接接收所有数据
#p="scope"
{{scope.msg}}
20、自定义指令
1、vue官方提供了v-text、v-for、v-model等常用的指令,还允许开发者自定义指令
2、vue的自定义指令分为两类:
1)、私有自定义指令
2)、全局自定义指令
3、私有自定义指令:
在每个vue组件中,可以在directives(自定义指令节点)节点下声明私有自定义指令
就在组件实例里面定义,和methods、data等平级,这个指令是对象形式,定义的指令 也是对象形式
// 这是自定义指令的节点
directives:{
// 定义一个color的指令,指向一个配置对象
color:{
// 当这个指令绑定到元素的时候,会马上触发bind函数
// bind函数会接收一个el参数,这个el参数就是绑定的dom元素
bind(el){
console.log(el);
}
}
}
4、例如,定义一个color的指令,可以在绑定元素的时候,把元素的背景颜色渲染为绿色
// 这是自定义指令的节点
directives:{
// 定义一个color的指令,指向一个配置对象
color:{
// 当这个指令绑定到元素的时候,会马上触发bind函数
// bind函数会接收一个el参数,这个el参数就是绑定的dom元素
// 可以利用这个el参数对Dom对象做操作,将背景颜色渲染为绿色
bind(el){
el.style.backgroundColor="green"
}
}
}
5、这种定义私有指令的时候,不用使用v-开头来定义,但是使用的时候必须使用v-开头,例如
<div class="box" v-color>
这是一个红色的盒子
</div>
6、自定义指令接收实际参数,会有一个binding对象。binding对象里面有一个value,可以接收到传入的数据,而且,,如果传入的数据时字符串格式的话,要记得给字符串加上单引号。不带引号传入的是一个变量。写法:
<div class="box" v-color="'yellow'">
这是带有参数的自定义指令
</div>
定义私有指令的写法
directives:{
color:{
bind(el,binding){
el.style.backgroundColor=binding.value
}
}
}
7、expreion:是一个表达式,就是这个=后面的表达式。代表用户写的东西。
8、bind函数的缺点,只会在第一次绑定元素的时候执行,而且只执行一次,而如果页面数据更新,是无法改变的,二update函数会在每次Dom更新的时候调用。
updated() {
console.log(this.str);
},
9、凡是使用到了这个指令的元素,都会触发这个update函数
10、update只会在数据更新的时候生效,不会在第一次的时候生效
11、函数简写:
如果bind和update函数中的逻辑完全相同,则对象格式的自定义指令可以写成函数格式:
color(el,binding){
el.style.backgroundColor=binding.value
}
12、私有自定义指令只能在当前定义的组件使用,不能在其他组件使用
13、全局共享的自定义指令需要在main.js 通过“vue.directive()”进行声明
像定义全局过滤器一样,以对象形式写两个函数方法
Vue.directive('c',{
binding(el,binding){
el.style.color=binding.value
},
update(){
el.style.color=binding.value
}
})
14、如果逻辑一样,可以以函数形式写代码
Vue.directive('c',function(el,binding){
el.style.color=binding.value
})
main.js
// 引入残缺版的vue,残缺版的vue不能自己渲染页面
// 只有完整版的vue能够渲染,
// vue由两部分组成:核心(生命周期、路由)+模板解析器
// 节省空间,残缺版去掉了模板解析器,通过render函数
// 去渲染页面
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
Vue.directive('c',function(el,binding){
el.style.color=binding.value
})
new Vue({
el:"#app",
render:h=> h(App)
})
// .$mount('#app')
bind对象和它的缺点
<template>
<div id="app">
<nav>App根组件
<div class="box" v-bgc>
这是一个红色的盒子
</div>
<!-- 直接传入一个颜色值 -->
<div class="box" v-color="'yellow'">
这是带有参数的自定义指令
</div>
<button @click="str='yellowgreen'">改变str的颜色</button>
<div class="box" v-color="str">
这是使用变量的带参数的自定义指令
,看清楚bind函数只执行一次
</div>
<div class="box" v-color="str">
这是使用变量的带参数的自定义指令
,看update的更新
</div>
</nav>
</div>
</template>
<script>
import Hello from './components/Hello.vue'
import Hi from './components/Hi.vue'
export default {
name: "App",
components: {
Hello,
Hi,
},
data() {
return {
str:"pink"
}
},
// 这是自定义指令的节点
directives:{
// 定义一个color的指令,指向一个配置对象
bgc:{
// 当这个指令绑定到元素的时候,会马上触发bind函数
// bind函数会接收一个el参数,这个el参数就是绑定的dom元素
// 可以利用这个el参数对Dom对象做操作
bind(el){
el.style.backgroundColor="green"
}
},
color:{
bind(el,binding){
el.style.backgroundColor=binding.value
}
}
},
//生命周期函数,看见这个str已经改变,但是因为bind而不会更新页面
updated() {
console.log(this.str);
},
};
</script>
<style lang="less" scoped>
* {
padding: 0;
margin: 0;
}
nav {
width: 100%;
height: 50px;
background-color: #eee;
}
.box{
width: 200px;
height: 200px;
background-color: red;
}
</style>
update的优点
<template>
<div id="app">
<nav>App根组件
<button @click="str='yellowgreen'">改变str的颜色</button>
<div class="box" v-color="str">
这是使用变量的带参数的自定义指令
,看update的更新
</div>
</nav>
</div>
</template>
<script>
import Hello from './components/Hello.vue'
import Hi from './components/Hi.vue'
export default {
name: "App",
components: {
Hello,
Hi,
},
data() {
return {
str:"pink"
}
},
// 这是自定义指令的节点
directives:{
// 定义一个color的指令,指向一个配置对象
bgc:{
// 当这个指令绑定到元素的时候,会马上触发bind函数
// bind函数会接收一个el参数,这个el参数就是绑定的dom元素
// 可以利用这个el参数对Dom对象做操作
bind(el){
el.style.backgroundColor="green"
},
},
color:{
bind(el,binding){
el.style.backgroundColor=binding.value
},
update(el,binding){
el.style.backgroundColor=binding.value
}
}
},
updated() {
console.log(this.str);
},
};
</script>
<style lang="less" scoped>
* {
padding: 0;
margin: 0;
}
nav {
width: 100%;
height: 50px;
background-color: #eee;
}
.box{
width: 200px;
height: 200px;
background-color: red;
}
</style>
21、路由
21-1、理解路由
1、路由就是对应关系,route
2、路由器:router
3、路由就是一组key-value的对应关系,多个路由需要经过路由器的管理
4、路由就是为了实现单页面应用。
5、项目由导航区和展示区组成
1、路由指的就是Hash地址与组件之间的关系
2、#号代表锚链接,不会导致页面的刷新,会导致历史记录的变化
3、普通的超链接:<a href="路径"></a> 是跳转到不同的页面
锚点:<a href="位置"></a> 可以在同一个页面中不同的位置间跳转
4、建立锚点目标,只需要给目标元素增加 id 或者 name 即可
锚的名称可以是任何你喜欢的名字
可以使用 id 属性来替代 name 属性,命名锚同样有效,推荐使用 id
5、#往后都叫做hash地址,
锚链接
<!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>#锚链接</title>
<style>
div{
height: 800px;
}
#d1{
background-color:red ;
}
#d2{
background-color:rgb(26, 224, 108) ;
}
#d3{
background-color:rgb(22, 56, 230) ;
}
#d4{
background-color:rgb(231, 65, 143) ;
}
nav{
position: fixed;
top: 0;
left:0;
}
</style>
</head>
<body>
<nav>
<a href="#d1">d1</a>
<a href="#d2">d2</a>
<a href="#d3">d3</a>
<a href="#d4">d4</a>
</nav>
<div id="d1"></div>
<div id="d2"></div>
<div id="d3"></div>
<div id="d4"></div>
</body>
</html>
21-2、路由的工作方式
1、点击页面上的路由连接后,url地址栏上的hash值发生改变,前端路由监听到了hash地址的变化,然后把当前hash地址对应的组件渲染到浏览器中
2、在html页面中对应关系: a#d1 <-> div#d1
3、在vue中路由:path:"#/d1",compoment:#d1
21-3、简单的路由实现
1、window.onhashchange监听页面的hash值变化
2、location.hash.substring(2)截取本地的hash值的字符串2位后的字符串
3、使用动态组件决定显示那个页面,is属性绑定一个动态组件,切换组件
<template>
<div id="app">
<nav>
<h2>App根组件</h2>
<a href="#/Home">首页</a> |
<a href="#/Login">登录</a> |
<a href="#/Regist">注册</a> |
</nav>
<component :is="cname"></component>
</div>
</template>
<script>
import { nanoid } from 'nanoid'
import Hello from './components/Hello.vue'
import Home from './components/Home.vue'
import Login from './components/Login.vue'
import Regist from './components/Regist.vue'
export default {
name: "App",
components: {
Hello,
Home,
Login,
Regist
},
data() {
return {
n: 5,
id: 0,
cname:'Home'
}
},
created() {
this.id = nanoid()
window.οnhashchange=()=>{
// console.log("hash值发生变化",location.hash);
// console.log( location.hash.substring(2));
this.cname=location.hash.substring(2)
}
},
};
</script>
<style lang="less" scoped>
* {
padding: 0;
margin: 0;
}
nav {
width: 100%;
height: 50px;
background-color: #eee;
}
.box {
width: 200px;
height: 200px;
background-color: red;
}
</style>
21-4、vue-router的使用
1、2022年2月7日以后,vue-router的默认版本,为4版本,4版本适用于vue3
3版本的vue-router适用2版本的vue。我们直接安装vue-router就会报错, 出现。
Found:vue @2.。。。
peer vue@“^3.0..
所以一定要安装正确版本
2、cmd安装vue--router的版本,指定3版本
npm i vue-router@3
3、vue-router是一个插件库,需要use。
import VueRouter from 'vue-router'
Vue.use(VueRouter)
4、创建一个router文件夹,用于创建整个应用的路由器,创建一个index.js
文件。
1)、引入路由vue-router
import VueRouter from 'vur-router'
2)、创建路由器
const router=new VueRouter({ })
3)、配置路径routes,path,表示显示的url路径的hash地址,component 表示那个hash地址显示对应的组件
// 创建一个路由器
const router=new VueRouter({
routes: [
{
path:'/hello',
component:Hello
}
]
})
4)、因为配置的component是组件上,所以我们还需要引入组件
import Login from '@/components/Login.vue'
import Regist from '@/components/Regist.vue'
5)、暴露这个路由器
export default router
6)、简写
export default new VueRouter({
routes: [
{
path:'/hello',
component:Hello
}
]
})
7)、在main.js里面引入路由器
import router from '@/router'
8)、使用router-link标签跳转路径,这个标签实际上就是a标签
<router-link to="/login">Login</router-link>
9)、这个时候页面没有展示出来。需要向slot插槽一样,给要显示组件的地方需要用到 router-view占位。组件一个router-view标签,表示router显示的页面展示在这个位置
<router-view></router-view>
10、这些定义了hash路径的组件都叫做路由组件
router的index.html
// 用于创建整个应用的路由器
import VueRouter from 'vue-router'
// 引入组件
import Login from '@/components/Login.vue'
import Regist from '@/components/Regist.vue'
// 创建一个路由器
export default new VueRouter({
routes: [
{
path:'/login',
component:Login
},
{
path:'/regist',
component:Regist
}
]
})
main.js
// 引入残缺版的vue,残缺版的vue不能自己渲染页面
// 只有完整版的vue能够渲染,
// vue由两部分组成:核心(生命周期、路由)+模板解析器
// 节省空间,残缺版去掉了模板解析器,通过render函数
// 去渲染页面
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router'
import router from '@/router'
Vue.use(VueRouter)
Vue.config.productionTip = false
new Vue({
el:"#app",
router:router,
render:h=> h(App)
})
// .$mount('#app')
App引入router
<template>
<div id="app">
<nav>
<h2>App根组件</h2>
</nav>
<div class="box">
<router-link to="/login" >Login</router-link>
</div>
<div class="txt">
<router-link to="/regist" >Regist</router-link>
</div>
<div class="tt">
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
name: "App",
components: {
},
data() {
return {
}
},
};
</script>
<style lang="less" scoped>
* {
padding: 0;
margin: 0;
}
nav {
width: 100%;
height: 50px;
background-color: #eee;
}
.box {
width: 100px;
height: 30px;
text-align: center;
border: 1px solid #a1a0a0;
}
.txt{
width: 100px;
height: 30px;
text-align: center;
border: 1px solid #a1a0a0;
border-top: 0;
}
</style>
21-5、路由注意点
1、配置了hash路径的组件都叫做路由组件
2、这些路由组件一般放在pages文件夹下面。
3、$route:这个组件的路由信息,每个路由组件都有。 route是单个路由,存放 当前路径信息,携带的参数
4、$router:整个应用的路由器。只有一个路由器。 管理整个路由系统,里面保 存所有的路径信息,能够实现路由的跳转
5、通过切换。“隐藏”了的路由组件,默认是被销毁掉的,需要的时候再去挂载
21-6、嵌套路由
1、一级路由,定义在routes对象中,是routes对象的属性,被定义为一级路 由。
2、多级路由是一级路由的孩子。使用routes的children属性定义,children是一个数组,里面可以配置多个对象,对象的写法和以及路由是一样的。是被定义在一级路由为代表的路由组件里面的路由组件。children里面不用添加 /
{
path:'/regist',
component:Regist,
children:[
{
path:'home',
component:Home
}
]
},
3、使用的时候,记得to属性加上完整路由。
<router-link to="/regist/home">Home组件</router-link>
21-7、路由传参
1、路由跳转的时候可以传递参数,而跳转到的那个路由组件可以接收到值传递的这个参数值。
<router-link to="/regist/home/hello?id=01"> {{ item.name }}</router-link>
2、每个路由组件都有一个this.$route对象,有关于这个路由组件的很多多信息。
<li>学生学号{{ $route.query.id}}</li>
3、动态展示传递过去的参数,使用属性绑定v-bind绑定to属性,让字符串变成动态表达式,然后使用模板语法用 ` `括起来,把name属性=对象的id属性,使用${}。让这句话变成模板字符串。这是跳转路由携带query参数的to的字符串写法
<router-link
:to="`/regist/home/hello?id=${item.id}&name=${item.name}`"
>
{{ item.name }}
</router-link>
4、跳转路由并携带query参数to的对象写法,path代表路径,表示你跳转的路由组件的地址,还有query参数,query是一个对象,里面装的就是要携带的参数,这样写的好处是简单明了
<router-link :to="{
path:'/regist/home/hello',
query:{
id:item.id,
name:item.name
}
}">
{{ item.name }}
</router-link>
21-8、命名路由
1、name是什么呢?name 是配置路由时给 path 取的别名,方便使用。但要注意的是 “地址栏显示的路径始终是 path 的值”.可以简化代码,就在routes设置里面添加一个name属性。
{
name:'login',
path:'/login',
component:Login,
},
2、这个name属性可以简化代码。比如说路径跳转的时候我们使用path进行路径跳转。
//在routes设置跳转的 路由的name属性
{
name:'login',
path:'/login',
component:Login,
},
//路由跳转:通过name属性跳转
<router-link :to="{
name:'hello',
query:{
id:item.id,
name:item.name
}
}">
{{ item.name }}
</router-link>
21-9、params参数
字符串写法
1、在跳转前的组件通过to属性使用/传递参数,但是要在路径的path属性里面去声明这是接收参数。通过占位符来声明,跳转到的路由组件接收参数的写法也不一样。
//传递固定格式的数据的写法
<router-link :to="`/regist/home/hello/007/王老五`">
{{ item.name}}
</router-link>
//传递动态数据的写法
<router-link :to="`/regist/home/hello/${item.id}/${item.name}`">
{{ item.name}}
</router-link>
2、在路由组件的路由设置里面通过占位符声明接收的参数。这些数据就会放在params对象里面。
path:'hello/:id/:name',
3、路由组件接收的参数的方式,通过params对象去接收:
<li>学生学号{{ $route.params.id}}</li>
对象写法
必须把path换成name就可以了。不能使用path,
然后query对象的参数换成params对象设置传递的数据参数
4、解决路由组件接收参数写死的情况,路由的props配置:,
在路由里面设置,使用rpops参数去接收,
1)
//第一种写法,值为对象,
{
name:'hello',
path:'hello/:id/:name',
component:Hello,
// props的第一种写法,值为对象,该对象
// 所有key-value都以props形式传递给这个hello组件
props:{a:1,str:"小红"}
}
路由组件通过props接收这个两个变量的值
props:['a','str'],
组件可以直接使用这两个数据,但是,这是写死的数据,不推荐使用
<li>{{ a}}</li>
<li>{{ str }}</li>
2)
//第二种写法,值为布尔值,
// props的第二种写法,值为布尔值,若布尔值为真
// 就会把该路由收到的所有的params参数以props
// 的形式转给该路由组件
{
name:'hello',
path:'hello/:id/:name',
component:Hello,
// props的第二种写法,值为布尔值,若布尔值为真
// 就会把该路由收到的所有的params参数以props
/ 的形式转给该路由组件
props:true
}
引用路由组件的字符串写法
<router-link :to="`/regist/home/hello/${item.id}/${item.name}`">
{{ item.name}}
</router-link>
路由组件通过props接收这个两个变量的值
props:['id','name'],
组件可以直接使用这两个数据,但是,这是写死的数据,不推荐使用
<li>学生学号{{ id}}</li>
<li>学生姓名{{ name}}</li>
对象写法
<!-- 6、路由跳转携带params 参数,引用路由的组件对象写法写法-->
<router-link :to="{
name:'hello',
params:{
id:item.id,
name:item.name
}
}">
{{ item.name}}
</router-link>
4)如果把路径删了,想转成query参数。通过props接收,不能使用props接收的数据,会告诉你属性未定义,只能通过query对象使用数据
引用路由的组件设置跳转路由
<!-- 7、跳转路由由query 接收props传递的数据 -->
<router-link :to="{
name:'hello',
query:{
id:item.id,
name:item.name
}
}"> {{ item.name }}</router-link>
路由组件接收传递的参数的写法
<li>学生学号{{ $route.query.id}}</li>
<li>学生姓名{{ $route.query.name}}</li>
路由设置
{
name:'hello',
// path:'hello/:id/:name',
path:'hello',
component:Hello,
// 如果把路径删了,想转成query参数。通过props接收。
props:true
}
5)props的第三种方法:值为函数。
// props的第三种写法:值为函数,
//值为函数的第一种写法
// props(){
// 这是写死的用法。这个props传递的数据既不在params
//里面,也不在query里面
// return {id:11,name:"小兰"}
/ }
//值为函数的第二种写法:
// 传入route对象,就可以使用query里面的参数传递数据
props($route){
// 这是写死的用法。这个props传递的数据既不在params
// 里面,也不再query里面
return {
id:$route.query.id,
name:$route.query.name}
}
//值为函数的第三种写法:
// 解构query对象,使用里面的数据
props({query}){
return {id:query.id,name:query.name}
}
//值为函数的第四种写法:
// 再解构赋值
props({query:{id,name}}){
return {id,name}
}
5、props的作用:让路由组件更方便的收到参数,既适用于params也适用于 query
21-10、params和query的不同
在Vue路由中,query和params都是用于向路由添加附加信息的方式。query通常用于传递查询字符串,而params则用于传递路由参数。query通过URL中的“?”传递附加信息,而params则在路由路径中传递,例如“/users/:id”。params可以使用$router.push()来更改,而query则使用$router.replace()。查询参数和路由参数在Vue的$route对象中都可以使用,但是路由参数更适用于表示唯一标识符,例如用户ID,而查询参数更适合用于分页或搜索过滤器等用途
21-11、路由跳转的两种导航方式
1、声明式导航,
在浏览器中,点击链接实现导航的方式,叫做声明式导航。
例如:普通网页中点击a链接,vue项目中点击<router-link>都属于声明式导航
2、 编程式导航
在浏览器中,调用API方法实现导航的方式,叫做编程式导航。
例如:普通网页中调用location.href 跳转到新页面的方式,都属于编程式导航
作用:不借助<router-link>实现路由跳转,让路由跳转更加灵活
21-12、router-link的replace属性
1、路径以push模式增加为历史记录,一条条路径重叠,不破坏任何一条路径。最新的页面在最上面
2、replace属性直接替换当前路径页面,不会生成页面记录,写法,直接添加replace属性,在router-link里面。
<router-link
replace
to="/regist/home">Home组件
</router-link>
3、总结:replace属性的作用
1)、作用:控制路由跳转时操作浏览器历史记录的模式
2)、浏览器的历史记录有两种写入方式,分别为push和replace,push是追加历史记录,replace是替换当前记录,路由默认为push
3)、开启replace模式的方法:在router-link里面添加replace属性。
21-13、编程式导航
1、在浏览器中,调用API方法实现导航的方式,叫做编程式导航。
例如:普通网页中调用location.href 跳转到新页面的方式,都属于编程式导航
2、使用路由器:$router的api方法跳转
pushShow(m){
this.$router.push({
name:'hello',
query:{
id:m.id,
name:m.name
}
})
},
replaceShow(m){
this.$router.replace({
name:'hello',
query:{
id:m.id,
name:m.name
}
})
}
3、使用路由器方法的前进后退:
this.$router.back
this.$router.forward
4、编程式导航的作用:不借助router-link实现路由跳转,让路由跳转更灵活
21-14、缓存路由组件
1、通过keep-alive:让不展示的组件保持挂载,不被销毁
2、是在路由router-link里面指定,include属性指定哪个组件被挂载
3、缓存多个组件的写法
:include="['组件1','组件2']"
21-15、路由组件相关的生命周期
1、activated:激活时触发
2、deactivated:失活时触发
3、路由组件所独有的两个钩子,用于捕获路由组件的激活状态
21-16、全局路由守卫
1、路由守卫的作用:对路由进行权限控制,分类:全局守卫、独享守卫、组件内守卫。如果想实现登录注册后才能看见网站首页,就需要添加路由守卫
2、第一步就是在路由组件里面选择不直接暴露router。而是直接定义一个router对象,
const router=new VueRouter({
routes:[
{
}
]
})
//全局前置路由守卫,路由切换之前会调用
//初始化的时候调用
router.BeforeEach((to,from.next)=>{
})
3、to和from是去的路由组件和前一个路由组件,里面是路由组件的相关信息。next()表示放行,如果不放行,是不会执行到下一步,
4、所以前置路由守卫一般是用来判断,是否登录注册过,才可以跳转页面,然后可以路由跳转到其他页面,to.name也可以
if(to.path=='/login' || to.path =='/regist'){
if(这里和数据库的会员数据做比对,一致的话就可以放行){
next()
}
else
{
console.log("不能成功登录")
}
}
5、meta:提供容器配置特殊的数据。称作路由原信息,配置程序员自己想配置的信息,可以用来作为验证路由守卫的信息。也可以用来做网页的title信息。
const router=new VueRouter({
routes:[
{
name:'hello',
path:'/hello',
component:Hello,
meta:{isNext:true}
}
]
})
6、使用meta信息判定权限:
//判断是否需要鉴权
if(to.meta.isNext){
if(这里和数据库的会员数据做比对,一致的话就可以放行){
next()
}
else
{
console.log("不能成功登录")
}
}
7、全局后置路由守卫:初始化之后调用,每次切换之后调用,没有next,不需要放行。
router.afterEach((to,from)=>{
document.title=to.meta.title || '网站'
})
21-17、独享路由守卫
1、某一个路由单独想用的守卫。
2、想设置独享路由守卫,在设置路由里面设置beforeEnter。表示进入这个路由之前。进行规则的对比,只对该路由组件做测试。
routes:[
{
name:'hello',
path:'/hello',
component:Hello,
meta:{isNext:true},
beforeEnter((to,from,next)=>{
})
}
]
3、独享守卫只有前置没有后置,可以喝全局后置守卫搭配使用。
21-18、组件内路由守卫
1、beforeRouteEnter,路由组件使用的函数,通过路由规则,进入该组件时被调用。
beforeRouteEnter(to,from.next){
}
2、beforeRouteleave,路由组件使用的函数,通过路由规则,离开该组件时被调用。
beforeRouteleave(to,from.next){
}
21-19、history模式与hash模式
1、hash值最大的特点:hash值不会因为http请求作为路径数据发给服务器,是程序员自己设置的路径
2、可以通过在路由器里面设置mode属性,选择路由是history模式还是hash模式,默认是hash模式
const router=new VueRouter({
mode:'history',
routes:[
]
})
3、开启history模式后不会再有hash值。需要新开页签
4、hash兼容性好,history兼容性较差。
5、npm的中间件:connect-history-api-fallback专门解决history模式404的问题。
6、总结;
hash模式:
1、地址中带着#号,不美观
2、如果以后将地址通过第三方手机app分享,如果app校验严格,则地址会被标记不合法
3、兼容性较好
history模式:
1、地址干净、美观
2、兼容性和hash模式相比略差
3、应用部署上线时需要后端人员支持,解决刷新页面服务器404问题
21-20、路由重定向
暂时省略
21-21、路由懒加载
暂时省略
22、minxin:混入
22-1-1、什么是混入
1、mixins(混入),官方的描述是一种分发 Vue 组件中可复用功能的非常灵活的方式 mixins 是一个 js 对象,它可以包含我们组件中 script 项中的任意功能选项,如:data、components、methods、created、computed 等等。我们只要将公用的功能以对象的方式传入 mixins 选项中,当组件使用 mixins 对象时所有 mixins 对象的选项都将被混入该组件本身的选项中来,这样就可以提高代码的重用性,并易于后期的代码维护
22-1-2、怎么使用mixin
1、当我们存在多个组件中的数据或者功能很相近时,我们就可以利用 mixins 将公共部分提取出来,通过 mixins 封装函数,组件调用他们是不会改变函数作用域外部的。
2、一样的方法我们把它提取出来放在一个公共的地方
22-1-3、如何创建mixin
1、在 src 目录下创建一个 mixins 文件夹,在文件夹下新建一个myMixins,js 文件。 因为 mixins 是一个 js 对象,所以应该以对象的形式 来定义 myMixins,在对象中可以和vue 组件一样来定义 data、components、methods、created、computed 等属性, 并通过 export 导出该对象。export表示分别暴露,如果需要在组件里面使用该混合,需要在该组件引入,因为是分别暴露,所以,需要以对象的形式暴露:
import {mixin} from '../mixin'
然后,所以我们使用mixins配置项去接收,因为有多个的mixin,所以数组形式接收,只有一个混合也这样写
mixins:[mixin]
2、组件有的东西以组件为主,组件没有的以混合为主
3、生命周期mountend都会实现
4、功能:就是可以把多个组件共用的配置提取成一个混入对象
22-2、案例
export const mixin={
methods:{
fn(){
this.n++
}
}
}
<template>
<div>
{{ n }}
<button @click="fn">按我+1</button>
</div>
</template>
<script>
import {mixin} from '../mixin'
export default {
data(){
return{
n:2
}
},
mixins:[mixin]
}
</script>
22-3、定义全局混合
1、在main.js里面引入混合,然后使用Vue.mixin()就可以使用该混合里面的方法了
import {mix} from './mixin'
Vue.mixin(mix)
23、过渡与动画
1、过渡与动画的作用:在插入或移除DOM元素的时候,在核实的时候给元素添加样式类名
2、有进入的样式和离开的样式
3、进入
v-enter:进入的起点
v-enter-active:进入过程中
v-enter-to:进入的终点
4、离开
v-leave:离开的起点
v-leave-active:离开过程中
v-leve-to:离开的终点
5、进入的终点就是离开的起点
6、使用transtion包裹想要过渡的元素,
23-1、动画
23-2-1、Vue动画的理解
1、设置来回切换的效果,vue用transtion包裹有动画效果的元素,设置进入的时候的的类名:v-enter-active,设置离开的时候的类名:v-leave-active。
2、这个transtion还可以起名字,
<transition name="tr">
<nav v-show="flag">动画效果</nav>
</transition>
3、如果给transtion起了名字,那么,v-enter-active就改成 transtion的名字-enter-active
4、设置一开始就是动画效果,就给transtion设置一个appear属性,设置属性值为true,但是要通过v-bind进行绑定。不然的话是一个布尔值
<transition name="tr" :appear="true">
<nav v-show="flag">动画效果</nav>
</transition>
5、transtion在vue解析的时候没有被解析,是给vue 设置动画的,动态给元素添加样式的动画效果
<template>
<div>
<button @click="flag=!flag">显示/隐藏</button>
<transition>
<nav v-show="flag">动画效果</nav>
</transition>
</div>
</template>
<script>
export default {
data(){
return {
flag:1
}
}
}
</script>
<style lang="less" scoped>
nav{
width: 1000px;
height: 100px;
background-color: aquamarine;
}
.v-enter-active{
animation: trans 1s linear reverse;
}
.v-leave-active{
animation: trans 1s linear ;
}
@keyframes trans {
from{
transform: translateX(0%);
}
to{
transform: translateX(-100%);
}
}
</style>
23-2、过渡
1、vue提供了transtion的封装插件,在下列情形中,可以给任何元素和组件添加enter/leave过渡
1、v-if
2、v-show
3、动态组件
4、组件根节点
过渡的类名
1、v-enter:进入的起点,在外边的盒子以左边坐标为开始,向右从-100%的位置开始
2、v-enter-to:进入的终点,在里边的盒子以左边的坐标未开始,向左从0%的位置转
3、v-leave:离开的起点,0%的位置开始转移
4、v-leave-to:离开的终点,转移到-100%的位置
5、给元素设置transtion。同样位置的一样的类名设置可以放在一起
<template>
<div>
<button @click="flag=!flag">显示/隐藏</button>
<transition >
<nav v-show="flag">动画效果</nav>
</transition>
</div>
</template>
<script>
export default {
data(){
return {
flag:1
}
}
}
</script>
<style lang="less" scoped>
nav{
width: 1000px;
height: 100px;
transition: 2s linear;
background-color: aquamarine;
}
.v-enter{
transform: translateX(-100%);
}
.v-enter-to{
transform: translateX(0%);
}
.v-leave{
transform: translateX(0%);
}
.v-leave-to{
transform: translateX(-100%);
}
</style>
22-2-1、多个元素过渡
1、 can only be used on a single element. Use <transition-group> for lists.
transtion只能有一个元素,多个元素可以使用transtio-group
2、transtion-group的元素必须有唯一的key值
<transition-group name="tr" appear>
<nav v-if="flag" key="one">1</nav>
<nav v-if="flag" key="two">2</nav>
</transition-group>
22-3、动画库(使用第三方库写动画样式)
1、搜素npm.js官网,https://www.npmjs.com/
2、在官网里面搜索animate.css,点击第一个
https://www.npmjs.com/package/animate.css
3、选择animate.style
https://animate.style/
4、根据animate上面的步骤进行使用:
1、安装,停止该项目,安装animate
2、引入样式库
import 'animate.css'
3、复制粘贴类名,放在name属性上
animate__animated animate__bounce
4、给这个transtion指定进入和离开的类名,复制类名 字符串里面是自己喜欢的动画效果
进入的类名:enter-active-class=””
离开的类名:leave-active-class=””
<transition-group
name="animate__animated animate__bounce"
appear
enter-active-class="animate__wobble"
leave-active-class="animate__zoomOutDown"
>
<nav v-if="flag" key="one">1</nav>
<nav v-if="flag" key="two">2</nav>
</transition-group>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1nGHkSMl-1686141820666)(C:\Users\Direct\Desktop\常用前端框架及工具\拓展学习资料\7-animate使用.PNG)]
23、Vue原理
23-1、MVVM
1、Vue坐着参考mvvm模型,m(model)代表模型,v(view)代表视图,模板,vm,视图模型,vue实例对象
23-2、数据代理
1、是否被枚举指的是是否可以被遍历出来
2、数据代理:通过一个对象代理对另一个对象中属性的操作
3、重点:Object.defineProperty,
24、配置代理
1、跨域,也就是违背了同源策略:主机名、协议名、端口号必须一致
2、解决跨域的方法
1.cors,后端人员添加特殊的响应头,
2、jsonp,通过script标签,前端后端一起设置,只能设置get方法
3、代理服务器,服务器和服务器之间传递数据不用ajax请求,使用的是http协议,而代理服务器的端口号和客户端的端口号这些是一致的,满足同源策略
服务器之间不受同源策略的影响
3、代理服务器的几种方式:
1、nginx
2、借助vue-cli
4、vue脚手架设置代理服务器的方式,在vue.config.js里面设置
1、打开vuejs的官网,选择vue2文档,点击配置参考,选择devServer。procy,
2、按照参考文档设置
3、lintOnSave:false //关闭语法检查
//举例
module.exports = {
devServer: {
//这里是告诉代理服务器等会在哪个服务器请求数据,在这里就开启了一个
//代理服务器,所以设置的是请求数据的服务器端口
proxy: 'http://localhost:4000'
}
}
4、在axios请求数据的时候改变端口号,只改变自己的端口号,不改变请求路径。然后重启项目,比如服务器端口号是4000,但我们设置了代理服务器,axios请求的路径本来是4000,但我们改成本机端口号80880
axios.get('http://localhost:4000')
改:axios.get('http://localhost:8080')
5、两个小问题:
1、只能配置一个代理服务器
2、没办法控制走不走代理,因为如果文件的public有路径文件,会优先获取public里面的。
6、解决以上两个问题的方法,看官网
第二种方法
module.exports = {
devServer: {
proxy: {
//第一个代理
///api叫做请求前缀,如果请求前缀是api就走代理服务器
'/api': {
//target是服务器的路径
target: '<url>',
//用于支持websocket:
ws: true,
//true表示隐瞒自己的端口号,
//用于控制请求头中的host值
changeOrigin: true
},
//第二个代理
'/foo': {
target: '<other_url>'
}
}
}
}
注意:在这里因为设置了请求前缀,我们的axios也要作出相应改变,在端口号的后面添加请求前缀,其他的不会改变
axios.get('http://localhost:8080/api')
但是因为axios请求的路径会完整的带给服务器去请求数据,所以我们要去设置一个配置。
//重写路径,它是一个对象格式,里面是key、value形式,表示所有以api开头的路径将被替换为空字符串
pathRewrite:{'/api':''}
7、第二种方法的优点:可以配置多个代理,且可以灵活的控制请求是否走代理
缺点:配置稍微繁琐,请求资源时必须添加前缀
25、axios
25-1、项目中使用
1、在vue里面使用axios需要先安装axios,
npm i axios -S
2、在组件中引入
import axios from 'axios'
3、调用方法
axios.get()
25-2、axios拦截器
暂时省略
26、nanoid
1、使用nanoid可以给数据生成id,
2、
先引入
import {nanoid} from 'nanoid'
后使用,直接使用
this.id=nanoid()
27、Vue UI组件库
27-1、移动端组件库
1、Vant
2、Cube UI
3、Mint UI
27-2、PC端常用UI组件库
1、element UI
2、IView UI