vue2学习
1.vue的基本概念
1.概念:Vue是一个用于 构建用户界面 的 渐进式 框架
- 构建用户界面:基于数据渲染出用户看到的界面
- 渐进式:循序渐进
- 框架:一套完整的项目解决方案
2.优缺点:
- 可以提高开发效率,需要理解记忆规则
- 响应式特性:数据变化,视图自动更新
2.核心包传统开发模式
1.常用指令
1.插值表达式
- 概念:Vue的一种模版语法
- 作用:利用 表达式 进行插值渲染
- 表达式:可以被求值
- 语法: {{ 表达式 }}
代码:
//语法:{{ 表达式 }}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
//导入根目录下的 开发版本包
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
{{ count }}
</div>
<script>
const app=new Vue({
el:'#app',
data:{
count:100
}
})
</script>
</body>
</html>
2.v-html指令
- 作用:动态地设置元素的innerHTML,可以解析字符串标签
- 语法:v-html=“表达式”
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app" v-html="mgs">
</div>
<script>
const app=new Vue({
el:'#app',
data:{
mgs:' <a href="https://www.baidu.com/">百度官网</a>'
}
})
</script>
</body>
</html>
3.v-show和v-if指令
v-show
- 作用:控制元素的显示与隐藏
- 语法:v-show=“表达式” 表达式值为 true 显示,为 false 隐藏
- 原理:切换display:none 来控制显示与隐藏
- 应用场景:适合于频繁切换显示与隐藏的场景
v-if
- 作用:控制元素的显示与隐藏(条件渲染)
- 语法:v-if=“表达式” 表达式值为 true 显示,为 false 隐藏
- 原理:基于条件判断,是否 创建 或 移除 元素节点
- 应用场景:要么显示,要么隐藏,不频繁切换的场景
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.js"></script>
<style>
.a1{
width: 200px;
height: 100px;
background-color: aqua;
}
.a2{
width: 200px;
height: 100px;
background-color: pink;
}
</style>
</head>
<body>
<div id="app">
<div class="a1" v-show="flag1">我是v-show指令盒子</div>
<div class="a2" v-if="flag2">我是v-if指令盒子</div>
</div>
<script>
const app=new Vue({
el:'#app',
data:{
flag1:true,
flag2:true
}
})
</script>
</body>
</html>
4.v-else指令和v-else-if指令
- 作用:辅助 v-if 进行判断渲染
- 语法:v-else后面不加表达式 v-if-else=“表达式”
- 注意:需要紧挨着v-if使用
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<span v-if="score >= 90">优秀</span>
<span v-else-if="score >= 80 & score<90">良好</span>
<span v-else-if="score >= 60 & score<80">合格</span>
<span v-else>不合格</span>
</div>
<script>
const app=new Vue({
el:'#app',
data:{
score:85
}
})
</script>
</body>
</html>
5.v-on指令
-
作用:注册事件 = 添加监听 + 提供处理逻辑
-
语法:
-
v-on:事件名 = “内联语句”
-
v-on:事件名 = “methods中的函数名”
函数中可以设置形参
-
-
简写:@事件名
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<button @click="count++">+</button>
<span>{{ count }}</span>
<button @click="fn">-</button>
</div>
<script>
const app=new Vue({
el:'#app',
data:{
count:100
},
methods:{
fn(){
this.count--
}
}
})
</script>
</body>
</html>
6.v-bind指令
- 作用:动态的设置html的标签属性,如 src url title
- 语法:v-bind:属性名=“表达式”
- 简写::属性名=“表达式”
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.js"></script>
<style>
div{
width: 300px;
height: 400px;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
button{
margin-left: 60px;
}
</style>
</head>
<body>
<!-- v-bind指令 动态的设置html标签的属性 -->
<div id="app">
<img v-bind:src="list[index]" v-bind:title="msg">
<!-- 另一种写法:
<img :src="imgUrl" :title="msg">
-->
<button @click="index--" v-show="index > 0">上一张</button>
<button @click="index++" v-show="index < 3">下一张</button>
</div>
<script>
const app=new Vue({
el:'#app',
data:{
index:0,
list:[
'./imges/1.png',
'./imges/2.png',
'./imges/3.png',
'./imges/4.png'
],
msg:'小鸟飞呀飞~~~'
}
})
</script>
</body>
</html>
对样式控制的增强——操作class
- 语法::class=“对象/数组”
- 对象:键就是类名,值就是布尔值,如果为true,就有这个类,如果为false,就没有这个类,适用于一个场景,类名来回切换
- 数组:数组中所有的类都添加到盒子上,本质上是一个calss列表,适用于,批量的添加或删除类
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.a{
background-color: red;
color: white;
}
li{
width: 100px;
height: 50px;
background-color: aqua;
margin-bottom: 10px;
}
</style>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<ul>
<li :class="{a: index == flag}" v-for="(item,index) in list" :key="item.id" @click="flag=index">{{ item.name }}</li>
</ul>
</div>
<script>
const app=new Vue({
el:'#app',
data:{
flag:0,
list:[
{id:1,name:'A'},
{id:1,name:'B'},
{id:1,name:'C'}
]
}
})
</script>
</body>
</html>
7.v-for指令
- 作用:基于数据循环,多次渲染整个元素 数组、对象、数字
- 遍历数组语法: v-for = “(item,index) in 数组名”
- item 每一项
- index 数组下标
- v-for中key的用法
- 作用:给列表项添加唯一的标识,便于Vue进行列表项的正确排序复用
- 语法:key属性=“唯一标识”
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<ul>
<li v-for="(item,index) in list" :key="item.id">
<span> {{ item.name}} </span>
<span>{{ item.score }}</span>
</li>
</ul>
</div>
<script>
const app=new Vue({
el:'#app',
data:{
list:[
{id:1,name:'张三',score:80},
{id:2,name:'李思',score:85},
{id:3,name:'王五',score:75},
]
}
})
</script>
</body>
</html>
8.v-model指令
- 作用:给 表单元素 使用,双向数据绑定, 可以快速 获取 或 设置 表单元素内容
- 数据变化 视图自动更新
- 视图变化 数据自动更新
- 语法:v-model=”变量“
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
账号:<input type="text" v-model="username">
<br>
密码:<input type="password" v-model="password">
<br>
<button @click="login">登录</button>
<button @click="reset">重置</button>
</div>
<script>
const app=new Vue({
el:'#app',
data:{
username:'',
password:''
},
methods:{
login(){
console.log(this.username,this.password)
},
reset(){
this.username='',
this.password=''
}
}
})
</script>
</body>
</html>
2.计算属性
作用:基于现有的数据,计算出来的新属性。依赖的数据变化,自动重新计算
语法:
- 声明在computed配置项中,一个计算属性对应一个函数
- 使用起来和普通属性一样 {{ 计算属性名 }}
计算属性就是将一段 求值的代码 进行封装
语法格式:
computed:{
计算属性名(){
基于现有的数据,编写求值逻辑
return 结果
}
}
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<table>
<tr v-for="(item,index) in list" :key="item.id">
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
<td>{{ item.price }}</td>
</tr>
</table>
<p>统计:{{ totilprice }} 元</p>
</div>
<script>
const app=new Vue({
el:'#app',
data:{
list:[
{id:1,name:'篮球',price:30},
{id:2,name:'乒乓球',price:15},
{id:3,name:'羽毛球',price:20},
{id:4,name:'足球',price:25}
]
},
computed:{
totilprice(){
// 利用 reduce 函数对数组里的 price 进行求和
let count = this.list.reduce((sum,item) => sum+item.price,0)
return count;
}
}
})
</script>
</body>
</html>
计算属性的完整语法格式:
- 计算属性默认的简写,只能读取,访问,不能 修改
- 如果需要修改,需要写计算属性的完整写法
语法格式:
computed:{
计算属性名:{
get(){
计算逻辑
return 结果
},
set(){
修改逻辑
}
}
}
3.watch语法
作用:监视数据变化,执行一些 业务逻辑 或 异步操作
语法:
-
简单写法,简单类型数据,直接监视
-
完整写法,添加额外的配置项
4.生命周期
- 创建阶段
- before Create
- created :可以发送初始化渲染请求
- 挂载阶段
- before Mount
- mounted:可以操作dom
- 更新阶段
- before Update
- updated
- 销毁阶段
- before Destroy
- destroyed
3.工程化开发模式
1.基本环境的搭建
1.安装node.js
node.js 官网地址:Node.js (nodejs.org)
2.配置Vue脚手架
用cmd命令运行
- 全局安装:yarn global add @Vue/cli 或者 npm i @Vue/cli -g
- 查看Vue版本:vue - - version
- 创建项目架子:vue create 项目名称 (项目名不能用中文)
- 启动项目:yarn serve 或者 npm run serve
2.组件化开发
1.相关概念
-
组件化:一个页面可以拆分为一个个组件,每个组件有着自己独立的 结构 样式 行为
- 好处:便于维护,利于复用,提高开发效率
- 组件分类:普通组件 根组件
-
根组件:整个应用最上层的组件,包裹所有普通的小组件(App.vue)
-
组件组成:
<template> //结构 </template> <script> //行为 export default { } </script> <style> //样式 </style>
根组件的结构: 根组件 div盒子中放的是组件,而不是标签
<template>
<div id="app">
<!-- 头部组件 -->
<DiyiHead></DiyiHead>
<!-- 主体组件 -->
<DiyiMain></DiyiMain>
<!-- 底部组件 -->
<DiyiFooter></DiyiFooter>
<DiyiFooter></DiyiFooter>
</div>
</template>
2.普通组件的局部注册
**作用范围:**只能在注册的组件内使用
步骤:
-
在components文件夹下创建 .vue文件
-
在使用的组件内导入并注册
<script> //导入需要注册的组件 //import 组件对象 from '.vue文件的路径'; import DiyiFooter from './components/DiyiFooter.vue'; import DiyiHead from './components/DiyiHead.vue'; import DiyiMain from './components/DiyiMain.vue'; export default { components:{ //局部注册 //组件名:组件对象 DiyiHead:DiyiHead, DiyiMain: DiyiMain, DiyiFooter:DiyiFooter } } </script>
-
使用:当成html标签使用 <组件名></组件名>
3.普通组件的全局注册
**作用范围:**所有组件都能使用
步骤:
-
在components文件夹下创建 .vue文件
-
在main.js中进行全局注册
import Vue from 'vue' import App from './App.vue' //导入 import DiyiQj from './components/DiyiQj' Vue.config.productionTip = false //Vue.component('组件名',组件对象) //进行全局注册,在所有组件范围内都能直接使用 Vue.component('DiyiQj',DiyiQj) //.$mount('#app) 就相当于 el:'#app' new Vue({ render: h => h(App), }).$mount('#app')
-
使用:当成标签使用
4.scoped样式冲突和data函数
样式冲突:
- 默认情况:写在组件中的样式会全局生效
- 全局样式:默认组件中的样式会作用于全局
- 局部样式:可以给组件加上scoped属性,可以让样式只作用于当前组件
代码:
<style scoped>
</style>
data函数:
-
一个组件的data项必须是一个函数,保证每个组件实例,维护独立的一份数据对象
-
代码:
<script> export default { //data 必须是一个函数 ,保证每个组件实例,维护独立性 data(){ return { count:100 } } } </script>
3.组件通信
1.组件通信的作用
- 组件通信就是指组件与组件之间的数据传递
- 组件的数据是独立的,无法直接访问其他组件的数据
- 想要使用其他组件的数据必须通过组件通信
2.“父子”通信
-
父组件通过props将数据传递给子组件
- 在父组件内 , 给子组件以添加属性的方式传值
<template> <div id="app"> 我是父组件 <NoeSon :shuju="Fu"></NoeSon> </div> </template>
- 在子组件内 , 通过props接收数据
- 在模版中直接使用
<template> <div id="zi">我是子组件 <p>{{ shuju }}</p> </div> </template> <script> export default { props:['shuju'] } </script>
-
子组件利用$emit通知父组件修改更新
- $emit触发事件,给父组件发送消息通知
<template> <div id="zi">我是子组件 <p>{{ shuju }}</p> <br> <button @click="dianji">点我呀</button> </div> </template> <script> export default { props:['shuju'], methods:{ dianji(){ this.$emit('change','好的,爸爸!') } } } </script>
- 父组件监听事件
<template> <div id="app"> 我是父组件 <NoeSon :shuju="Fu" @change="geibian"></NoeSon> </div> </template>
( @后面监听的事件名要与父组件中$emit中触发的事件名相同 )
- 提供处理函数,形参中获取参数
<script> export default { methods:{ geibian(newValue){ this.Fu=newValue } } </script>
-
props的详解
-
定义:给组件上 注册 一些 自定义 的属性
-
作用:给子组件传递数据
-
特点:可以传递 任意数量 任意类型 的props
-
props和data的区别
- props和data都可以给组件提供数据
- data是自己的数据可以修改,而props是别人的数据不能直接修改
- props是单向数据流
-
代码演示:
-
//在父组件内
```vue
//在子组件内
<template>
<div id="zi">
<p>姓名:{{ username }}</p>
<p>年龄:{{ age }}</p>
<p>兴趣爱好:{{ love.join("、") }}</p>
</div>
</template>
<script>
export default {
props:['username','age','love']
}
</script>
-
props的校验
-
为组件中的props指定验证要求,不符合要求,控制台就会提示错误
-
语法
- 类型校验
- 非空校验
- 默认值
- 自定义校验
-
代码
一般写法:
<script> export default { props:{ 校验的属性名:类型 } } </script>
完整写法:
<script> export default { props:{ 校验的属性名:{ type:类型,// required:true,//是否必填 default:默认值, validator(value){ //自定义校验逻辑 return 是否通过校验 } } } } </script>
-
3.非父子通信
event bus 事件总线
- 创建一个都能访问到的事件总线(空的Vue实例) 首先在src下创建一个utils文件夹,然后在文件夹中创建一个EventBus.js文件,内容如下:
import Vue from 'vue'
const Bus=new Vue()
export default Bus
- 在消息接收方组件,监听Bus实例的事件
<script>
import Bus from '../utils/EventBus'
export default {
created(){
Bus.$on('FaSong',(msg) =>{
// console.log(msg)
this.title=msg
})
},
data(){
return {
title:''
}
}
}
</script>
- 在消息发送方组件,触发Bus实例的事件
<template>
<div id="zi">
<span>我是组件1</span>
<br>
<button @click="Fn">发送消息</button>
</div>
</template>
<script>
import Bus from '@/utils/EventBus';
export default {
methods:{
Fn(){
Bus.$emit('FaSong','hello word')
}
}
}
</script>
- 注意:监听的事件名应和触发的事件名保持一致,且消息的传递可以是一对多的关系
provide 和 inject
- 父组件provide提供数据
<script>
import NoeSon1 from './components/NoeSon1.vue';
import NoeSon2 from './components/NoeSon2.vue';
export default {
components:{
NoeSon1,
NoeSon2
},
data(){
return {
username:'张三',//简单类型(非响应式)
users:{//复杂类型
age:18,
sex:'男'
}
}
},
provide(){
return{
username:this.username,
users:this.users
}
}
}
- 子组件/孙组件 inject 取值
<script>
export default {
inject:['username','users']
}
</script>
4.子组件与父组件的数据绑定
v-model的原理
- 原理:本质上是value属性和input事件的合写
- 作用:实现数据的双向绑定
<template>
<div id="app">
<input type="text" v-model="msg1">
<br>
<input type="text" :value="msg2" @input="msg2=$event.target.value">
</div>
</template>
<script>
export default {
data(){
return{
msg1:'',
msg2:''
}
}
}
</script>
<style>
</style>
- 注意:$event用于在模版中,获取事件的形参
- 利用v-model简化 组件数据绑定 代码
//父组件中直接使用v-model指令
<template>
<div id="app">
<OneSon v-model="msg"></OneSon>
</div>
</template>
//子组件中
<template>
<div id="zi">
<select :value="value" @change="FN">
<option value="001">武汉</option>
<option value="002">黄冈</option>
<option value="003">襄阳</option>
<option value="004">宜昌</option>
<option value="005">十堰</option>
<option value="006">荆门</option>
</select>
</div>
</template>
<script>
export default {
props:{
value:String
},
methods:{
FN(e){
this.$emit('input',e.target.value)
}
}
}
</script>
<style>
</style>
.sync修饰符
- 作用:实现子组件和父组件数据的双向绑定,简化代码
- 特点:props属性名可以自定义,非固定为value
- 场景:封装弹窗类的 基础组件
- 本质:就是 属性名 和 updata : 属性名的合写
- 语法:
//父组件
<template>
<div id="app">
<OneSon :visible.sync="msg"></OneSon>
</div>
</template>
//子组件
<script>
export default {
props:{
value:Boolean
},
methods:{
FN(e){
this.$emit('updata:visible',true)
}
}
}
</script>
4.dom元素的获取
1.ref 和 $refs
- 作用:利用ref和$refs可以用于获取 dom元素 或 组件实例
- 特点:在当前组件范围内查找(更加精确)
- 代码演示:
<template>
<div id="main" ref="mychart">
</div>
</template>
<script>
import * as echarts from 'echarts'
export default {
mounted(){
const myChart = echarts.init(this.$refs.mychart);
var option = {
title: {
text: 'ECharts 入门示例'
},
tooltip: {},
legend: {
data: ['销量']
},
xAxis: {
data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
},
yAxis: {},
series: [
{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}
]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
},
}
</script>
<style>
#main{
width: 600px;
height: 400px;
border: 3px black solid;
}
</style>
2.Vue异步更新和$nextTick
- 同步交互:指发送一个请求,需要等待返回,然后才能够发送下一个请求,有个等待过程;
- 异步交互:指发送一个请求,不需要等待返回,随时可以再发送下一个请求,即不需要等待。
- 区别:一个需要等待,一个不需要等待,在部分情况下,我们的项目开发中都会优先选择不需要等待的异步交互方式。
- Vue在更新DOM 时是异步执行的
- 想要在dom更新完成之后再执行某件事情,可以使用==$nextTick==
- 具体语法:
this.$nextTick(() => {
//业务逻辑
})
3.自定义指令
- 作用:自己定义的指令可以封装一些dom操作,扩展额外的功能
- 全局注册:可以在任意组件内使用
//main.js 文件中进行全局注册
Vue.directive('focus',{
//inserted 是生命周期钩子, 会在 指令所在元素,被插入到页面中时触发
inserted(el){
//el就是指令所绑定的元素
el.focus();
}
})
//在使用的组件中,直接加上 v-“指令名”
<template>
<div id="zi">
<h1>自定义指令</h1>
<input type="text" ref="inp" v-focus>
</div>
</template>
- 局部注册:只能在当前组件内使用
<script>
export default {
//在directives中可以设置多个指令
directives:{
//指令名:{指令配置项}
focus:{
inserted(el){
el.focus()
}
}
}
}
</script>
- 指令的值:在绑定指令时,可以通过“等号”的形式伪指令 绑定具体的参数值
<template>
<div id="zi">
<h1>自定义指令</h1>
<h2 v-color="color1">指令的值测试1</h2>
<h2 v-color="color2">指令的值测试2</h2>
</div>
</template>
<script>
export default {
//在directives中可以设置多个指令
directives:{
//指令名:{指令配置项}
color:{
inserted(el,binding){
//binding.value 就是指令的值
el.style.color=binding.value
}
}
},
data(){
return {
color1:'red',
color2:'pink'
}
}
}
</script>
<style>
</style>
5.插槽
1.默认插槽
作用:让组件内的一些 结构 支持 自定义
只有一个定制位置
使用步骤:
- 现在组件内用slot占位
- 使用组件时,传入具体标签内容插入
代码:
//先占位
<template>
<div id="zi">
<h1>提示框</h1>
<span>友情提示:</span>
<div class="cz">
<slot></slot>
</div>
</div>
</template>
//使用时传入具体的值
<template>
<div id="app">
<OneSon>
<span>不要玩手机</span>
</OneSon>
<OneSon>不要打游戏</OneSon>
</div>
</template>
2.默认值
可以在slot标签内部传入默认值
如果在组件内部没有传入具体的值,默认值生效
如果在组件内部传入了具体的值,则显示的是具体的值
代码演示:
<div class="cz">
<slot>我是默认值</slot>
</div>
3.具名插槽
- 需求:一个组件内部有多处结构,需要外部传入标签,进行定制
- 语法结构:
多个slot使用name属性区分名字
<template>
<div id="zi">
<h1>提示框</h1>
<span>友情提示:</span>
<div class="cz1">
<slot name="no1"></slot>
</div>
<div>
<slot name="no2"></slot>
</div>
</div>
</template>
template配合 v-slot:插槽名字 来分发对应标签
v-slot:插槽名字 可以简写为 #插槽名
<template>
<div id="app">
<OneSon>
<template v-slot:no1>
我是传入值1
</template>
<template v-slot:no2>
我是传入值2
</template>
</OneSon>
</div>
</template>
4.作用域插槽
作用:定义slot插槽 的同时,是可以传值的,给插槽上可以绑定数据,将来使用组件时可以用
应用场景:封装表格组件
使用步骤:
- 给slot标签,以添加属性的方式传值
- 所有添加的属性,都会被收集到一个对象中
- 在template中,通过 #插槽名=“obj”接收,默认插槽名为default
6.路由
1.路由模块封装
路由的基本使用:
- 下载Vuerouter模版到当前工程,版本3.6.5
yarn add vue-router@3.6.5
- 引入
- 安装注册
- 创建路由对象
- 注入,将路由对象注入到new Vue实例中,建立关联
- 创建需要的组件,并放在views文件夹下,配置路由规则
//在src下创建router文件夹
//在router文件夹中创建index.js文件
import OneSon from '@/views/OneSon'
import TwoSon from '@/views/TwoSon'
import ThreeSon from '@/views/ThreeSon'
import VueRouter from 'vue-router'
import Vue from 'vue'
Vue.use(VueRouter)
const router =new VueRouter({
routes:[
{path:'/one', component: OneSon},
{path:'/two', component: TwoSon},
{path:'/three', component: ThreeSon},
]
})
//导出路由对象
export default router
//main.js 文件中
//将路由对象注入到Vue实例中
import Vue from 'vue'
import App from './App.vue'
import router from './router/index.js'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
router
}).$mount('#app')
- 配置导航,配置路由出口(路径匹配的组件显示的位置)
<template>
<div id="app">
<div id="biao">
<router-link to="one">我的</router-link>
<router-link to="two">我的喜欢</router-link>
<router-link to="three">我的收藏</router-link>
</div>
<div id="xia">
//路由出口
<router-view></router-view>
</div>
</div>
</template>
2.声明式导航 跳转传参
- 目的:在跳转路由时,进行传参
1.查询参数传参(多个参数)
- 语法:to=“/path?参数名=值”
<template>
<div id="app">
<div id="biao">
<router-link to="/one?key=首页">首页</router-link>
<router-link to="/two?key=购物车">购物车</router-link>
<router-link to="/three?key=我的喜欢">我的喜欢</router-link>
</div>
<div id="xia">
<router-view></router-view>
</div>
</div>
</template>
对应页面组件接收传递过来的值 :$route.query.参数名
<template>
<div>
<h1>这里是我的喜欢</h1>
<h2>输入的是:{{ $route.query.key }}</h2>
</div>
</template>
2.动态路由传参(简洁优雅)
- 设置动态路由
- 配置导航链接
- 对应页面组件接收传递过来的值
设置动态路由
path:'/path/:参数名'
配置导航链接
to="/path/参数值"
对应页面组件接收传递过来的值
$route.params.参数名
注意:动态路由参数可选符,‘/path/:参数名’,表示必须要传参数,如果不传参数,也希望匹配,可以加一个可选符 “?”
3.路由——重定向
1.重定向
- 问题:网页打开,URL默认是 / 路径,未匹配到组件时,就会出现空白
- 说明:匹配path后,强制跳转path路径
- 语法:{path:匹配路径,redirect重定向到的路径}
2.Vue路由 404
- 作用:当路径找不到匹配时,给一个提示页面
- 位置:配在路由最后
- 语法:{path:“*” (任意路径)前面不匹配就命中最后这个}
3.Vue路由——模式设置
-
问题:路由的路径看起来不自然,有#,能否切成真正的路径形式
-
hash路由(默认) 路径中有#
-
history路由(常用) 没有# (以后上线需要服务器端支持)
-
语法:
const router =new VueRouter({ routes:[ {path:'/', redirect: '/one'}, {path:'/one', component: OneSon}, {path:'/two', component: TwoSon}, { name: 'three' , path:'/three/:key?', component: ThreeSon}, ], mode:'history', // linkActiveClass:'active', // linkExactActiveClass:'exact-active' })
4.编程式导航——基本跳转
1.path路径跳转(简易方便)
this.$router.push({
// path:'路由路径'
path:'/one'
})
- name 命名路由跳转(适合与path 路径长的场景)
//首先给路由设置名字
{ name: 'three' , path:'/three/:key?', component: ThreeSon},
//然后跳转
this.$router.push({
// name:'路由名'
name:'three'
})
3.路由传参
- path路径跳转传参
//1.查询参数传参
this.$router.push({
path:'路由路劲',
query:{
参数名1:'参数值1',
参数名2:'参数值2',
}
接收:$route.query.参数名
//2.动态路由传参
this.$router.push({
path:'/路径/参数值',
})
接收:$route.params.参数名 (动态路由传参需要配置路由)
2.name路径传参
this.$router.push({
name:'路由名',
query:{
参数名1:'参数值1',
参数名2:'参数值2',
/* params:{
参数名1:'参数值1',
参数名2:'参数值2',*/
}
接收:用什么传参就用什么接收,用query传参就用,$route.query.参数名接收
用params传参就用,$route.params.参数名接收
5.组件缓存
原因:路由跳转后。组件被销毁了、返回回来组件又被重构了,所以数据重新被加载了
解决:利用Keep-alive 将组件缓存下来
优点:减少加载时间以及性能消耗,提升用户体验性
代码:
<div id="xia">
<keep-alive>
<router-view></router-view>
</keep-alive>
</div>
7.vue cli自定义创建项目
1.创建项目
1.创建项目
PS D:\ProgrammingLanguage\vscode\HTml\vue\demo> vue create moble
2.选择自定义
Vue CLI v5.0.8
? Please pick a preset:
Default ([Vue 3] babel, eslint)
Default ([Vue 2] babel, eslint)
> Manually select features//自定义
3.添加项目需要那些特性:Babel / Router / CSS Pre-processors / Linter / Formatte
? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection, and
<enter> to proceed)
(*) Babel
( ) TypeScript
( ) Progressive Web App (PWA) Support
(*) Router
( ) Vuex
>(*) CSS Pre-processors
(*) Linter / Formatter
( ) Unit Testing
( ) E2E Testing
4.选择Vue的版本:vue2
? Choose a version of Vue.js that you want to start the project with
3.x
> 2.x
5.是否使用路由的history模式:no
? Use history mode for router? (Requires proper server setup for index fallback in production) No
6.选择一个css的预处理器:Less
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default):
Sass/SCSS (with dart-sass)
> Less
Stylus
7.选择采用哪一套 ESLint规范: ESLint + Standard config 无符号规范(标准化)
? Pick a linter / formatter config:
ESLint with error prevention only
ESLint + Airbnb config
> ESLint + Standard config
ESLint + Prettier
8.你需要什么时候校验: Lint on save 保存时校验
? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection, and <enter> to
proceed)
>(*) Lint on save
( ) Lint and fix on commit (requires Git)
9.你想要将配置文件放在哪里? In dedicated config files 放在单独的配置文件中
? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys)
> In dedicated config files
In package.json
10.是否需要保存?不保存
? Save this as a preset for future projects? (y/N) n
最后整个的步骤:
Vue CLI v5.0.8
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Router, CSS Pre-processors, Linter
? Choose a version of Vue.js that you want to start the project with 2.x
? Use history mode for router? (Requires proper server setup for index fallback in production) No
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Less
? Pick a linter / formatter config: Standard
? Pick additional lint features: Lint on save
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? No
2. ESLint 代码规范
其中一小部分规则:
- 字符串使用单引号
- 无分号
- 关键字后面加空格
- 函数名后加空格
- 坚持使用 === 放弃使用 ==
代码规范说明:https://standardjs.com/rules-zhcn.html
查找错误:进入上面网页 Ctrl + F 直接搜索错误原因
8.vuex
1.vuex概述
- 是什么:vuex是一个插件,可以帮助我们管理Vue通用的数据(多组件共享的 数据)
- 应用场景:
- 某个状态 在很多个组件 来使用(个人信息)
- 多个组件 共同维护 一份数据(购物车)
- 优势:
- 共同维护一一份数据,数据集中化管理
- 响应式变化
- 操纵简洁(vuex提供了一些辅助函数)
2.创建一个空仓库
- 安装vuex
yarn add vuex@3
- 在src文件夹下,新建store文件夹,在store文件夹下新建index.js文件,专门存放vuex
- 创建仓库
// 这里面就是存放vuex的相关的核心代码
import Vue from 'vue'
import Vuex from 'vuex'
// 插件安装
Vue.use(Vuex)
// 创建仓库
const store = new Vuex.Store()
// 导出给main.js使用
export default store
- 在main.js 中导入挂载
import Vue from 'vue'
import App from './App.vue'
import store from '@/store/index'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
store
}).$mount('#app')
3.访问vuex的数据
1.提供数据
state提供唯一的 公共数据源,所有共享的数据都要统一放在store中的state中存储
在state对象中可以添加我们需要共享的数据
const store = new Vuex.Store({
state: {
count: 100
}
})
2.使用数据
通过store直接访问
获取store:
- this.$store
- import 导入 store
在模版中:
{{ $store.state.xxx }}
组件逻辑中:
this.$store.state.xxx
js模块中:
store.state.xxx
通过辅助函数(化简)
mapState是辅助函数,帮助我们把store中的数据 自动 映射到组件的计算属性中
- 导入mapState : import { mapState } from ‘vuex’
- 数组方式引入state
- 展开运算符映射
<script>
import { mapState } from 'vuex'
export default {
computed: {
...mapState(['count'])
}
}
</script>
4.mutations的基本使用
作用:来修改state中的数据(state中的数据的修改只能通过mutations)
语法:
const store = new Vuex.Store({
state: {
count: 100
},
// 通过mutations可以提供 修改数据的方法
mutations: {
add (state, n) {
state.count += n
}
}
})
在mutations中提供修改数据的方法
方法中的第一个参数为state
在组件中只需要调用mutations中的方法就可以修改state中的数据
this.$store.commit('add', 5)
mutations中方法的参数只能有一个,如果需要多个参数可以包装成一个对象
this.$store.commit('add', {
count: 10,
title: 'hello word!'
})
5.辅助函数mapMutations
作用:把位于mutations中的方法提取出来,映射到组件中methods中
语法:
<script>
import { mapMutations } from 'vuex'
export default {
name: 'SonTwo',
methods: {
...mapMutations(['add']),
jia () {
this.add(5)//调用
}
}
}
</script>
6.action
作用:用于处理异步操作
说明:mutations必须是同步的(便于监测数据变化,记录调试)
语法:
const store = new Vuex.Store({
state: {
count: 100
},
// 通过mutations可以提供 修改数据的方法
mutations: {
add (state, n) {
state.count += n
}
},
actions: {
change (context, n) {
setTimeout(() => {
context.commit('add', n)
}, 2000)//模拟异步
}
}
})
mapActions辅助函数
作用:mapActions把位于action中的方法提取出来,映射到组件methods 中
语法:
<script>
import { mapActions } from 'vuex'
export default {
name: 'SonOne',
methods: {
...mapActions(['change']),
cn () {
this.change(10)
}
}
}
</script>
getters
作用:类似于计算属性
语法:
getters: {
//1.getters函数中的第一个参数必须是state
//getters函数必须有返回值
fn (state) {
return state.list.filter(item => item > 5)
}
}
7.modules模块
1.模块的创建
在store文件夹下新建modules文件夹,在modules文件夹下新建user.js文件
// user模块
const state = {
userInfo: {
username: '',
age: 18
},
score: 80
}
const mutations = {}
const actions = {}
const getters = {}
// 导出挂载
export default {
namespaced: true,
state,
mutations,
actions,
getters
}
在index.js中导入使用
导入
import uesr from './modules/uesr'
modules: {
uesr
}
2.模块中数据的使用
State中的数据
直接通过模块名访问
语法:
<p>{{ $store.state.uesr.userInfo.username }}</p>
通过mapState映射
-
默认根级别的映射
就是将先子模块当做根模块的一个属性,然后用子模块这个属性拿到里面的值
//导入
import { mapState } from 'vuex'
//映射
computed: {
...mapState(['uesr'])
}
//使用
<p>{{ uesr.userInfo.age }}</p>
-
子模块的映射
需要开启命令空间
语法:
//首先,在子模块中开启命令空间
export default {
namespaced: true, // 开启命令空间
state,
mutations,
actions,
getters
}
//映射
computed: {
...mapState('uesr', ['score'])
}
//使用
<p>{{ score }}</p>
Getters的访问
直接通过模块名访问
$store.getters['模块名/xxx']
通过mapGetters映射
- 默认根级别的映射
mapGetters(['xxx'])
- 子模块的映射 需要开启命名空间
mapGetters('模块名',['xxx'])
mutation的调用语法
直接通过store调用 $store.commit(‘模块名/xxx’,额外参数)
通过mapMutations映射
- 默认根级别的映射
mapMutations(['xxx'])
- 子模块的映射 需要开启命名空间
mapMutations('模块名',['xxx'])
4.小结
项目打包
将多个文件压缩成一个文件
打包命令:
yarn build
结果:根目录会自动创建一个dist文件夹,dist文件夹中的文件就是打包后的文件,只需要放在服务器中即可
配置:默认情况下,需要放在服务器根目录打开,如果希望双击打开,需要配置publicPath配成相对路径
//在vue.config.js中加上 publicPath: './',
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
publicPath: './',
transpileDependencies: true
})