# VueBasic2
**Repository Path**: pyds/vue-basic2
## Basic Information
- **Project Name**: VueBasic2
- **Description**: Vue基础练习笔记2
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 0
- **Created**: 2022-02-19
- **Last Updated**: 2022-06-21
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 笔记
## 脚手架文件结构:
```
├─ node_modules
├─ public
│ ├─ favicon.ico: 页签图标
│ └─ index.html: 主页面
├─ src
│ ├─ assets: 存放静态资源
│ │ └─ logo.png
│ ├─ components: 存放组件
│ │ └─ HelloWorld.vue
│ ├─ App.vue: 汇总所有组件
│ └─ main.js: 入口文件
├─ .gitignore: git版本管制忽略的配置
├─ babel.config.js: babel的配置文件
├─ package-lock.json: 包版本控制文件
├─ package.json: 应用包配置文件
└─ README.md: 应用描述文件
```
## 关于不同版本的Vue:
- vue.js与vue.runtime.xxx.js的区别:
(1)vue.js是完整版的Vue,包含:核心功能+模板解析器
(2)vue.runtime.xxx.js是运行版的Vue,只包含:核心功能,没有模板解析器
- 因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用render函数接收到的createElement函数去指定具体内容
## vue.config.js配置文件
>使用 `vue inspect > output.js` 可以查看到Vue脚手架的默认配置
>使用 `vue.config.js` 可以对脚手架进行个性化定制,详情见:https://cli.vuejs.org/zh/ 中配置参考
## ref属性
1. 被用来给元素或子组件注册引用信息(id的替代者)
2. 应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc)
3. 使用方式:
打标识:`
...
` 或 ``
获取:`this.$refs.xxx`
## 配置项props
功能:让组件接收外部传过来的数据
1. 传递数据:
> ``
2. 接收数据:
>第一种方式(只接收): `props: ["names", "age"]`
>第二种方式(限制类型):
>```
>props: {names: String, age: Number}
>```
>第三种方式(限制类型、限制必要性、指定默认值):
>```
>props: {
> name: {
> type: String, // 类型
> required: true // 必要性
> },
> age: {
> type: Number,
> default: 99 // 默认值
> }
>}
>```
备注:props是只读的,Vue底层会检测你对props的修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。
## mixin(混入)
功能: 可以把多个组件共用的配置提取成一个混入对象
```
使用方式:
第一步: 定义混合,例如:
{
data(){...},
methods: {...},
...
}
第二步: 使用混合,例如:
(1)全局混入: Vue.mixin(xxx)
(2)局部混入: mixins: [xxx]
```
## 插件
功能:用于增强Vue
本质:包含install方法的一个对象,install的另一个参数是Vue,第二个以后的参数是插件使用者传递的数据。
```
定义插件:
对象.install = function(Vue, options){
// 1.添加全局过滤器
Vue.filter(...)
// 2.添加全局指令
Vue.directive(...)
// 3.配置全局混入(合)
Vue.mixin(...)
// 4.添加实例方法
Vue.prototype.$myMethod = function(){...}
Vue.prototype.$myProperty = xxx
}
使用插件:
Vue.use()
```
## scoped样式
作用:让样式在局部生效,防止冲突
写法:`
```
- 具名插槽:
```html
父组件中:
html结构1
html结构2
子组件中:
插槽默认内容...
插槽默认内容...
```
- 作用域插槽:
- 理解:数据在组件自身,但根据数据生成的结构需要组件使用者来决定。(games数据在Category组件中,但使用数据所遍历出来的结构由App组件决定)
- 具体编码:
```html
父组件中:
{{ scopeData.msg }}
- {{ g }}
{{ g }}
子组件中:
插槽默认内容...
```
## Vuex
#### 1.概念
在Vue中实现集中式状态(数据)管理的一个Vue插件,对Vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信方式,且适用于任意组件间通信。
#### 2.何时使用
多个组件需要共享数据时。
#### 3.搭建Vuex环境
- 创建 `src/store/index.js` 文件:
```js
// 该文件用于创建Vuex中最为核心的store
// 引入Vue
import Vue from "vue"
// 引入Vuex
import Vuex from "vuex"
// 应用Vuex插件
Vue.use(Vuex)
// 准备actions——用于响应组件中的动作
const actions = {}
// 准备mutations——用于操作数据(state)
const mutations = {}
// 准备state——用于存储数据
const state = {}
// 创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state
})
```
- 在 `src/main.js` 中创建vm时传入 `store` 配置项
```js
......
// 引入store
import store from "./store"
......
// 创建vm
new Vue({
el: "#app",
render: h => h(App),
store,
......
})
```
#### 4.基本使用
- 初始化数据`state`、配置`actions`、`mutations`,操作文件 `store.js`:
```js
// 该文件用于创建Vuex中最为核心的store
// 引入Vue
import Vue from "vue"
// 引入Vuex
import Vuex from "vuex"
// 应用Vuex插件
Vue.use(Vuex)
// 准备actions——用于响应组件中的动作
const actions = {
// 响应组件中的加的动作
jia(context, value) {
// console.log("actions中的jia被调用了", context, value)
context.commit("JIA", value)
},
}
const mutations = {
// 执行加
JIA(state, value) {
// console.log("mutations中的JIA被调用了", state, value)
state.sum += value
},
}
// 初始化数据
const state = {
sum: 0 // 当前的和
}
// 创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state
})
```
- 组件中读取vuex中的数据:`$store.state.sum`
- 组件中修改vuex中的数据:`$store.dispatch('actions中的方法名', 数据)` 或 `$store.commit('mutations中的方法名', 数据)`
- 备注: 若没有网络请求或其它业务逻辑,组件中也可以越过actions,即不写`dispatch`,直接写`commit`
#### 5.getters的使用
- 概念: 当state中的数据需要经过加工后再使用,可以使用getters加工。
- 在`store.js`中追加`getters`配置
```js
......
const getters = {
bigSum(state) {
return state.sum * 10
}
}
// 创建并暴露store
export default new Vuex.Store({
......
getters
})
```
- 组件中读取数据:`$store.getters.bigSum`
#### 6.四个map方法的使用
- **mapState方法:** 用于帮助我们映射`state`中的数据为计算属性
```js
computed: {
// 借助mapState生成计算属性,从state中读取数据 (对象写法)
...mapState({sum: 'sum', school: 'school', subject: 'subject'}),
// 借助mapState生成计算属性,从state中读取数据 (数组写法)
...mapState(['sum', 'school', 'subject']),
}
```
- **mapGetters方法:** 用于帮助我们映射`getters`中的数据为计算属性
```js
computed: {
// 借助mapGetters生成计算属性,从getters中读取数据 (对象写法)
...mapGetters({bigSum: 'bigSum'}),
// 借助mapGetters生成计算属性,从getters中读取数据 (数组写法)
...mapGetters(['bigSum']),
}
```
- **mapActions方法:** 用于帮助我们生成与actions对话的方法,即:包含 `$store.dispatch(xxx)` 的函数
```js
methods: {
// 借助mapActions生成,incrementOdd、incrementWait (对象形式)
...mapActions({incrementOdd: "jiaOdd", incrementWait: "jiaWait"})
// 借助mapActions生成,incrementOdd、incrementWait (数组形式)
...mapActions(["jiaOdd", "jiaWait"])
}
```
- **mapMutations方法:** 用于帮助我们生成与mutations对话的方法,即:包含 $store.commit(xxx) 的函数
```js
methods: {
// 借助mapMutations生成,increment、decrement (对象形式)
...mapActions({increment: "JIA", decrement: "JIAN"})
// 借助mapMutations生成,"JIA"、"JIAN" (数组形式)
...mapActions(["JIA", "JIAN"])
}
```
>备注:mapActions与mapMutations使用时,若需要传递参数,需要在模板中绑定事件时传递好参数,否则参数是事件对象。
#### 7.模块化+命名空间
- 目的:让代码更好维护,让多种数据分类更加明确
- 修改`store/index.js`
```js
......
const countAbout = {
namespaced: true, // 开启命名空间
actions: { ... },
mutations: { ... },
state: { x: 1 },
getters: {
bigSum(state) {
return state.sum * 10
}
}
}
const personAbout = {
namespaced: true, // 开启命名空间
actions: { ... },
mutations: { ... },
state: { ... }
}
const store = new Vuex.Store({
modules: {
countAbout,
personAbout
}
})
```
- 开启命名空间后,组件中读取state数据:
```js
// 方式一:自己直接读取
this.$store.state.countAbout.sum
// 方式二:借助mapState读取
...mapState('countAbout', ['sum', 'school', 'subject'])
```
- 开启命名空间后,组件中读取getters数据:
```js
// 方式一:自己直接读取
this.$store.getters['personAbout/firstPersonName']
// 方式二:借助mapGetters读取
...mapGetters('countAbout', ['bigSum'])
```
- 开启命名空间后,组件调用dispatch:
```js
// 方式一:自己直接dispatch
this.$store.dispatch('personAbout/addPersonLi', person)
// 方式二:借助mapActions读取
...mapActions('countAbout', {increment: 'jiaOdd', incrementWait: 'jiaWait'})
```
- 开启命名空间后,组件调用commit:
```js
// 方式一:自己直接commit
this.$store.commit('personAbout/ADD_PERSON', person)
// 方式二:借助mapMutations读取
...mapMutations('countAbout', {increment: 'JIA', decrement: 'JIAN'})
```
## 路由
- 理解:一个路由(route)就是一组映射关系(key-value),多个路由需要路由器(router)进行管理。
- 前端路由:key是路径,value是组件。
#### 1.基本使用
- 安装vue-router,命令:`npm i vue-router`
- 应用插件:`Vue.use(VueRouter)`
- `src/router/index.js`编写router配置项
```js
// 引入VueRouter
import VueRouter from 'vue-router'
// 引入路由组件
import About from '../components/About'
import Home from '../components/Home'
// 创建router实例对象,去管理一组一组的路由规则
const router = new VueRouter({
routes: [
{
path: '/about',
component: About
},
{
path: '/home',
component: Home
},
]
})
// 暴露router
export default router
```
- 实现切换(active-class可配置高亮样式)
```html
About
```
- 指定展示位置
```html
```
#### 2.几个注意点
- 路由组件通常存放在`pages`文件夹,一般组件通常存放在`components`文件夹。
- 通过切换,‘隐藏’了的路由组件,默认是被销毁掉的,需要的时候再去挂载。
- 每个组件都有自己的`$route`属性,里面存储着自己的路由信息。
- 整个应用只有一个router,可以通过组件的`$router`属性获取到。
#### 3.多级(嵌套)路由
- 配置路由规则,使用children配置项:
```js
routes: [
{
path: '/about',
component: About,
},
{
path: '/home',
component: Home,
children: [ // 通过children配置子路由
{
path: 'news', // 此处一定不要写: /news
component: News
},
{
path: 'message', // 此处一定不要写: /message
component: Message
},
]
}
]
```
- 跳转(要写完整路径):
```html
News
```
#### 4.路由的query参数
- 传递参数
```html
{{ m.title }}
{{ m.title }}
```
- 接收参数
```
$route.query.id
$route.query.title
```
#### 5.命名路由
- 作用:可简化路由跳转
- 如何使用:
- 给路由命名
```js
{
path: '/demo',
component: Demo,
children: [
{
path: '/test',
component: Test,
children: [
{
name: 'hello', // 给路由命名
path: '/welcome',
component: Hello,
}
]
}
]
}
```
- 简化跳转
```html
跳转
跳转
跳转
```
#### 6.路由的params参数
- 配置路由,声明接收params参数
```js
{
path: '/home',
component: Home,
children: [
{
path: 'news',
component: News
},
{
path: 'message',
component: Message,
children: [
{
name: 'xiangqing',
path: '/detail/:id/:title', // 使用占位符声明接收的params参数
component: Detail
}
]
},
]
}
```
- 传递参数
```html
跳转
跳转
```
> 特别注意:路由携带params参数时,若使用to的对象写法,则不能使用path配置项,必须使用name配置!
- 接收参数
```js
$route.params.id
$route.params.title
```
#### 7.路由的props配置
- 作用:让路由组件更方便的收到参数
```js
{
name: 'xiangqing',
path: 'detail/:id/:title',
component: Detail,
// 第一种写法,props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件。
// props: {a: 666, b: '你好'}
// 第二种写法,props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给Detail组件。
// props: true,
// 第三种写法,props值为函数,该函数返回的对象中每组key-value都会通过props传给Detail组件
props(route) {
return {
id: route.query.id,
title: route.query.title,
}
}
}
```
#### 8.``的replace属性
- 作用:控制路由跳转时操作浏览器历史记录的模式。
- 浏览器的历史记录有两种写入方式:分别为push和replace,push是追加历史记录,replace是替换当前记录,路由跳转时默认为push。
- 如何开启replace模式:
```html
News
```
#### 9.编程式路由导航
- 作用:不借助 `` 实现路由跳转,让路由跳转更加灵活。
- 具体编码:
```js
// $router的两个API(push和replace)
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(-2)
```
#### 10.缓存路由组件
- 作用:让不展示的路由组件保持挂载,不被销毁
- 具体编码:
```html
```
#### 11.两个新的生命周期钩子
- 作用:路由组建所独有的两个钩子,用于捕获路由组件的激活状态。
- 具体名字:
- `activated` 路由组件被激活时触发。
- `deactivated` 路由组件失活时触发。
#### 12.路由守卫
- 作用:对路由进行权限控制
- 分类:全局守卫、独享守卫、组件内守卫
- 全局守卫
```js
// 全局前置路由守卫,初始化时执行、每次路由切换前执行
router.beforeEach((to, from, next) => {
console.log("beforeEach", to, from)
if (to.meta.isAuth) { // 判断当前路由是否需要进行权限控制
if (localStorage.getItem("test-token") === "abc123") { // 权限控制的具体规则
next() // 放行
}
else {
alert("权限不足,无法查看!")
}
}
else {
next() // 放行
}
})
// 全局后置路由守卫,初始化时执行、每次路由切换后执行
router.afterEach((to, from) => {
console.log("afterEach", to, from)
if (to.meta.title) {
document.title = to.meta.title // 修改网页title
}
else {
document.title = "test"
}
})
```
- 独享路由守卫
```js
......
{
name: "xinwen",
path: "news",
component: News,
meta: {
title: "新闻",
isAuth: true
},
beforeEnter: (to, from, next) => {
if (to.meta.isAuth) { // 判断当前路由是否需要进行权限控制
if (localStorage.getItem("test-token") === "abc123") {
// document.title = to.meta.title
next()
}
else {
alert("test-token错误, 无权限查看!")
}
}
else {
// document.title = to.meta.title
next()
}
}
}
......
```
- 组件路由守卫
```js
// 进入守卫,通过路由规则,进入该组件时被调用
beforeRouteEnter(to, from, next) { ... },
// 离开守卫,通过路由规则,离开该组件时被调用
beforeRouteEnter(to, from, next) { ... },
```
#### 13.路由器的两种工作模式
- 对于一个URL来说,什么是hash值?—— URL中#及其后的内容就是hash值(eg: http://localhost:8080/#/about, hash值为`#/about`)。
- hash值不会包含在HTTP请求中,即:hash值不会带给服务器。
- hash模式:
- 地址中永远带着#号,不美观
- 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法。
- 兼容性较好。
- history模式:
- 地址干净、美观。
- 兼容性相对于hash模式较差。
- 应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题