目录
vue是什么
MVVM
vue优势
vue的开发目的
vue核心
vue初体验
{{}}是什么?
vue渲染数据
数据驱动分类
指令
v-model
双向绑定的原理
v-show
v-on
v-for
v-bind(使用中最容易忽略的指令)
v-if全家桶
v-if
v-if与v-show的区别
v-else
v-else-if
v-html
v-once
v-text
屏幕闪烁
watch监听
计算属性---computed
为什么要使用计算属性?
什么是计算属性
计算属性与方法的区别
计算属性与watch的区别
vue的事件对象
事件修饰符
案件修饰符
事件修饰符
过滤器与全局局部
自定义过滤器---filter
全局过滤器---filter
局部过滤器---filters
扩展--内置过滤器
钩子函数
生命周期的钩子函数
实例创建
模板渲染
数据更新
实例销毁
第一次之行的之后执行那几个钩子
生命周期的钩子函数有什么作用?
DOM渲染在那个钩子中完成
vue-cil脚手架
.vue文件
拿到空项目怎么办?
属性的使用
为什么data是一个函数而不是对象
一下的和之前本地模式没有任何区别
组件
组建分类
全局组件--component
局部组件--components
组件的本质 就是自定义标签
scoped
父子组件
组件传值
正向传值--props
props验证
逆向传值
实现:
兄弟同胞传值--中央事件总线
什么是中央事件总线
实现
跨组件传值--vuex
vuex使用
modules模块
mutations状态修改
payload 载荷
actions用来触发异步操作
数据请求的闭环操作
slot--槽口/插槽
引子
槽口是什么?
基础用法
具名槽口
路由---router
传统的项目怎么切换跳转页面?
路由基本概念
路由基本创建
vue-cl自动创建
带有路由的空项目怎么办?
手动创建
路由导航
标签方式----声明式导航
声明式导航选中样式类
js的方式--- 编程式导航
404页面
重定向----redirect
路由出口
多级路由/嵌套路由
路由传参/动态路由匹配
方式
params方式
编程式
query方式
query和params的区别
$router与$route区别
路由模式
路由守卫/路有钩子/导航守卫
全局守卫
路由独享守卫
组件内守卫
扩展--懒加载
扩展--路由的更多属性
meta 路由记录/路由元信息
在组件内获取路由全部规则
前后端数据交互
axios
基本使用
数据请求封装与拦截器
数据请求封装
axios拦截器
mockjs 模拟数据
使用
mixins 混入
分类
自定义指令----directives
ref
扩展--$set以及原理
$set的使用
动态组件
keep-alive
引子
出现的原因
keep-alive
属性
钩子函数keep-alive
nextTick
数据修改异步说明
什么是nextTick
扩展---浏览器自动开启与修改端口
vue.js是现今最为主流的MVVM框架
作者:尤雨溪
mvvm是一个编程思想 在这个思想下 更加只专注于业务的开发(功能)让我们的开发变得更加简单
M ----model 模型=数据
V ----view 视图=界面(就是你写出来让用户看见的内容)
VM ---viewmodel 视图模型 用来传递模型和关联视图的
数据驱动与组件化
获取vue的依赖库 npm install --save vue
编写如下内容:
Document
{{text}}
{{表达式---通过计算返回结果的公式}}
{{}}大括号赋值法/双大括号语法/模板语法
Document
双大括号赋值法
{{text}}
{{num+2}}
{{bool?"你好":"你坏"}}
vue.js的核心就是数据驱动 vue的数据驱动就是视图的内容是根据模型data数据的改变而改变的
1.声明式渲染 我们只需要告诉程序 想干什么 那么程序就会自动来完成
2.命令式渲染 我们需要一步步的指挥着程序 程序才会按照我们的指令去执行
在vue中 使用v-开头html特殊属性
指令的作用:在vue中 扩展标签的功能
指令的语法:写在html开标签中并且 v-指令="指令值"
作用:用于在表单元素上完成数据的双向绑定
语法:v-model='值'
双向绑定
用户可以看见的界面中也就是v层视图层 改变了数据 那么data中内容也就会改变 视图变模型变
模型改变了 反之也会让视图发生改变 模型变视图变
Document
v-model
{{inputval}}
双向绑定是通过数据劫持与发布者订阅者模式来实现的
数据劫持:数据(变量)劫持(拦截)就是当数据改变的时候我要拦截到这次改变 通知模型或者视图发生改变
通过一个Object,defindProperty()来监听数据当数据改变时它就会触发 从而通知另外一方(有一个get的方法和set的方法 分别是读取与修改)
也有一个bug
bug详见$set
发布者订阅者模式:就是一个一对多的关系,当发布者改变了起所有的订阅者页随之发生改变
作用:控制dom元素的显示和隐藏
语法:v-show=“返回值为布尔值的表达式” true 显示 false 隐藏
Document
v-show
{{bool?"显示了":"隐藏了"}}
我是测试显示和隐藏的元素
作用:就是给dom元素绑定事件的
语法:v-on:事件不加on=“函数” 简写就是@
Document
v-on
作用:遍历展示数据
语法:v-for=“(参数1==遍历出来的值,参数2--遍历出来的下标)in 你要便利的数据”
Document
v-for
- {{v}}
{{i}}
{{v.name}}
{{v.age}}
作用:就是给html的属性插入变量
语法:v-bind:html标签的属性=“变量”简写:
Document
从用户的角度看上去和v-show没有区别
作用:判断当前dom是否加载
语法:v-if=“表达式结果为布尔值” true加载当前dom false溢出当前dom
Document
v-if
我是测试v-if
我是测试v-show
v-if在显示和隐藏的时候是对当前dom进行溢出的添加 v-if在页面初始化的时候性能损耗低 在切换的时候性能损耗高
v-show是对于css的样式设置显示和隐藏 v-show在页面初始化的时候性能损耗高 在切换的时候性能损耗低
必须配合v-if来使用 当v-if条件不成立的时候执行
Document
v-else
请登录
欢迎您尊敬的vip
多重if选择 当其中一项成立的时候
Document
v-else-if
吃饭
睡觉
上厕所
在吃饭
在睡觉
啥都没干
作用:把字符串标签 解析到页面中
语法:v-html=“值”
Document
v-html
{{newhtml}}
作用:一次性插值 数据插入到页面中之后就不会改变了
Document
v-once
{{text}}
{{text}}
{{text}}
{{text}}
{{text}}
{{text}}
作用:就是在页面中插入纯文本{{}}可以理解为和他是一样的功能
Document
v-text
{{num}}
当用户网络或者设备性能比较低的时候 可能在vue渲染初期会在页面显示没有编译好很多{{}} 当网络通顺或者设备渲染完成之后 突然间显示最终效果 就叫屏幕闪烁
解决:
1.v-text
2.v-cloak指令 该指令是会在vue渲染完毕后自动消失
v-text
{{num}}
他是vue实例中的一个属性 写在与了data methods等属性同级的位置
用来绑定监听data中创建的数据 当ssata的数据改变的时候,watch就会通知 做出相关的反应
watch在初始化的时候是不会执行的 只有当数据改变的时候才会运行
如果就是想让watch在初始化执行怎么办?
watch: {
value: {
handler: function (o, n) {
this.text="123456"
},
immediate: true
}
},
语法:
watch:{
newval 就是改变之后的值 oldval就是之前的旧数据
你要监听的数据(newval,oldval){
}
}
Document
watch的使用
{{text}}
视图层是用来展示数据的 但是我们却在视图层中处理数据 不太合适
Document
{{text}}
大写展示:{{text.toUpperCase()}}
大写加截取展示:{{text.toUpperCase().substr(1,4)}}
计算属性 他是一个vue实例下的属性 这个属性是一个带有甲酸(data数据的)功能的 他会时时刻刻的盯着data中的数据 当data的数据改变了 他也会知道 重新计算并且在返回出计算之后的结果
一条数据 在不同位置展示不同形态的时候 使用
语法:
computed:{
你计算之后返回的数据变量(){
return 你处理数据的逻辑
}
}
Document
{{text}}
大写{{upptext}}
Document
{{text}}
大写{{upptext}}
{{fun()}}
计算属性 是依赖与缓存的 也就是说计算属性处理的数据 在第一次处理好之后就会把结果存储在内存中 只要处理的数据不变 那么无论我们调用多少次 他的数据都是从缓存中读取出来的
方法:方法只要被调用就会执行 方法比较消耗性能
watch监听一个data数据 当这个data数据改变的时候 watch就会出发一个函数完成一些指定的功能(异步操作 开销较大的逻辑)
计算属性 依赖一个data的数据 当这个数据变了他会重新计算这个数据返回结果
$event来描述事件对象
Document
事件对象的使用
就是帮助我们来修饰一些在触发事件过程中的一些细节
修饰符:@事件.修饰符
帮助我们在出发一些事件的时候 指定键盘按钮
.up .down .ctrl .enter .space等 按键修饰符
.prevent 阻止事件默认行为
.stop 阻止冒泡
.captrue 设置当前为捕获事件
.once 当前事件只会触发一次
.self 只会触发自身的事件 不包含子元素
全局与局部
全局就是在所以uvue实例中都可以使用
局部就是只能在当千实例中使用
在不改变原始数据的情况下 格式化展示内容
写在创建vue实例之前
Vue.filter(“过滤器的名字”,(你要过滤的数据)=>){
return 你过滤的逻辑
})
Document
{{text}}
{{text}}
使用:
| 管道符来进行使用 数据|过滤器的名字
{{text|xiaoming}}
写咋像是这个过滤器的实例中 与el data methods watch computed同级
filters:{
过滤器的名字(val 你要过滤的数据会自动传入){
return 你过滤的逻辑
}
}
Document
{{text|xiaoming}}
{{text|xiaoming}}
在vue2x之后 内置过滤器已经移除了 所以在vue2.0之后就没有内置过滤器了
在特定阶段内被自定义执行的函数 就叫做钩子函数
被自动执行的函数
就可以让程序在特定阶段自动执行某些操作
钩子函数就是几个vue预先定义好的自动执行的函数 所以我们如果要写 写在data el methods等同级位置
实例创建之前---beforeCreate 在这个钩子中数据观测与事件还没有开始
实例创建完毕---created数据的观测 实例的其他属性 以及事件等 都已经准备好了
模板渲染之前--befireMount 已经准备开始挂载页面了 次是页面还诶有开始渲染
模板渲染之后--mounted el属性已经挂载完成 dom也已经渲染加载完毕了
数据更新之前--beforeUpdate 准备开始更新 猜这个时候还没有更新进行数据的状态修改
数据更新之后--updata 数据页面Dom都已经修改完毕了
实例销毁之前 -- beforeDestory 小胡胡之前 但是此时实例还可以使用
实例销毁之后 -- destoryed 实例已经不存在了和vue相关的左右内容都不能使用
实例创建前后 模板渲染前后
vue预先定义好的自动致新个函数 实在vue实例从创建到销毁的过程中自动执行某些特定过得业务函数
nounted
1.电脑上必须有node
2.全局下载vue-cli(除非你重新装电脑了或者重装node了,否则只要下载一次就好了 )npm install -g @vue/cil
3.测试下载是否成功 vue --version
4.把cmd cd到执行下载项目的文件夹下
5.新建项目 vue create项目名
会出现选择 那么在第一项 我们选择第三个自定义 剩下的 眼睛一闭 回车到底
6 把cms cd到你下载的项目之下
7 启动 npm run serve
.vue文件---》单文件组件
组成:
1.template --》把你的html写进去
2.script --》把你的js写进去
3.style --》把你的css写进去
1.删除src下的components文件夹下的Helloword.vue
2.在新建一个属于我们自己的.vue文件并写入如下内容
你好么么哒
3.来到app.vue中(app.vue是全部组件的老大)修改原来里面helloword相关内容成我们自己的
data
语法:
data(){
return {
}
}
因为对象是引用数据类型 如果data是对象的方式创建的 那么这个组件被多次调用的时候 data都指向的是统一的内存空间
函数的话 每一次调用都返回一个新的对象
methods
watch
computed
filters
8个生命周期的钩子函数
组件把一个页面拆成多个细小的小功能个区域 分别来创建就可以让这一个个的小模块方便重复的进行调用 减少了代码量降低了后期维护难度
创建组件其实就是新建一个.vue文件 并且写入如下内容
我是一个组件么么哒
使用组件
在你想使用的地方
引用
// 1.引用
import Demo from "./components/demo.vue"
调用
components用来描述局部组件 写在与data methods watch等同级的位置
语法:
components:{
给你引用的组件起个名字:你引用的组件
}
components:{
Demo
}
使用
标签有单标签和双标签 单标签 <关键字/> 双标签 <关键字>关键字>
<你的组件名/>
当前样式仅对当前组件生效
其实就是在一个组件中引用另外一个组件
引用
调用
使用
我在父组件中有个数据 我能在子组件中直接使用吗?不能
我在子组件中有个数据 我能在父组件中直接使用吗?不能
结论:
组件与组件之间是完全独立的个体 无论组件是什么关系都不能直接相互使用数据
父组件把数据给子组件使用
1.子组件需要使用props来创建接受传递过来数据的变量
props写在与data methods等同级的位置
语法:
props:[变量1,变量2,......,变量n]
{{xiaoming}}
2.父组件要给他传递数据
在子组件在被调用的时候 把子组件的props当做一个属性来进行传值
就是在现有的正向传值之上 对父组件传递给子组件的数据进行数据格式或者累心上的验证
1.子组件接收的时候需要设置接收数据的验证
props:{
你接收数据的变量:数据类型
你接收数据的变量:[ 数据类型1,数据类型2 ]
你接收数据的变量:{
type:你要验证的数据类型,
default:默认值
}
}
props:{
//text:String 只验证一种类型
text:[String,Number]
}
默认值语法
props:{
//text:String 只验证一种类型
// text:[String,Number]
text:{
type:String,
// 默认值
default:"你好我是默认值"
}
}
子组件把数据给父组件
逆向传值默认是不被允许的 如果想逆向传值的话那么我们必须要通过自定义事件来完成
逆向传值必须要通过一个事件来触发自定义事件的创建
1.在子组件中必须要用一个事件来触发
zizzizizizizizi
2.自定义事件 使用this.$emit()来实现自定义事件
语法:this.$emit(“自定义事件名”,“数据”)
zizzizizizizizi
3.父组件接受这个自定义事件
fufuffufufufufufufu
逆向传值默认不被允许 所以我们通过事件触发一个自定义事件的抛出 在父组件中使用@绑定这个自定义事件 从而得到子组件的数据
相同父组件的两个子组件之间相互传值
默认情况下兄弟组件要进行传值
eventBus---中央事件总线 就是凌驾在两兄弟组件之上的一个空的vue实例(中央事件总线eventBus)通过这个空的vue实例 就在两个兄弟组件之上建立了数据通信的桥梁
1.新建文件夹eventbus与文件用来存放这个中央事件总线的空实例
2.创建空实例
import Vue from "vue"
//创建空实例并且暴漏
export default new Vue
3.需要传递的组件中 引用中央事件总线 并且 使用事件来触发 给中央事件总线之上绑定一个自定义事件
zia
4.在需要数据的组件之上 先引用中央事件总线 使用$on()来监听实例上的自定义事件
zib
组件与组件之间有多个层级关系的时候传值
vuex状态(数据)管理工具 给仙姑提供了一个集中保存数据的地方 把项目的数据都放在这个仓库中 无论哪个组件想使用某条数据 那么直接来仓库去取出即可 免去了传统组件与组件之间传递数据的复杂性
vue是单项数据流 那么组件与组件之间在传递的时候 如果是兄弟或者跨组件又或者逆向传值 我们就可以使用vuex来集中的管理我们的数据
state存放数据的地方
定义state实在vuex在文件中的state中进行定义
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {//就是这个仓库中存放数据的地方
name:"xixi"
},
mutations: {
},
actions: {
},
modules: {
}
})
使用方式1
直接在你想使用的地方用 this.$store.state.xxx 来直接读取
This is an about page{{this.$store.state.name}}
使用方式2
在计算属性中进行调用
This is an about page{{this.$store.state.name}}
计算属性方式取值--{{newname}}
总结:
1.vuex是一个仓库 里面有很多个对象 其中state就是用来保存数据的地方 相对与vue的data作用
2.state里面的数据时响应式的 vue的组件从store中读取数据如果store中的state改变了 那么对应引用的视图也会随之发生改变
传统写法上 我们把所有的vuex操作都在一个文件中继续编写太麻烦了 后期也不好维护
1.在store下新建文件夹 用来存放我们拆分的模块文件
2.在文件中新建对象并且把vuiex的属性放置进去
let aboutm={
state: {//就是这个仓库中存放数据的地方
name:"我是about的数据",
},
mutations: {
},
actions: {
},
}
export default aboutm
3.在vuex的文件中引用模块 调用模块
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
// 1.引用模块
import Aboutm from "./modules/aboutm.js"
import Homem from "./modules/homem.js"
export default new Vuex.Store({
modules: {//2.模块的调用
Aboutm,Homem
}
})
4.在使用模块之后 页面使用数据 就必须是this.$store.state.模块名.xxxx
This is an about page{{this.$store.state.aboutm.name}}
在vuex中如果想要修改数据 不能直接修改 而是要通过mutations来进行修改 mutations是一个属性 其中有n和方法就是一个修改的动作
let homem={
state: {//就是这个仓库中存放数据的地方
name:"我是home的数据",
},
// 在vuex中如果想要修改数据 不能直接修改
// 而是要通过 mutations来进行修改
// mutations 是一个属性
// 其中有n个方法 每个方法就是一个修改的动作
mutations: {
// state 形参就是上面的state数据源
// payload 提交载荷 后续调用的时候传递进来的参数
upname(state){
state.name="呵呵!!!!"
}
},
actions: {
},
}
export default homem
在组建中触发这个修改 commit(“你要触发的mutations的名字”)
在组件中使用函数 来调用this.$store.commit()修改
methods:{
fun(){
// 使用commit()调用mutations 修改state
this.$store.commit("upname")
}
}
总结 在vuex中使用commit调用mutations 来修改state的数据
就是用来接收调用mutations的时候传递进来的数据
homedata(state,payload){
state.name=payload.text
}
在组件中使用conmmit的时候传递第二个参数
fun(){
// commit中传递了第二个参数 那么这个参数会被mutations的payload接收
this.$store.commit("homedata",{text:"我是paylad接收的数据"})
}
action也是vuex的一个属性 作用就是用来在vuex中触发异步操作 它里面也是有n个方法 每个方法就是一个触发异步操作的动作
1.创建actions并且写入触发的动作
actions: {
// 创建触发异步的动作
// context就是代表$store
// payload 载荷接收外部的数据
demolink(){
// 调用异步操作
console.log("我触发了异步操作");
}
},
2.在页面触发数据请求 dispatch(“actions的名字”)
funb(){
this.$store.dispatch("demolink")
}
1.需要模拟数据就新建mockjs 写好数据请求与拦截器
2.我们需要在组件页面通过dispath()来处罚一个vuex的actions来调用一个请求
数据请求的闭环操作
3.来到vuex中创建对应的modules并且在vuex文件中引用调用 方可使用模块
创建模块
let aboutm={
state: {
},
mutations: {
},
actions: {
}
}
export default aboutm
使用模块
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
// 2.引用创建的vuex模块
import aboutm from "./modules/aboutm.js"
export default new Vuex.Store({
state: {
},
mutations: {
},
actions: {
},
modules: {
// 3.调用模块
aboutm
}
})
4.在vuex的actions中创建对应的异步触发方法
let aboutm={
state: {
},
mutations: {
},
actions: {
// 4创建 异步触发的任务动作
demoaxios(){
}
}
}
export default aboutm
5.在模块中引用 使用我们封装好的异步请求 进行数据请求
// 5.先引用数据请求封装
import getlink from "@/api/getapi.js"
let aboutm={
state: {
},
mutations: {
},
actions: {
// 4创建 异步触发的任务动作
demoaxios(){
// 6 调用封装的请求 进行数据请求
getlink("/data/mock/userlist").then((ok)=>{
console.log(ok.data)
})
}
}
}
export default aboutm
6.把请求来的数据 通过commit传递到mutations上
// 5.先引用数据请求封装
import getlink from "@/api/getapi.js"
let aboutm={
state: {
},
mutations: {
},
actions: {
// 4创建 异步触发的任务动作
// 7.创建context形参
demoaxios(context){
// 6 调用封装的请求 进行数据请求
getlink("/data/mock/userlist").then((ok)=>{
console.log(ok.data)
// 8把请求来的数据交给mutations来修改state
context.commit("uparr",{data:ok.data})
})
}
}
}
export default aboutm
7.在mutations中进行state的修改 并且在state中也创建数据
// 5.先引用数据请求封装
import getlink from "@/api/getapi.js"
let aboutm={
state: {
// 11.新建状态数据
arr:[]
},
mutations: {
// 9.新建mutations
uparr(state,payload){
// 10修改state的数据 根据payload的值(payload的值就是请求来的数据)
state.arr=payload.data
}
},
actions: {
// 4创建 异步触发的任务动作
// 7.创建context形参
demoaxios(context){
// 6 调用封装的请求 进行数据请求
getlink("/data/mock/userlist").then((ok)=>{
console.log(ok.data)
// 8把请求来的数据交给mutations来修改state
context.commit("uparr",{data:ok.data})
})
}
}
}
export default aboutm
8.在组件中读取请求过来的state数据
数据请求的闭环操作
{{newarr}}
组件在被调用的时候 我们知道组件的本质是自定义标签 标签是可以在内部插内容的 组件可以
默认情况下不可以
用来混合父组件与子组件自己的模板(就是可以在组件被调用的时候 向其内部插入新的dom节点)槽口也是组件提高复用的技术之一 props如果是只能向组件内部插入数据的话 那么槽口就是可以向组件内容部插入新的dom节点
默认情况在组件是一个自定义标签 但是在组件被调用的时候不能直接插入dom节点 所以在这个时候需要给组件内部设置一个插槽 来接收外部插入的数据
语法
zizizizizziizziz
上面这种写法 后期插入的内容多个就不好维护了 所以在开发的时候使用的很少
带有名字的槽口 给槽口在定义的时候起个名字
语法:
在定义的时候
在插入内容的时候:
<组件>
组件>
子组件
zizizizizziizziz
父组件
fufufufuffufufu
插入内容1
插入内容2
插入内容3
插入内容4
插入内容5
插入内容6
插入内容7
插入内容8
插入内容9
插入内容0
1.新建很多的html文件
2.使用 标签的方式进行跳转(a标签) 或者使用js的方式进行跳转(window.location.href )
传统的项目称之为 多页面项目
根据url的不同来渲染不同的组件页面
SPA -- 单页面应用 在用户切换页面的时候 没有那种传统页面的白屏问题 提高了用户的体验
在创建脚手架的时候 选择自定义 在选择Router 即可
在创建完项目之后 会在src中多了两个文件夹
router ---》 当前文件夹就是配置路由的文件夹
views ---》 当前文件夹就是来写路由页面组件的
1.删除components里面的helloword.vue 与views里面的home.vue about.vue文件
2.views下新建你所需要的组件页面
3.需要配置路由规则 去router下的index.js中配置
(3-1)引用你所想要的页面 到index.js下 import from
(3-2) 在index.js的数组对象中 进行规则的配置
// 引用vue
import Vue from 'vue'
// 引用vue的路由功能模块
import VueRouter from 'vue-router'
// 引用你要配置的路由页面
// @ 只要在路径中出现 无论是在那个层级 只要写@就指向src
import Home from "@/views/home.vue"
import Jingxi from "@/views/jingxi.vue"
import Phone from "@/views/phone.vue"
import Shop from "@/views/shop.vue"
import User from "@/views/user.vue"
// 在vue中 使用 vue路由
Vue.use(VueRouter)
// 配置路由规则的地方
const routes = [
// 配置路由规则
{
path: '/home', //url的路径
name: 'home',//给这个规则起个名字
component: Home //根据上后面的path路径 所渲染的组件页面
},
{
path: '/jingxi', //url的路径
name: 'jingxi',//给这个规则起个名字
component: Jingxi //根据上后面的path路径 所渲染的组件页面
},
{
path: '/phone', //url的路径
name: 'phone',//给这个规则起个名字
component: Phone //根据上后面的path路径 所渲染的组件页面
},
{
path: '/user', //url的路径
name: 'user',//给这个规则起个名字
component: User //根据上后面的path路径 所渲染的组件页面
},
{
path: '/shop', //url的路径
name: 'shop',//给这个规则起个名字
component: Shop //根据上后面的path路径 所渲染的组件页面
},
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
使用 router-link这个标签来完成页面的跳转 其中有个to属性就是 你要去哪里的路径
每当我们选中那个声明式导航之后 vue会自动给这个导航添加一个router-link-active的类名 那么我们就可以根据这个动态的类名添加样式
1.跳转 this.$router.push("/去哪里的路径")
2.替换 this.$router.replace("/替换的路径")
fun(){
this.$router.push("/home")
}
3.前进与后退 this.$router.go() 正数 前进 负数 后退
就是当路径没有匹配页面的时候 需要给用户一个错误页面的提示
// 404页面是一个错误提示页面 我们必须把路由规则配置放在最后
{
path: '*',
name: 'Err',
component: Err
},
路由规则也是由优先级的 配置越靠前 优先级越高
重(重新)定(定位)向(方向路径)
在用户第一次进入的时候 我们需要把用户的路径重新定位到 首页
在路由规则中进行重定向的设置
const routes = [
{
path: '/home',
name: 'Home',
component: Home
},
{
path: '/shop',
name: 'Shop',
component: Shop
},
{
path: '/user',
name: 'User',
component: User
},
// 重定向 /默认路径
{path:"/",redirect:"/home"},
// 404页面是一个错误提示页面 我们必须把路由规则配置放在最后
{
path: '*',
name: 'Err',
component: Err
}
]
router-view 来设置路由出口 就是根据路由的规则 显示规则所匹配的路由组件页面 显示的位置
在应用开发的过程中通常会出现在一个页面中嵌套另外一个局部页面进行局部跳转的时候
1.新建二级路由页面
2.在router下的index.js中先引用二级路由
3.配置二级路由的规则
(3-1)要配置规则先要确定规则写在那 二级路由的规则写在一级路由的规则内 使用children来标识
path可以是 /二级路由
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/home.vue'
import Shop from '../views/shop.vue'
import User from '../views/user.vue'
import Err from '../views/err.vue'
// 二级路由
import Era from "@/views/er/era.vue"
import Erc from "@/views/er/erc.vue"
import Erd from "@/views/er/erd.vue"
Vue.use(VueRouter)
const routes = [
{
path: '/home',
name: 'Home',
component: Home
},
{
path: '/shop',
name: 'Shop',
component: Shop
},
{
path: '/user',
name: 'User',
component: User,
// 设置二级路由
children:[
{
path: '/era',
name: 'era',
component:Era
},
{
path: '/erc',
name: 'erc',
component:Erc
},
{
path: '/erd',
name: 'erd',
component:Erd
},
]
},
// 重定向 /默认路径
{path:"/",redirect:"/home"},
// 404页面是一个错误提示页面 我们必须把路由规则配置放在最后
{
path: '*',
name: 'Err',
component: Err
}
// {
// path: '/about',
// name: 'About',
// // route level code-splitting
// // this generates a separate chunk (about.[hash].js) for this route
// // which is lazy-loaded when the route is visited.
// component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
// }
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
path也可以是 不带/
{
path: '/user',
name: 'User',
component: User,
// 设置二级路由
// path不带/
children:[
{
path: 'era', // path不带/
name: 'era',
component:Era
},
{
path: 'erc', // path不带/
name: 'erc',
component:Erc
},
{
path: 'erd', // path不带/
name: 'erd',
component:Erd
},
]
},
4.设置二级路由的路由出口 在对应的一级路由页面中进行设置 使用router-view
user
5.设置二级路由的导航
方式1 在设置二级路由规则的时候 path带/来设置的时候 二级路由的路径是 /二级路由
era
erc
erd
方式2 在设置二级路由规则的时候 path不不不不不不不不不不不不不不带/来设置的时候
二级路由的路径是 /一级路由/二级路由
era
erc
erd
在vue中需要把数据从一个页面传递到另外一个页面的时候
1.在需要接收数据的路由规则中设置接收参数
{
path: '/shop/:xiaoming',//设置接收参数
name: 'Shop',
component: Shop
},
2.发送
声明式
home
点我把数据使用声明式方式传递到shop中
methods:{
fun(){
this.$router.push({name:'Shop',params:{xiaoming:'1111呵呵我是传递的额数据'}})
}
}
3.接收
直接使用this.$route.params.xxxx
shop----{{this.$route.params.xiaoming}}
1.发送
语法:
点我声明式传参query
点我声明式传参query2222
语法上区别
query方式传参分为两步 发送数据的时候可以使用name还可以使用path来进行 接收的时候使用this.$route.query.xxxxxx
params 传参需要三步 并且在发送数据的时候只能是name 接收的时候使用this.$route.params.xxxx
url展示上 params在url上面只展示数据 相对来说传参安全一点 queryurl 有key还有val 相对来说不安全
$router对象: 是vue路由的对象 他是路由实例 他是一个路由全局对象 包含了与路由相关的关键属性
$route对象 : 是跳转到指定路由的局部对象 一个路由页面就有一个$route对象
在vue中路由模式使用 mode来进行指定
1.hash模式 默认模式 你不写就是hash模式
2.history模式
区别 | hash | history |
url展示上 | url带# | url不带# |
浏览器兼容性 | 兼容性好 | html5新特性所以对ie兼容性不好 |
浏览器刷新 | 刷新之后正常显示 | 上线之后刷新页面丢失 |
就是在路由跳转的时候触发的钩子函数
全局前置
在路由跳转的时候 进入下一个路由之前触发
beforeeach
to 去哪里
from 从哪里来
next 下一步 必须有
router.beforeEach((to,from,next)=>{
console.log(to)
console.log(from)
next()
})
全局后置
在路由跳转的时候 进入下一个路由后触发
aftereach()
仅仅只会对一个路由生效
beforeRouterEnter()
to 去哪里
from 从哪来
next 下一步
{
path: '/user',
name: 'user',
component: () => import('../views/user.vue'),
// d当前路由生效
beforeEnter(to,from,next){
console.log(to)
console.log(from)
next()
}
beforeRouteEnter() 进入当前组件的时候调用
beforeRouteLeave() 离开当前组件的时候调用
shop
路由懒加载 路由页面按需加载
因为在传统的vue项目中如果使用了路由可能会出现 首页白屏问题 也会造成很大的性能问题
1.import导入
component: () => import('你要显示路由的页面路径')
2.异步组件
component: (resolve) => require(['你要显示的路由页面路径即可'], resolve),
我们给路由的规则中添加一个meta的对象 那么就可以在其中存储一些信息 在页面进行使用
{
path: '/phone',
name: 'phone',
component: () => import('../views/phone.vue'),
// meta元信息
meta:{
text:"我是路由中的meta信息"
}
在当前页面中使用这个meta信息
this.$route.meta.xxx
phone---{{this.$route.meta.text}}
this.$router.options.routes
数据请求在vue中有多种方式
1.原生或者jquery的ajax
2.vue-resource vue官方出品 vue2x之后已经停止更新了
3.axios 是一个第三方的数据请求 他是基于XHr对象的 但是在XHR对象之上使用promise进行了封装 让他更符合当下的主流语法规范
4.fetch请求 是es最新的规范
因为是第三方的所有需要先下载 npm install --save axios
axios.get() axios.post()
axios()
基本axios的使用
公司中就不一定是按照咱们所学的方式进行封装了 因为有的公司可能在封装的时候就是单纯的把请求提取出来
有一些可能使用promise来进行封装 有一些公司可能是用async 来进行封装
我们需要认识一个文件夹 **api 这个文件夹通常百分之90都是用来存放数据请求的**
使用promise来进行封装(提高了复用性 让自己写的代码叼一点)
api文件夹中进行封装
import axios from "axios"
// 在其中进行请求的封装
let getlink=(url)=>{
// resolve成功数据会交给then来接收 reject失败的数据会交给catch来接收
return new Promise((resolve,reject)=>{
// 就来写你的异步操作
axios({
url,
method:"GET"
}).then((ok)=>{
resolve(ok)
}).catch((err)=>{
reject(err)
})
})
}
// 千万不要忘了
export default getlink
在组件中引用使用
使用封装来进行请求
如果需要编写拦截器 我们需要创建一个util文件夹工具文件夹(与项目业务无关的一些代码 但是有了这些代码可以提高效率)
什么是拦截器?
拦截请求的一个技术
有些情况下 我们需要在每次请求的时候都要携带一个参数(比如:用户的登录状态信息) 那么我们就可以放到拦截器中 因为每次请求拦截器都会先拦截到 让后才去发送请求 那么我们就可以在拦截器中吧这些参数信息进行统一的添加 不需要每次请求都写一遍
1.请求拦截 我们在发送请求的时候 他会拦截
2.相应拦截 服务器把数据给我们的时候先被拦截器所拦截
// 就是用来存放拦截器的
// 引用axios
import axios from "axios"
// 1创建axios实例并且交给一个变量方便使用\
const service = axios.create()
// 2.创建请求与相应拦截
// 添加请求拦截器
service.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
service.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
// 千万不要忘了暴露
export default service
请求封装调用拦截器
// 数据封装于拦截器
import service from "@/util/service.js"
let getblink=(url)=>{
return new Promise((resolve,reject)=>{
// 使用request请求
service.request({
url,
method:"GET"
}).then((ok)=>{
resolve(ok)
}).catch((err)=>{
reject(err)
})
})
}
export default getblink
在前后端分离开发的过程中 有的时候后台数据在我们编写前台的时候还没有写好 我们可以在后台没有准备好的时候 先试用模拟数据创建数据 然后用请求请求我们的模拟数据进行展示、
数据json json是键值对 但是后台在创建数据的时候 这个key起什么名字 后台可能会问你咱俩一起对下接口数据吧(理想派 我们可以把我们的模拟数据的key来进行和他沟通) 他自己默默的把后台数据写好了 然后给你了(沉默派 你不知道数据里面的东西代表什么 你的嘴要甜一点 发信息说 哥 我刚来公司 咱们公司的流程可能不太熟 您看 某某key是个什么意思 你可以问题要接口文档 你也可以过去问他)
1.mockjs是一个第三方的模拟数据的库
npm install --save mockjs (注意单词没有点)
2.新建一个mock文件夹 这个文件夹今后在工作中通常就是写模拟数据的 在其中创建一个存放模拟数据的文件夹 与编写代码的index.js
3.新建模拟数据 是以.json结尾的文件
4.在index.js来编写 mockjs的代码
let Mock=require("mockjs")
// Mock.mock("随便写一个请求的接口地址","请求方式",require("你的模拟数据路径"))
Mock.mock("/data/list","GET",require("./data/demo.json"))
5.在main.js中引用mock
import Vue from 'vue'
import App from './App.vue'
import router from './router'
// 引用mock
require("./mock")
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App)
}).$mount('#app')
注意 一定要重启项目
多个组件中都要使用一些相同的方法
混入就是vue组件中一个提高组件复用性的一个技术 他可以让多个组件中重复使用的方法 等内容进行提取出来然后在想使用的地方直接使用
1.全局混入
慎用 因为会污染整个项目
1.文件夹mixins与文件的创建 并且全局混入的文件写法和局部混入相同
2.引用调用的时候需要在main.js中引用调用 剩下在任何组件中就可以直接使用混入的内容了
// 1.混入引用 import xiaoming from "./mixins/xiaoming.js" // 2.调用 Vue.mixin(xiaoming)
2.局部混入
1.新建文件夹mixins文件 来存放我们提取出来的内容 创建js文件来进行存放
2.在js中创建一个对象写入你想复用的内容
let xiaoming={
// 提取出想复用的方法
methods:{
fun(){
console.log("你好");
}
}
}
export default xiaoming
3.在想使用的组件中引用调用使用
混入的使用
混入中除了函数 生命周期 计算属性等也可以 data也可以
在现有指令不够的情况下我们可以创建自定义指令
指令就是html的属性 属性就是给html添加特殊的功能
写在与data methods等同级的位置
语法:
direactives:{
自定义指令的名字:{
自定义指令的钩子函数(形参就是你绑定这个自定义指令的当前dom元素){
你的逻辑
}
},
自定义指令的名字:{
},
}
自定义自定义指令
在vue中默认是没有dom操纵的 有些时候我们就是需要使用dom的操纵 那么就可以使用vue提供的ref来进行
基本使用
ref的基本使用
你在开发中有没有遇见过数据改变了但是视图没有改变的问题 你是怎么解决的?
$set
{{obj.name}}
--------------------------------
age:{{obj.age}}
出现的场景是 如果我们在vue中向data定义的数组获取对象中添加新的属性的时候 就会出现数据变了但是视图没有发生改变
原因 :因为双向绑定中 依赖数据劫持(object.defineProperty()) 数据劫持有一个非常大的bug 他只会劫持初始化的时候data有的数据 但是当程序运行之后 在给data的属性插入新的内容的时候 由于数据劫持劫持不到 就没有双向绑定了 没有双向绑定了 当然数据变了视图不会发生改变
所以我们为了解决这种数据变视图不发生改变的问题 我们使用$set来解决
语法: this.$set( 你要操纵的数据,新增的key,新增的val )
fun(){
// this.obj.age=18
// $set来进行添加新属性
this.$set(this.obj,"age",666)
console.log(this.obj.age);
}
多个组件使用同一个挂载点(component)并且动态组件
挂载点这个挂载点放在页面的那个地方 那么动态切换的内容就在哪里展示:
1.新建多个组件
2.在需要动态显示这多个组件的位置使用 来设置挂载点 并且引用调用 你要使用的组件到当前页面中
3.创建变量 在变量中设置多个组件初始化显示的内容
data(){ return{ com:"你要初始化显示的组件名" } },
4.把这个变量插入到挂载点的is上
5.想动态切换 只需要 改变 你保存显示组件的那个变量即可
我们新建的路由页面 用户在路由页面中填写内容之后 在进行路由的切换 会发现数据不见了
同样的我们在使用动态组件进行切换的时候 会和路由一样 数据丢失
因为路由或者动态组件 在切换的时候 vue会在每次切换的过程中 对切换的组件进行实例的重新创
keep-alive 使用他可以把组件中的状态保留在内存中 防止组件重复dom渲染 减少了在切换的时候性能上面损耗 提高用户体验
语法 :
你要保存状态的组件放进去
在vue2.1之后 kepp-alive加入了新的特性 引进了两个属性
incloude 你要缓存谁
excloude 你不缓存谁
incloude 与 excloude 同时都写了听谁的?
excloude的优先级高
这两个钩子函数需要写在被keep-alive管理的组件之内 以data methods等同级
activated 进入被keep-alive管理的组件时候调用
deactivated 离开被keep-alive管理的组件时候调用
vue的响应式 不是在 数据变化了之后 DOM立即改变 而是按照一定的策略进行dom的更新。
{{text}}
简单来说 vue在数据修改之后 视图是不会立即更新 而是等同一事件循环中的所有数据都变化了 之后 在同一进行页面视图的更新
原理:
1 vue先进行数据的修改 是一个同步任务 同一事件循环上的所有同步任务 进行一个个的执行 但是这个时候 还没有涉及到dom的任何操作
2.vue开启一个异步列队 把在上面事件循环中的数据变化进行异步的缓冲
3 同步任务执行完毕 开始执行异步的列队任务 , 更新dom
会在dom加载完毕之后 立即执行的一个方法
nextTick
{{text}}
在根路径下创建vue.config.js 写入open 自动开启
module.exports={ devServer:{ open:true,//自动开启浏览器 } }
修改端口
module.exports={ devServer:{ open:true,//自动开启浏览器 port:8888 //修改端口 } }