基本语法
1.1、初时Vue
1.想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象;
2.root容器里的代码依然符合html规范,只不过混入了一些特殊的Vue语法;
3.root容器里的代码被称为【Vue模板】;
4.Vue实例和容器是一一对应的;
5.真实开发中只有一个Vue实例,并且会配合着组件一起使用;
6.{{xxx}}中的xxx要写js表达式,且xxx可以自动读取到data中的所有属性;
7.一旦data中的数据发生改变,那么页面中用到该数据的地方也会自动更新;
注意区分:js表达式 和 js代码(语句)
1.表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方:
(1). a
(2). a+b
(3). demo(1)
(4). x === y ? 'a' : 'b'
2.js代码(语句)
(1). if(){}
(2). for(){}
1.2、插值语法{{}}
Vue模板语法有2大类:
1.插值语法:
功能:用于解析标签体内容。
写法:{{xxx}},xxx是js表达式,且可以直接读取到data中的所有属性。
** 2.指令语法:**
功能:用于解析标签(包括:标签属性、标签体内容、绑定事件…)。
举例:v-bind:href=“xxx” 或 简写为 :href=“xxx”,xxx同样要写js表达式,
且可以直接读取到data中的所有属性。
备注:Vue中有很多的指令,且形式都是:v-???,此处我们只是拿v-bind举个例子。
1.3、绑定属性
Vue中有2种数据绑定的方式:
1.单向绑定(v-bind):数据只能从data流向页面。
2.双向绑定(v-model):数据不仅能从data流向页面,还可以从页面流向data。
备注:
1.双向绑定一般都应用在表单类元素上(如:input、select等)
2.v-model:value 可以简写为 v-model,因为v-model默认收集的就是value值。
<!-- 普通写法 -->
单向数据绑定:<input type="text" v-bind:value="name"><br/>
双向数据绑定:<input type="text" v-model:value="name"><br/>
<!-- 简写 -->
单向数据绑定:<input type="text" :value="name"><br/>
双向数据绑定:<input type="text" v-model="name"><br/>
1.3.1绑定样式
<template>
<div>
<!--绑定样式-->
<div :style="['font-size:50px','color:red']">box</div>
<div :style="[fontSize,bgColor]">box</div>
<hr>
<!--绑定类-->
<!-- <div class="one" :class="'two'">aaaaaaaa</div>-->
<div class="one" :class="two">aaaaaaaa</div>
<!-- <div class="one" :class="['one','two']">aaaaaaaa</div>-->
<!--数组方式-->
<div class="one" :class="[one,two]">元素为变量</div>
<div class="one" :class="boxStyle">数组为变量</div>
<hr>
<!--对象方式 {类名:真假值} 真则添加 假则不添加-->
<div :class="{one:isone,two:istwo}">{类名:真假值} 真则添加 假则不添加</div>
<div :class="{three}">键值相同可简写</div><!--键值相同可简写-->
<!--函数返回值方式-->
<div :class="getStyleObj()">函数返回对象</div>
<div :class="getStyleArr()">函数返回数组</div>
</div>
</template>
<script>
/*
* 单向绑定 v-bind 简写 :
*
* */
export default {
name: 'App',
data() {
return {
size: 100,
fontSize: 'font-size:50px',
bgColor: 'background-color:blue',
two: 'two',
one: 'one ',
boxStyle: ['one', 'two'],
isone: false,
istwo: true,
three: true,
};
},
methods: {
getStyleArr() {
return [this.one, this.two];
},
getStyleObj() {
return { one: this.isone, two: this.istwo };
},
},
};
</script>
1.4、计算属性
1.定义:要用的属性不存在,要通过已有属性计算得来。
2.原理:底层借助了Objcet.defineproperty方法提供的getter和setter。
3.get函数什么时候执行?
(1).初次读取时会执行一次。
(2).当依赖的数据发生改变时会被再次调用。
4.优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。
5.备注:
(1)计算属性最终会出现在vm上,直接读取使用即可。
(2)如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变。
computed:{
fullName:{
//get有什么作用?当有人读取fullName时,get就会被调用,且返回值就作为fullName的值
//get什么时候调用?1.初次读取fullName时。2.所依赖的数据发生变化时。
get(){
console.log('get被调用了')
// console.log(this) //此处的this是vm
return this.firstName + '-' + this.lastName
},
//set什么时候调用? 当fullName被修改时。
set(value){
console.log('set',value)
const arr = value.split('-')
this.firstName = arr[0]
this.lastName = arr[1]
}
}
}
1.5、事件监听
在前端开发中,需要经常和用户交互
绑定事件监听器指令:v-on
缩写: @ (语法糖)
参数: $event
v-on事件修饰符号
–.stop 阻止事件冒泡
–.self 当事件在该元素本身触发时才触发事件
–.capture 添加事件侦听器是,使用事件捕获模式
–.prevent 阻止默认事件
–.once 事件只触发一次
1.6、条件分支指令v-if和v-show
1.v-if
写法:
(1).v-if=“表达式”
(2).v-else-if=“表达式”
(3).v-else=“表达式”
适用于:切换频率较低的场景。
** 特点:不展示的DOM元素直接被移除。**
注意:v-if可以和:v-else-if、v-else一起使用,但要求结构不能被“打断”。
2.v-show
写法:v-show=“表达式”
适用于:切换频率较高的场景。
特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉(display:none)
3.备注:使用v-if的时,元素可能无法获取到,而使用v-show一定可以获取到。
1.7、循环遍历指令v-for
v-for指令:
1.用于展示列表数据
2.语法:v-for=“(item, index) in xxx” :key=“yyy”
3.可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少)
<!-- 遍历数组 -->
<h2>人员列表(遍历数组)</h2>
<ul>
<li v-for="(p,index) of persons" :key="index">
{{p.name}}-{{p.age}}
</li>
</ul>
<!-- 遍历对象 -->
<h2>汽车信息(遍历对象)</h2>
<ul>
<li v-for="(value,k) of car" :key="k">
{{k}}-{{value}}
</li>
</ul>
<!-- 遍历字符串 -->
<h2>测试遍历字符串(用得少)</h2>
<ul>
<li v-for="(char,index) of str" :key="index">
{{char}}-{{index}}
</li>
</ul>
<!-- 遍历指定次数 -->
<h2>测试遍历指定次数(用得少)</h2>
<ul>
<li v-for="(number,index) of 5" :key="index">
{{index}}-{{number}}
</li>
</ul>
补充:key的原理
:::info
面试题:react、vue中的key有什么作用?(key的内部原理)
1. 虚拟DOM中key的作用:
key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,
随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:
2.对比规则:
(1).旧虚拟DOM中找到了与新虚拟DOM相同的key:
①.若虚拟DOM中内容没变, 直接使用之前的真实DOM!
②.若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM。
(2).旧虚拟DOM中未找到与新虚拟DOM相同的key
创建新的真实DOM,随后渲染到到页面。
3. 用index作为key可能会引发的问题:
1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作:
会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。
2. 如果结构中还包含输入类的DOM:
会产生错误DOM更新 ==> 界面有问题。
4. 开发中如何选择key?:
1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
2.如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,
使用index作为key是没有问题的。
:::
1.8、v-model双向绑定
v-model的修饰符号:
.lazy 懒加载修饰符
.number 修饰符让其转换为 number 类型
.trim修饰符可以自动过滤掉输入框的首尾空格
1.9、v-model在表单中的应用
1.9.1、单选框
1、使用v-model 可以代替name 变量相同则代表同组
2、单选框状态发生改变时 会把value中的数据传到 v-model绑定的变量中
3、初始选项不必再使用checked ,直接给变量赋初值即可
<input type="radio" name="sex" value="女">女-->
<input type="radio" value="男" v-model="sex">男
<input type="radio" value="女" v-model="sex">女
<br>{{sex}}
data() {
return {
msg: 'this is a test',
sex:'男',
isRead:false,
hobby:[],
language:'vue',
languages:'vue',
}
1.9.2、多选框
1、当只需要一个复选框为真假值判断的时候,v-model传递一个布尔值,会自动根据选种情况来改变 变量值的真或假
2、当需要多个复选框同组使用时 , 需要使用数组变量接收 ,会把选中项的value值存到数组中
使用v-model 可以代替name 变量相同则代表同组
<input type="checkbox" v-model="isRead">我已阅读协议{{isRead}}
<br>
<input type="checkbox" v-model="hobby" value="smoke">抽烟
<input type="checkbox" v-model="hobby" value="drink">喝酒
<input type="checkbox" v-model="hobby" value="hotHead">烫头
<br>
{{hobby}}
data() {
return {
msg: 'this is a test',
sex:'男',
isRead:false,
hobby:[],
language:'vue',
languages:'vue',
}
1.9.3、下拉列表
1、单选时
1)v-model绑定在select标签上 可以代替name的功能
2)使用一个字符串接受选中value值
3)设置初始选项时可以将目标选项的value赋给字符串变量
2、多选时 multiple
会自动将变量转成数组类型,并将选中选项的value值存到数组中
<select v-model="language">
<option value="java">java</option>
<option value="php">php</option>
<option value="vue">vue</option>
<option value="python">python</option>
</select>
{{language}}
<br>
<select v-model="languages" multiple>
<option value="java">java</option>
<option value="php">php</option>
<option value="vue">vue</option>
<option value="python">python</option>
</select>
{{languages}}
data() {
return {
msg: 'this is a test',
sex:'男',
isRead:false,
hobby:[],
language:'vue',
languages:'vue',
}
组件化开发
- 组件化是Vue的精髓,Vue开发就是由一个一个的组件构成的。
- 组件的分类:
- 页面级组件
- 业务上可复用的基础组件
- 与业务无关的独立功能组件
- 组件开发三要素(prop,自定义事件,slot)
- prop用于定义组件的属性。
- 自定义事件用于触发组件的事件。
- slot用于组件功能的扩展。
- 组件设计需要考虑的问题
- 可扩展性强
- 组件中方法函数的抽离,便于复用,适用程度高。
- 文档清楚详细
- 颗粒度合适,适度抽象
- 功能尽可能单一,代码行数适中
2.1、父子组件之间的通信
2.1.1、父组件向子组件传数据 父=>子
props配置项
- 功能:让组件接收外部传过来的数据 , 接收到后用法和data中数据一样 (父 ==> 子)
- 传递数据:
- 接收数据:
- 第一种方式(只接收):props:[‘name’]
- 第二种方式(限制类型):props:{name:String}
- 第三种方式(限制类型、限制必要性、指定默认值):
:::info
props:{
name:{
type:String, //类型
required:true, //必要性 不传则警告
default:‘老王’ //默认值
}
}
:::
_ 备注:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,_
_ 若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。_
//父组件
<my-conn :article="article"></my-conn>
//子组件
<li v-for="item in article">{{item}}</li>
export default {
name: "MyConn",
props:{
article:{
type:Array,
}
}
}
2.1.2、子组件向父组件传数据 子=>父
**通过自定义事件
e
m
i
t
(
)
和事件监听实现
∗
∗
子组件通过使用
t
h
i
s
.
emit()和事件监听实现** 子组件通过使用this.
emit()和事件监听实现∗∗子组件通过使用this.emit(‘自定义事件名称’,传递参数data)
父组件通过在组件标签上使用<子组件 @自定义事件名称=“方法fun”></子组件>
fun(子组件传递的参数data){}
//子组件 my-conn
<button @click="changeNum(2)">++++</button>
methods:{
changeNum(n){
this.$emit("myCountEvent",n)
}
}
//父组件
<my-conn @myCountEvent="myDemo"></my-conn>
methods:{
myDemo(data){
this.count += data
}
}
2.2父子组件之间的访问方式
2.2.1、子组件访问父组件:
可以通过$parent获取父组件中的属性和方法,可连续调用访问多层
如果访问跟组件可直接调用$root方法
2.2.2、父组件访问子组件:
在Vue2中可以使用$children 获取一个子组件数组,Vue3删除了该方法
可以先使用 ref属性标记子组件 (类似id属性) ref="xxx"
再调用 $refs.xxx 获取子组件
2.3、插槽
- 作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,
适用于父组件 ===> 子组件。 - 分类:默认插槽、具名插槽、作用域插槽
2.3.1、默认插槽
<!-- 默认插槽 ==>父组件 -->
<MyBar>
<button>默认插槽--提交</button>
</MyBar>
<!-- 默认插槽 ==>子组件-->
<slot>默认值</slot>
2.3.2、具名插槽
:::info
需要使用包裹内容
template中设置属性
1. v-slot:子组件中插槽name值 简写 #子组件中插槽name值
2. Vue2中还可使用 slot=“子组件中插槽name值” Vue3已删除
:::
<!-- 具名插槽 ==>父组件-->
<MyBar>
<template v-slot:btn>
<button>具名插槽--提交</button>
</template>
<template #one>
<a href="">具名插槽--one</a>
</template>
<template #two>
<a href="">具名插槽--two</a>
</template>
</MyBar>
<!-- 具名插槽 ==>子组件-->
<slot name="btn">默认值1</slot>
<br>
<slot name="one">默认值2</slot>
<br>
<slot name="two">默认值3</slot>
<br>
2.3.3、作用域插槽
:::info
理解:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。
(userinfo和school数据在子组件Mybar中,但使用数据所遍历出来的结构由父组件MySidebar决定)
使用方法 :
v-slot:子组件中插槽的name值=“自定义对象” ,子组件传的所有数据都会存到自定义的对象中
简写:#子组件中插槽的name值=“自定义对象”
:::
<!--作用域插槽 ==>父组件 -->
<MyBar>
<!-- <template v-slot:user="user">-->
<template #user="hello">
<p>作用域插槽--{{hello.userinfo.name}}-{{hello.userinfo.age}}--{{hello.userinfo.sex}}</p>
<p v-for="item in hello.school">{{item}}</p>
</template>
</MyBar>
<!-- 作用域插槽 ==>子组件-->
<slot name="user" :userinfo="userinfo" :school="school"></slot>
data(){
return{
title:"this is a title",
userinfo:{name:'张三',age:24,sex:'男'},
school:['融职教育','清华大学','北京大学','麻省理工']
}
}
2.4、Vue中组件的生命周期函数
- (1)初始化显示
- beforeCreate()
- created()
- beforeMount()
- mounted()
- (2)更新状态: this.xxx = value
- beforeUpdate()
- updated()
- (3)销毁 vue 实例: vm.$destory()
Vue2- beforeDestory()
- destoryed()
Vue3
-
beforeUnmount()
-
unmounted()
-
(4) nextTick
- 语法:
this.$nextTick(回调函数)
- 作用:在下一次 DOM 更新结束后执行其指定的回调。
- 什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。
- 语法:
-
(5)Vue-router的生命周期钩子
:::info
:::-
- 作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。
-
- 具体名字:
activated路由组件被激活时触发。
deactivated路由组件失活时触发。
2.5、Vue网络请求axios
import axios from "axios";
const server = axios.create({
baseURL: 'https://api.shop.eduwork.cn',
timeout: 10000,
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
})
//请求拦截器
server.interceptors.request.use(
config => {
console.log('-------------------请求拦截器----------------------')
config.headers.Authorization = `Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2FwaS5zaG9wLmVkdXdvcmsuY24vYXBpL2F1dGgvbG9naW4iLCJpYXQiOjE2ODE4MTk0OTQsImV4cCI6MTY4MjE3OTQ5NCwibmJmIjoxNjgxODE5NDk0LCJqdGkiOiJ4clZ6c2ZVelpySVJnYk1wIiwic3ViIjoiODk0MiIsInBydiI6IjIzYmQ1Yzg5NDlmNjAwYWRiMzllNzAxYzQwMDg3MmRiN2E1OTc2ZjcifQ.vsKQvw9m0HhWfUbzJuOvBvWVK4BnAxi-vOSNCkBwJoQ`
return config
},
err => {
return Promise.reject(error)
}
)
//响应拦截器
server.interceptors.response.use(
resp => {
console.log('-------------------响应拦截器----------------------')
return resp
},
err => {
return Promise.reject(err)
}
)
export function get(url) {
return server.get(url)
}
export function getParams(url, params) {
return server.get(url, {params})
}
export function post(url, params) {
return server.post(url, params)
}
export function put(url, params) {
return server.put(url, params)
}
export function del(url, params) {
return server.delete(url, params)
}
Vue Router 路由
3.1、基本使用
- 安装vue-router,命令:
npm i vue-router
- 应用插件:
Vue.use(VueRouter)
import router from './router'
createApp(App).use(router).mount('#app')
- 配置:
//引入路由的创建方法和模式
import {createRouter,createWebHistory} from 'vue-router'
//引入组件
import About from "@/view/About";
import Home from "@/view/Home";
import User from "@/view/User";
// 声明变量
const routes = [
{
path:'/',
name:'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: About
},
{
path: '/user',
name: 'User',
component: User
}
]
//创建路由
const router = createRouter({
history:createWebHistory(process.env.BASE_URL), //历史模式
// routes:routes,
routes
})
export default router
- 实现路由切换
<router-link to="/">首页</router-link> |
<router-link active-class="active" to="/about">关于我们</router-link> |
<router-link to="/user">个人中心</router-link>
//active-class="active" 当跳转到当前路由时添加active类样式
- 指定显示位置
:::info
:::
3.2 几个注意点
- 路由组件通常存放在view文件夹,一般组件通常存放在components文件夹。
- 通过切换,“隐藏”了的路由组件,默认是被销毁掉的,需要的时候再去挂载。
- 每个组件都有自己的$route属性,里面存储着自己的路由信息。
- 整个应用只有一个router,可以通过组件的$router属性获取到。
3.3 路由模式切换和懒加载
路由是由多个URL组成的,使用不同的URL可以相应的导航到不同的位置
Vue-Router在切换页面时是没有重新进行请求的,使用起来就好像页面是有状态的一样
借助了浏览器的History API来实现的,这样可以使得页面跳转而不刷新,页面的状态就被维持在浏览器中
vue-router中默认使用的是hash模式,也就是会出现如URL:‘localhost:8080/#/’ URL中带有#号
有三种模式
Hash: 使用URL的hash值来作为路由,用来指导浏览器动作的,对服务器端完全无用,支持所有浏览器。
History: 以来HTML5 History API 和服务器配置。
Abstract: 支持所有javascript运行模式。如果发现没有浏览器的API,路由会自动强制进入这个模式。
引入路由
:::info
//引入路由的创建方法和模式
import {createRouter,createWebHistory,createWebHashHistory} from ‘vue-router’
:::
创建路由
const router = createRouter({
//设计模式
history:createWebHistory(process.env.BASE_URL), //历史模式
// history:createWebHashHistory(process.env.BASE_URL),//哈希模式
//定义路由组件
/*
routes:[
{
path:'/',
name:'Home',
component: Home
},
]
*/
//外部引入变量方式
// routes:routes,
//简写
routes
})
引入组件的方式
方式一:普通方式:
打包时会将所有路由全部打包到一个js文件中,并加载全部组件
//引入组件
import Home from "@/view/Home";
import About from "@/view/About";
import User from "@/view/User";
const routes = [
{
path:'/',
name:'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: About
},
{
path: '/user',
name: 'User',
component:User
}
]
方式二:懒加载:
通过下面方法引入组件,会在打包时会打包成多个js文件,访问哪个路由加载哪个js文件(懒加载) — 加载速度快
const routes = [
{
path:'/',
name:'Home',
component: ()=>import('../view/Home')
},
{
path: '/about',
name: 'About',
component: 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.
//通过下面方法引入组件,会在打包时会打包成多个js文件,访问哪个路由加载哪个js文件(懒加载) --- 加载速度快
/* component: () => import(/!* webpackChunkName: "about" *!/ '../views/About.vue')*/
/*component: ()=>{return import('../view/About')}*/
component: ()=>import('../view/About')
},
{
path: '/user',
name: 'User',
component:()=>import('../view/User')
}
]
拆分写法
//引入路由的创建方法和模式
import {createRouter,createWebHistory,createWebHashHistory} from 'vue-router'
const Home = ()=> import('../view/Home')
const About = ()=> import('../view/About')
const User = ()=> import('../view/User')
// 声明变量
const routes = [
{
path:'/',
name:'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: About
},
{
path: '/user',
name: 'User',
component:User
}
]
//创建路由
const router = createRouter({
//设计模式
history:createWebHistory(process.env.BASE_URL), //历史模式
// history:createWebHashHistory(process.env.BASE_URL),//哈希模式
// routes:routes,
routes
})
export default router
使用路由:在入口js文件中
import {createApp} from 'vue'
import App from './App'
import router from './router'
createApp(App).use(router).mount('#app')
3.4 自定义标签
标签在打包时会编译成a标签,如果想要自定义其他标签的话在Vue3中需要通过以下方法:
<router-link to="/about" custom v-slot="{navigate}">
<button @click="navigate" @keypress.enter="navigate" role="link">关于我们</button>
</router-link>
//或
// 通过在全局路由追加历史记录实现
<button @click="$router.push('/user')" :class="{active:$route.path ==='/user'}">个人中心</button>
$router 表示全局路由
$route 表示当前路由
3.5 <router-link>的replace属性
- 作用:控制路由跳转时操作浏览器历史记录的模式
- 浏览器的历史记录有两种写入方式:分别为
push
和replace
,push
是追加历史记录,replace
是替换当前记录。路由跳转时候默认为push
- 如何开启
replace
模式:<router-link replace .......>News</router-link>
3.6 嵌套路由
- 配置路由规则,使用children配置项:
const routes = [
{
path:'/',
name:'Home',
component: Home
},
{
path: '/user',
name: 'User',
component:User,
// /user/order
children: [
{
path:'', //默认页面
component:MyOrder,
},
{
path:'order', //此处一定不要写:/order
name:'MyOrder',
component:MyOrder,
},
{
path:'setting', //此处一定不要写:/setting
name:'MySetting',
component:MySetting,
},
{
path:'page/:id',
name:'MyPage',
component:MyPage,
},
]
}
]
- 跳转**(要写完整路径)**
<router-link to="/user/order">我的订单</router-link>
<br>
<router-link to="/user/setting">个人设置</router-link>
3.7 参数传递
3.7.1 query参数
- 传递参数
<!-- 跳转并携带query参数,to的字符串写法 -->
<router-link :to="/home/message/detail?id=666&title=你好">跳转</router-link>
<!-- 跳转并携带query参数,to的对象写法 -->
<router-link
:to="{
path:'/home/message/detail',
query:{
id:666,
title:'你好'
}
}"
>跳转</router-link>
- 接收参数:
$route.query.id
$route.query.title
3.7.2 命名路由
- 作用:可以简化路由的跳转。
- 如何使用
- 给路由命名:
{
path:'/demo',
component:Demo,
children:[
{
path:'test',
component:Test,
children:[
{
name:'hello' //给路由命名
path:'welcome',
component:Hello,
}
]
}
]
}
- 简化跳转:
<!--简化前,需要写完整的路径 -->
<router-link to="/demo/test/welcome">跳转</router-link>
<!--简化后,直接通过名字跳转 -->
<router-link :to="{name:'hello'}">跳转</router-link>
<!--简化写法配合传递参数 -->
<router-link
:to="{
name:'hello',
query:{
id:666,
title:'你好'
}
}"
>跳转</router-link>
3.7.3 params参数
- 配置路由,声明接收params参数
{
path:'/home',
component:Home,
children:[
{
path:'news',
component:News
},
{
component:Message,
children:[
{
name:'xiangqing',
path:'detail/:id/:title', //使用占位符声明接收params参数
component:Detail
}
]
}
]
}
- 传递参数
<!-- 跳转并携带params参数,to的字符串写法 -->
<router-link :to="/home/message/detail/666/你好">跳转</router-link>
<!-- 跳转并携带params参数,to的对象写法 -->
<router-link
:to="{
name:'xiangqing',
params:{
id:666,
title:'你好'
}
}"
>跳转</router-link>
特别注意:路由携带params参数时,若使用to的对象写法,则不能使用path配置项,必须使用name配置!
- 接收参数:
$route.params.id
$route.params.title
3.7.4路由的props配置
作用:让路由组件更方便的收到参数
{
name:'xiangqing',
path:'detail/:id',
component:Detail,
//第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件
// props:{a:900}
//第二种写法:props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给Detail组件
// props:true
//第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件
props(route){
return {
id:route.query.id,
title:route.query.title
}
}
}
<ul>
<li>消息编号:{{id}}</li>
<li>消息标题:{{title}}</li>
</ul>
<script>
export default {
name:'Detail',
props:['id','title'],
}
</script>
3.8 编程式路由导航
- 作用:不借助
<router-link>
实现路由跳转,让路由跳转更加灵活 - 具体编码:
//$router的两个API
this.$router.push({
name:'xiangqing',
params:{
id:xxx,
title:xxx
}
})
this.$router.replace({
name:'xiangqing',
params:{
id:xxx,
title:xxx
}
})
this.$router.forward() //前进;
this.$router.back() //后退
this.$router.go() //可前进也可后退
3.9 重定向和别名
重定向:跳转到当前路由时,若此路由被重定向,则跳转到重定向指定的路由
redirect{name:‘路由name’}
别名:别
名是 **路径 ,**通过别名也可代替path中的路径
单个别名:alias: ‘/a’
多个别名:alias: [‘/a’ ,‘/b’,‘/c’]
注意:原路径有params参数 别名也需要写
:::info
{
path:‘page/:id’,
name:‘MyPage’,
alias:[‘p/:id’],
}
:::
const routes = [
{
path:'/',
name:'HomeRoot',
component: Home
},
{
path:'/home',
name:'Home',
//重定向
// redirect:'/', //路径
redirect:{name:'HomeRoot'}, //名字
component: Home
},
{
path: '/about',
name: 'About',
//单个别名
// alias:'/a',
//多个别名
alias:['/a','/b','/c'],
//原路径有params参数 别名也需要写
component: About
},
{
path: '/user',
name: 'User',
component:User,
// /user/order
children: [
{
path:'page/:id',
name:'MyPage',
//原路径有params参数 别名也需要写
alias:['p/:id'],
/* redirect:to=>{
//to => $route
return {path:'article',query:{name:'zhangsan',age:to.params.id}}
},*/
//缩写 to=>({})
component:MyPage,
},
]
}
]
3.10 路由守卫
- 作用:对路由进行权限控制
- 分类:全局守卫、独享守卫、组件内守卫
全局守卫:
//全局路由守卫
//全局前置路由守卫
/*Vue2中 有三个参数 :to :即将进入的路由
from 要离开的路由,
next (放行)
Vue3中 可以有两个参数:to ,from,next(可选) ,是否放行取决于返回值,假则禁止放行,真或不写则放行*/
router.beforeEach((to,from)=>{
document.title = to.meta.title;
// return false
})
//全局后置路由守卫
router.afterEach((to,from)=>{
// console.log('afterEach',to,from)
if(to.meta.title){
document.title = to.meta.title //修改网页的title
}else{
document.title = 'vue_test'
}
})
独享守卫:
{
path:'setting', //此处一定不要写:/setting
name:'MySetting',
beforeEnter(to,from){
console.log('beforeEnter',to,from)
if(localStorage.getItem('school') === 'rongzhi'){
return true
}else{
alert('暂无权限查看')
return false
}
},
component:MySetting,
},
组件内守卫: 在组件中使用
进入守卫:通过路由规则,进入该组件时被调用
:::info
beforeRouteEnter (to, from) {
},
:::
离开守卫:通过路由规则,离开该组件时被调用
:::info
beforeRouteLeave (to, from) {
}
:::
3.11 keep-alive和vue-router结合使用
- 作用:让不展示的路由组件保持挂载,不被销毁,保存在缓存中。
- 具体编码:
Vue3中:
<router-view v-slot="{Component}">
<transition>
<keep-alive>
<component :is="Component"/>
</keep-alive>
</transition>
</router-view>
Vue2中:
<keep-alive include="News">
<router-view></router-view>
</keep-alive>
两个新的生命周期钩子
- 作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。
- 具体名字:
-
activated
路由组件被激活时触发。 -
deactivated
路由组件失活时触发。
VueX
概念
在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。
何时使用?
多个组件需要共享数据时
基本使用
- 初始化数据、配置actions、配置mutations,操作文件store.js
export default createStore({
state: {
num:0,
dnum:0,
},
getters: {
},
mutations: {
mutAdd(state){
state.dnum ++
},
mutSub(state){
state.dnum --
},
//接收一个参数,参数可以使任意类型
mutAdd2(state,count){
state.dnum +=count
},
mutSub2(state,count){
state.dnum -=count
},
//接收多个参数
//将多个参数存在一个对象中
mutAdd3(state,payload){
state.dnum +=payload.count+payload.num
},
mutSub3(state,payload){
state.dnum -=payload.count+payload.num
},
//对象写法接收
mutSub4(state,p){
state.dnum -=p.payload.count+p.payload.num
},
},
actions: {
},
modules: {
}
})
- 组件中读取vuex中的数据:$store.state.sum
- 组件中修改vuex中的数据:$store.dispatch(‘action中的方法名’,数据) 或 $store.commit(‘mutations中的方法名’,数据)
备注:若没有网络请求或其他业务逻辑,组件中也可以越过actions,即不写dispatch,直接编写commit
搭建vuex环境
- 创建文件:
src/store/index.js
//引入Vuex
import { createStore } from 'vuex'
//暴露
export default createStore({
//准备state对象——保存具体的数据
state: {
num:0,
},
//VueX中的计算属性
getters: {
},
//准备mutations对象——修改state中的数据
mutations: {
},
//准备actions对象——响应组件中用户的动作
actions: {
},
//模块化
modules: {
}
})
- 在main.js中创建vm时传入store配置项
import store from './store'
createApp(App).use(store).use(router).mount('#app')
mutations传参问题
mutations中的方法只能接受两个参数
第一个参数:当前 state
第二个参数:接收到的数据
可以接收任何类型的数据,如果要传递多个数据,则需要将数据放到一个对象中进行传递
组件读取mutations中方法的方式:this.$store.commit(‘方法名’, 参数)
mutations: {
mutAdd(state){
state.dnum ++
},
mutSub(state){
state.dnum --
},
//接收一个参数,参数可以使任意类型
mutAdd2(state,count){
state.dnum +=count
},
mutSub2(state,count){
state.dnum -=count
},
//接收多个参数
//将多个参数存在一个对象中
mutAdd3(state,payload){
state.dnum +=payload.count+payload.num
},
mutSub3(state,payload){
state.dnum -=payload.count+payload.num
},
//对象写法接收
mutSub4(state,p){
state.dnum -=p.payload.count+p.payload.num
},
},
调用mutations中的方法
subMut() {
//调用Vuex中mutation中的方法
//this.$store.commit.('方法名')
this.$store.commit('mutSub')
},
subTwo() {
let count = 2
this.$store.commit('mutSub2', count)
},
addThree() {
/*let count = 2
let num = 1*/
let payload = {
count: 2,
num: 1
}
//commit只有两个参数,如果想传多个参数则需要放到一个对象里
this.$store.commit('mutAdd3', payload)
},
subThree() {
let payload={
count:2,
num:1
}
// this.$store.commit('mutSub3',payload)
// 对象写法
this.$store.commit({
type: 'mutSub4', //方法名
/*payload: {
count: 2,
num: 1
}*/
payload
})
}
vuex中的计算属性getters应用
- 概念:当state中的数据需要经过加工后再使用时,可以使用getters加工。
- 组件中读取数据:$store.getters.方法名
:::info
getters中定义的方法有两个参数
第一个参数就是state
第二个getters
如果想要传参数的话需要通过返回回调函数,并将要传的参数作为回调函数的参数
:::
vxNum(state) {
return state.num * state.num
},
booksPrice(state) {
let priceSum;
priceSum = state.books.reduce((s, n) => {
return s + n.price
}, 0)
return priceSum
},
booksGet(state) {
return state.books.filter(book=>{
return book.price >30
})
},
booksGet1(state,getters) {
//参入以回调函数参数形式传入
return function (price) {
return state.books.filter(book=>{
return book.price > price
})
}
/*return state.books.filter(book=>{
return book.price >30
})*/
},
//组件中
<h2>getter中的计算属性</h2>
<h3>{{$store.getters.vxNum}}</h3>
<h1>全部图书的总价</h1>
<h2>{{$store.getters.booksPrice}}</h2>
<h1>价格大于30的数的图书</h1>
<h2>{{$store.getters.booksGet}}</h2>
<h1>价格大于30的数的图书总价</h1>
<h2>{{$store.getters.booksPrice1}}</h2>
<h1>参数传递:价格大于20的数的图书</h1>
<h2>{{$store.getters.booksGet1(20)}}</h2>
actions异步处理操作
:::info
参数:第一个参数 context 代表上下文
相当于组件中的 this.
s
t
o
r
e
第二个参数和
m
u
t
a
t
i
o
n
s
中方法的第二个参数一样
,
负责接收数据
:
:
:
组件中获取
a
c
t
i
o
n
s
中方法的方式:
∗
∗
t
h
i
s
.
store 第二个参数和mutations中方法的第二个参数一样,负责接收数据 ::: 组件中获取actions中方法的方式:**this.
store第二个参数和mutations中方法的第二个参数一样,负责接收数据:::组件中获取actions中方法的方式:∗∗this.store.dispatch(‘方法名’,参数)**
demo(context){
setTimeout(()=>{
// context.state.num = 99;
context.commit('mutAdd')
},3000)
},
context中的方法: 可以使用解构赋值选择调用
1.commit
2.dispatch
3.getters
4.state
5.rootGetters 获取根中的getters
6.rootState 获取根中的state
fun2({state,commit,getters},payload){
// const {state,commit} = context
setTimeout(()=>{
state.num=99+payload.num1
commit('cnum')
},100)
}
注意:若没有网络请求或其他业务逻辑,组件中也可以越过actions,即不写dispatch,直接编写****commit
module模块划分
modules: {
//拆分成多个模块
//普通形式
user:{
state:{
},
getters:{},
mutations:{},
actions:{}
},
//声明调用分开
article:article,
//简写
cart,
goods,
}
const article = {
//在模块中state状态需要放在函数里面返回 类似 data(){return{}}
state:()=>({
name:'lmonkey',
slogen:'abc'
}),
getters:{
fullname(state){
return state.name+state.slogen
},
fullname2(state,getters){
//本模块中的getters
return getters.fullname+"222222"
},
fullname3(state,getters,rootState){
//rootState 根
//调用根中的state
return getters.fullname2+rootState.books[0].name
}
},
mutations:{
setname(state,payload){
state.name = payload.name
}
},
actions:{
demosome(context,payload){
/* context中的方法: 可以使用解构赋值选择调用
1.commit
2.dispatch
3.getters
4.state
5.rootGetters 获取根中的getters
6.rootState 获取根中的state
*/
// console.log(context)
setTimeout(()=>{
context.commit('setname',payload)
},2000)
}
}
}
const cart = {
state:{
},
getters:{},
mutations:{},
actions:{}
}
const goods = {
state:{
},
getters:{},
mutations:{},
actions:{}
}
如果在模块中想要获取根中的数据
在getters中,可以直接使用第三个参数rootState,获取根中的状态
在actions中,可以使用context中的rootState或rootGetters文章来源:https://www.toymoban.com/news/detail-821517.html
组合式API
https://vue3js.cn/vue-composition-api/文章来源地址https://www.toymoban.com/news/detail-821517.html
到了这里,关于Vue3脚手架笔记的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!