# 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 父组件中: 子组件中: ``` - 作用域插槽: - 理解:数据在组件自身,但根据数据生成的结构需要组件使用者来决定。(games数据在Category组件中,但使用数据所遍历出来的结构由App组件决定) - 具体编码: ```html 父组件中: 子组件中: ``` ## 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的问题