# vueStudy **Repository Path**: Xbaiss/vue-study ## Basic Information - **Project Name**: vueStudy - **Description**: 学习,复杂 vue - **Primary Language**: JavaScript - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-12-29 - **Last Updated**: 2021-02-22 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Vue.js 组件 注意: 所有的 Vue 组件同时也都是 Vue 的实例,所以可接受相同的选项对象 (除了一些根级特有的选项) 并提供相同的生命周期钩子。 https://www.cnblogs.com/moqiutao/p/8328931.html ## 自定义组件 三个 API:prop、event、slot :view/assembly/index.vue 一个再复杂的组件,都是由三部分组成的:prop、event、slot,它们构成了 Vue.js 组件的 API。如果你开发的是一个通用组件,那一定要事先设计好这三部分,因为组件一旦发布,后面再修改 API 就很困难了,使用者都是希望不断新增功能,修复 bug,而不是经常变更接口。 1. 属性prop:最好是对象的写好 这个是组件间传参 注意: 组件里定义的 props,都是单向数据流,也就是只能通过父级修改,组件自己不能修改 props 的值,只能修改定义在 data 里的数据,非要修改,也是通过后面介绍的自定义事件通知父级,由父级来修改。 2. 插槽 slot: 按钮 试试 ## 自定义事件 event 俩种方式: A.自定义的事件 @on-click 通过 $emit,就可以触发自定义的事件 on-click ,在父级通过 @on-click 来监听 在父组件: B.原生事件 区分原生事件和自定义事件 :不写 .native 修饰符,@click 就是自定义事件 click,而非原生事件 click,但在组件内只触发了 on-click 事件,而不是 click,所以直接写 @click 会监听不到。 在父组件:> ## 创建组件的方法 vue 在API中只有Vue.component和Vue.extend提供组件的创建。 ### Vue.component创建 Vue自定义组件 #### Vue.component(name,comp) 基本使用 Vue.component(组件名称, 组建的配置项) Vue.component(name,comp) 来注册全局组件; 组件的全局注册必须注意是在实例化对象之前完成。 Vue.component("mytest", { template:'
  • {{name}}
  • ', props:['name'] }) new Vue({ //... }) #### 组件创建原理: Vue.component( 组件名称, Vue.extend()) 创建vue组件主要使用了Vue.extend( options )函数; #### 组件的命名 一个单词命名时首字母大写,注意不要和原生h5标签重名eg:header、footer等 多个单词时,用小写,中间用 - 作为连接符,eg:header-title 不能使用大驼峰命名 eg:Header-Title,会被解析成header-title #### 异步组件【https://cn.vuejs.org/v2/guide/components-dynamic-async.html#%E5%BC%82%E6%AD%A5%E7%BB%84%E4%BB%B6】 ### Vue.extend 用法:使用基础 Vue 构造器,创建一个“子类”(Vue.extend(someClass)看成Vue的子类)。参数是一个包含组件选项的对象。 描述:Vue.extend返回的是一个“扩展实例构造器”,也就是预设了部分选项的Vue的实例构造器,它常常服务于Vue.component用来生成组件,可以简单理解为当在模板中遇到该组件作为标签的自定义元素时,会自动调用“扩展实例构造器”来生产组件实例,并挂在到自定义元素上 需要手动挂载,可以挂载到自定义元素上,元素的标识可以是id,也可以是class如: vue 页面:
    main.js: // 创建构造器 var Profile = Vue.extend({ template: '

    {{firstName}} {{lastName}} aka {{alias}}

    ', data: function () { return { firstName: 'Walter', lastName: 'White', alias: 'Heisenberg' } } }) // 创建 Profile 实例,并挂载到一个元素上。 new Profile().$mount('#mount-point') 结果如下:

    Walter White aka Heisenberg

    上面又用到了实例方法vm.$mount(), 注意:extend创建的是一个组件构造器,而不是一个具体的组件实例。所以他不能直接在new Vue中这样使用: new Vue({components: fuck})。最终还是要通过Vue.components注册才可以使用的。 查看案例:component/extend-mount ### vm.$mount( [elementOrSelector] )使用说明 参数: {Element | string} [elementOrSelector] {boolean} [hydrating] 返回值:vm - 实例自身 用法: 如果 Vue 实例在实例化时没有收到 el 选项,则它处于“未挂载”状态,没有关联的 DOM 元素。可以使用 vm.$mount() 手动地挂载一个未挂载的实例。 如果没有提供 elementOrSelector 参数,模板将被渲染为文档之外的的元素,并且你必须使用原生 DOM API 把它插入文档中。 这个方法返回实例自身,因而可以链式调用其它实例方法。 var MyComponent = Vue.extend({ template: '
    Hello!
    ' }) // 创建并挂载到 #app (会替换 #app) new MyComponent().$mount('#app') // 同上 new MyComponent({ el: '#app' }) // 或者,在文档之外渲染并且随后挂载 var component = new MyComponent().$mount() document.getElementById('app').appendChild(component.$el) ### 组件使用 ### 全局组件 第一种方式: 1. main.js // 注册 Vue.component('my-component', { template: '
    A custom component!
    ' }) var vm = new Vue({ el: '#example', data: { } }) 2.vue使用
    第二种:或者 Vue.extend 1. main.js // 注册 var MyComponent = Vue.extend({ template: '
    A custom component!
    ' }); // 注册 Vue.component('my-component', MyComponent); var vm = new Vue({ el: '#example', data: { } }) ### 局部组件 你不必把每个组件都注册到全局。你可以通过某个 Vue 实例/组件的实例选项 components 注册仅在其作用域中可用的组件: 第一种方式: var Child = { template: '
    A custom component!
    ' } new Vue({ // ... components: { // 将只在父组件模板中可用 'my-component': Child } }) 这种封装也适用于其它可注册的 Vue 功能,比如指令 第二种方式:? vue 页面:
    // 创建构造器 var Profile = Vue.extend({ template: `

    {{firstName}} {{lastName}} aka {{alias}}

    `, data: function () { return { firstName: 'Walter', lastName: 'White', alias: 'Heisenberg' } } }) // 创建 Profile 实例,并挂载到一个元素上。 new Profile({ propsData: { todoData: [ { id: 0, text: '蔬菜' }, { id: 1, text: '奶酪' }, { id: 2, text: '随便其它什么人吃的东西' } ] } }).$mount('#mount-point') ### Vue.extend、Vue.component与new Vue 关系 分别是:vue构造、vue组件、vue实例 https://blog.csdn.net/zeping891103/article/details/78133622?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-6.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-6.control ## 组件化与模块化的不同:     模块化:是从代码逻辑的角度进行分析,方便代码分层开发,保证每个功能模块的只能单一       组件化:是从UI界面的角度进行划分,前端的组件化,方便UI组件的重用。 # vue 内置组件 component 的用法 [内置组件 component 也就是 动态组件] ## 材料 1. 官网: component:https://cn.vuejs.org/v2/api/#component 动态组件: https://cn.vuejs.org/v2/guide/components.html#%E5%8A%A8%E6%80%81%E7%BB%84%E4%BB%B6 2. 博文:https://blog.csdn.net/weixin_42333548/article/details/80532919?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.control ## 案例 注册(tab标签:邮箱注册,手机注册):https://www.jb51.net/article/137236.htm https://codesandbox.io/s/github/vuejs/vuejs.org/tree/master/src/v2/examples/vue-20-dynamic-components ## component is 内置组件切换 component组件(单独拿出一个组件来专门进行切换使用) 使用is来绑定你的组件:如下面的about,list等引入的组件名 使用 is attribute 来切换不同的组件 tab 标签 component/componets ## 动态组件 缓存内容【https://cn.vuejs.org/v2/guide/components-dynamic-async.html】 当在这些组件之间切换的时候,你有时会想保持这些组件的状态,以避免反复重渲染导致的性能问题。 如tab标签案例 你会注意到,如果你 在about 里 填写input 内容,切换到 list 标签,然后再切换回 about 标签,是不会继续展示你之前填写的about的内容。这是因为你每次切换新标签的时候,Vue 都创建了一个新的 currentTabComponent实例。 我们希望可以缓存下来。为了解决这个问题,我们可以用一个 元素将其动态组件包裹起来。 # 自定义指令 除了核心功能默认内置的指令 ( v-model 和 v-show ),Vue 也允许注册自定义指令。注意,在 Vue2.0 中,代码复用和抽象的主要形式是组件。然而,有的情况下,你仍然需要对普通 DOM 元素进行底层操 作,这时候就会用到自定义指令。 范例:输入框获取焦点 Vue.directive('focus', { inserted(el) { el.focus() } }) 使用,cource-add 范例:按钮权限控制 const role = 'user' Vue.directive('permission', { inserted(el) { if (role !== 'admin') { el.parentElement.removeChild(el) } } })
    # vuex store文件 vuex-dome # mockjs ## 介绍 mock.js是模拟后端的数据,脱离后端独立开发,实现增删改查功能 安装mockjs :npm install mockjs -D 官网【http://mockjs.com/】 视频材料【https://www.bilibili.com/video/BV1rJ411u71A?from=search&seid=7985507154263444476】 材料【https://blog.csdn.net/gao_xu_520/article/details/79722821】 ## 优点 官网描述的是 1.前后端分离 2.不需要修改既有代码,就可以拦截 Ajax 请求,返回模拟的响应数据。 3.数据类型丰富 4.通过随机数据,模拟各种场景。 ## API 简单的使用:testMock.js ## 使用 ### 直接使用时 a. 在 main.js import axios from 'axios' // 全局挂载 Vue.prototype.$http = axios import '../mock/testMock.js' b.创建mock/testMock.js // 导入模拟假数据的包 import Mock, { Random } from 'mockjs' //生成随机id let id = Mock.mock('@id'); console.log('测试mock随机生成 id:',id) // 自定义一个数组--随机获取这个数组里边的值--引用Random // 创建自定义Mock函数 Random.extend({ // 自定义函数名:function 函数 fruit: function () { const arr = ['榴莲', '菠萝蜜', '椰子', '苹果', '菠萝'] return this.pick(arr) } }) // 通过Mock.mock()来模拟API接口----GET请求 Mock.mock('/api/goodslist', 'get', { status: 200, message: '获取商品列表成功', // 生成5到10条,或者直接data|5条数据 'data|5-10': [ { // mock自增函数@increment-从1开始 id: '@increment(1)', // 随机返回中文文字-显示名字 name: '@cword(2, 8)', // 随机返回一个自然数 price: '@natural(2, 10)', count: '@natural(100, 999)', // 建议使用 data字符串压缩64格式,你建议url地址请求 img: '@dataImage(78x78)' } ] }) c. 组件中使用 // 模拟异步get async getGoodsList () { const { data: res } = await this.$http.get('/api/goodslist') console.log("mock 数据:", res); }, ### 读取json 数据 json5 解决json文件,无法添加注释问题 cnpm install json5 -D main.js import axios from 'axios' // 全局挂载 Vue.prototype.$http = axios a. 创建mock/userInfo.json5 { // mock自增函数@increment-从1开始 id: '@increment(1)', // 随机返回中文文字-显示名字 name: '@cname(2, 8)', // 随机返回一个自然数 data: '@date()', description:"@paragraph()", ip:"@ip()", email:"@email()" } b. 创建mock/testJSON5.js const fs = require('fs')// fs文件读取 const path = require('path')// 文件路径 const Mock = require('mockjs') const JSON5 = require('json5')// json文件转换 /** * 读取 json 文件 * getJsonFile 定义了如何读取json文件并解析成数据对象 * @param {*} filePath 文件地址 */ function getJsonFile(filePath) { // 读取指定json文件 var json = fs.readFileSync(path.join(__dirname, filePath), 'utf-8'); // 解析并返回json 对象 return JSON5.parse(json); } module.exports = function (app) { //监听http请求 app.get('/user/userinfo', function (rep, res) { //每次响应请求时读取mock data 的json文件 // 读取json对象 var json = getJsonFile('./userInfo.json5'); //将json 传入Mock.mock方法中,生成数据,并返回 res.json(Mock.mock(json)); }) } c. 在vue.config.js module.exports = { devServer: { ///before 中间件 before: require('./mock/testJSON5.js') }, } d. 组件使用 index.vue mounted() { this.$http .get("/user/userinfo") .then(res => { console.log("组件中获取 数据:", res); }) .catch(err => { console.log("报错:", err); }); } 浏览器输入地址,访问到devServer,返回静态资源,页面中请求axios.get('url), ajax请求服务器,但是被我们配置的devServer给拦截了,然后devServer 会调用mock.js模块,产生随机数据,然后随机数据产生于json5的文件。产生的随机数据就返回给了页面 补充:可以配置环境变量 ### mock-server 服务 如果用了后端请求,尽量 不要使用mock-server.js 不然会影响到后端接口请求 ### 设置环境下的配置 .env.development 开发环境下的配置文件 .env.production 生产环境下的配置文件 .env.development 文件 # 开发环境配置 ENV_MOCKS = 'mock'、 main.js /** *您想将MockJs用于mock api *可以执行:mockXHR() *目前MockJs将用于生产环境, *请在上线前删除! */ //开发环境使用 import { mockXHR } from '../mock' if (process.env.ENV_MOCKS === 'mock') { mockXHR() console.log('ssss') } ### 增删改查 main.js import { mockXHR } from '../mock' if (process.env.ENV_MOCKS === 'mock') { mockXHR() } mock/table.js view/mockTest/index.vue 查看【https://www.yht7.com/news/124109,https://www.cnblogs.com/niejunchan/p/13022477.html】 ### jQuery中mock的使用 暂不分析 视频教程【https://www.bilibili.com/video/BV1PE411A7U6?p=10】 ## 注意问题 1. 在mock配置中使用mock造数据的时候,采用dataImage生成图片,但是编译的时候会报错:module.require is not a function,去掉dataImage就没问题 # 代码规范注意点 规范 :[前端各类规范集合](https://github.com/ecomfe/spec) ## json5 解决json文件,无法添加注释问题 cnpm install json5 -D ## 使用对象代替 if 及 switch 在很多情况下,我们经常会遇到循环判断执行赋值操作的场景,一般我们都会使用 if 及 switch 的条件判断,如果符合则执行赋值,不符合则进入下个判断,比如: let name = 'lisi'; let age = 18; if (name === 'zhangsan') { age = 21; } else if (name === 'lisi') { age = 18; } else if (name === 'wangwu') { age = 12; } // 或者 switch(name) { case 'zhangsan': age = 21; break case 'lisi': age = 18; break case 'wangwu': age = 12; break } 这样的写法不仅冗余,而且代码执行效率不高,我们可以使用对象的形式简写: let name = 'lisi'; let obj = { zhangsan: 21, lisi: 18, wangwu: 12 }; let age = obj[name] || 18; ## 使用 Array.from 快速生成数组 一般我们生成一个有规律的数组会使用循环插入的方法,比如使用时间选择插件时,我们可能需要将小时数存放在数组中: let hours = []; for (let i = 0; i < 24; i++) { hours.push(i + '时'); } 如果使用 Array.from 我们可以简写为: let hours = Array.from({ length: 24 }, (value, index) => index + '时'); ## 使用 computed 代替 watch 很多时候页面会出现 watch 的滥用而导致一系列问题的产生,而通常更好的办法是使用 computed 属性,首先需要区别它们有什么区别: watch:当监测的属性变化时会自动执行对应的回调函数 computed:计算的属性只有在它的相关依赖发生改变时才会重新求值 其实它们在功能上还是有所区别的,但是有时候可以实现同样的效果,而 computed 会更胜一筹,比如: 上方我们通过对比可以看到,在处理多数据联动的情况下,使用 computed 会更加合理一点。 computed 监测的是依赖值,依赖值不变的情况下其会直接读取缓存进行复用,变化的情况下才会重新计算;而 watch 监测的是属性值, 只要属性值发生变化,其都会触发执行回调函数来执行一系列操作。 ## 统一管理缓存变量 在项目中或多或少会使用浏览器缓存,比如 sessionStorage 和 localStorage,当一个项目中存在很多这样的缓存存取情况的时候就会变得难以维护和管理,因为其就像全局变量一样散落在项目的各个地方,这时候我们应该将这些变量统一管理起来,放到一个或多个文件中去,比如: /* types.js */ export const USER_NAME = 'userName'; export const TOKEN = 'token'; 在需要存取的时候,直接引用: import { USER_NAME, TOKEN } from '../types.js' sessionStorage[USER_NAME] = '张三'; localStorage[TOKEN] = 'xxx'; 使用这种方法的好处在于一旦我们需要修改变量名,直接修改管理文件中的值即可,无需修改使用它的页面,同时这也可以避免命名冲突等问题的出现,这类似于 vuex 中 mutations 变量的管理。 ## 使用 setTimeout 代替 setInterval 一般情况下我们在项目里不建议使用 setInterval,因为其会存在代码的执行间隔比预期小以及 “丢帧” 的现象,原因在于其本身的实现逻辑。很多人会认为 setInterval 中第二个时间参数的作用是经过该毫秒数执行回调方法,其实不然,其真正的作用是经过该毫秒数将回调方法放置到队列中去,但是如果队列中存在正在执行的方法,其会等待之前的方法完毕再执行,如果存在还未执行的代码实例,其不会插入到队列中去,也就产生了 “丢帧”。 而 setTimeout 并不会出现这样的现象,因为每一次调用都会产生了一个新定时器,同时在前一个定时器代码执行完之前,不会向队列插入新的定时器代码。 // 该定时器实际会在 3s 后立即触发下一次回调 setInterval(() => { // 执行完这里的代码需要 2s }, 1000); // 使用 setTimeout 改写,4秒后触发下一次回调 let doSometing = () => { // 执行完这里的代码需要 2s setTimeout(doSometing, 1000); } doSometing(); ## 不要使用 for in 循环来遍历数组 大家应该都知道 for in 循环是用于遍历对象的,但它可以用来遍历数组吗?答案是可以的,因为数组在某种意义上也是对象,但是如果用其遍历数组会存在一些隐患:其会遍历数组原型链上的属性。 let arr = [1, 2]; for (let key in arr) { console.log(arr[key]); // 会正常打印 1, 2 } // 但是如果在 Array 原型链上添加一个方法 Array.prototype.test = function() {}; for (let key in arr) { console.log(arr[key]); // 此时会打印 1, 2, ƒ () {} } 因为我们不能保证项目代码中不会对数组原型链进行操作,也不能保证引入的第三方库不对其进行操作,所以不要使用 for in 循环来遍历数组。 # 学会编写可复用性模块 ## 减少重复的代码 通过将 data.obj.items 的值赋值给变量 values 来实现了复用,此时修改 items 为 lists 的话我们只需修改一处地方即可,不管是维护成本还是代码可读性上,复用的优势都显而易见。 let person = []; for (let i = 0; i < data.obj.items.length; i++) { person.push({ name: data.obj.items[i].name, age: data.obj.items[i].age }); } 改成: let person = []; let values = data.obj.items; for (let i = 0; i < values.length; i++) { person.push({ name: values[i].name, age: values[i].age }); } ## 封装成一个函数 除了使用变量的赋值缓存使用来解决数据的重复读取外,我们在开发过程中重复性更多的也许是功能点的重复,比如:
    {{ str1.slice(1).toUpperCase() }}
    {{ str2.slice(1).toUpperCase() }}
    上述代码的重复功能点在于截取输入框中第二个字符开始到最后的值并把它们转化成大写字母,像这样很简单的操作虽然重复使用也不会出现太大的问题,但是如果是代码量较多的操作呢?重复书写相同功能的代码是一种不经过大脑思考的行为,我们需要对其进行优化,这里我们可以把功能点封装成一个函数: export default { methods: { sliceUpperCase(val) { return val.slice(1).toUpperCase() } } } 如此我们只要在用到该方法的地方调用即可,将值传入其中并返回新值。当然像在双花括号插值和 v-bind 表达式中重复的功能点我们可以封装成过滤器比较合适: // 单文件组件注册过滤器 filters: { sliceUpperCase(val) { return val.slice(1).toUpperCase() } } // 全局注册过滤器 Vue.filter('sliceUpperCase', function (val) { return val.slice(1).toUpperCase() }) 然后在 html 中使用“管道”符进行过滤:
    {{ str1 | toUpperCase }}
    {{ str2 | toUpperCase }}
    ## 封装成一个插件 [Vue 插件编写与实战](https://mp.weixin.qq.com/s/Aqgh7Dkialhm9v8U0wBuqg) Vue 提供给了我们一个 install 方法来编写插件,使用该方法中的第一个 Vue 构造器参数可以为项目添加全局方法、资源、选项等 /* toast.js */ import ToastComponent from './toast.vue' // 引入组件 let $vm export default { install(Vue, options) { // 判断实例是否存在 if (!$vm) { const ToastPlugin = Vue.extend(ToastComponent); // 创建一个“扩展实例构造器” // 创建 $vm 实例 $vm = new ToastPlugin({ el: document.createElement('div') // 声明挂载元素 }); document.body.appendChild($vm.$el); // 把 toast 组件的 DOM 添加到 body 里 } // 给 toast 设置自定义文案和时间 let toast = (text, duration) => { $vm.text = text; $vm.duration = duration; // 在指定 duration 之后让 toast 消失 setTimeout(() => { $vm.isShow = false; }, $vm.duration); } // 判断 Vue.$toast 是否存在 if (!Vue.$toast) { Vue.$toast = toast; } Vue.prototype.$toast = Vue.$toast; // 全局添加 $toast 事件 } } 成功编写完插件的 JS 脚本后,我们在入口文件中需要通过 Vue.use() 来注册一下该插件: import Toast from '@/widgets/toast/toast.js' Vue.use(Toast); // 注册 Toast 最后我们在需要调用它的地方直接传入配置项使用即可,比如: this.$toast('Hello World', 2000); ## 数据驱动 做数据是改变了,但是页面并没有因此重新渲染,这是为什么呢? 由于 Vue 检测不到数组变动,因此页面便无法重绘。同样 Vue 也不能检测对象属性的添加或删除,需要使用 Vue.set(object, key, value) 方法来实现。 // 设置数组值 setPuzzle(index, num) { let curNum = this.puzzles[index] this.$set(this.puzzles, index + num, curNum) this.$set(this.puzzles, index, '') }, # Vue API 盲点解析 # vue cli 模式和环境变量 官网【https://cli.vuejs.org/zh/guide/mode-and-env.html】 根据不同的环境 设置不同的变量 比如 开发环境配置 创建 .env.development 文件 就可以在里面定义变量 然后在js 里面直接获取process.env.XX # 滤器(filter)的使用 https://blog.csdn.net/badmoonc/article/details/81485803
    {{ userInfo.sex | formatDate }}
    import Formatter from "@/utils/initialData"; filters: { ...Formatter }, const formatter = { // 性别1、男 2、女 9、未说明性别 sex: (val) => { let result = ""; switch (val) { case 1: result = "男"; break; case 2: result = "女"; break; case 9: result = "未知"; break; } return result; } } export default formatter 例如: 过滤器filter :view/filter/index.vue # 静态请求及underscore JS使用 view/localData/index.vue # 登录拦截 axios:[](https://github.com/superman66/vue-axios-github) ## 拦截器 1. 创建axios实例 const instance = axios.create({ timeout: 1000 * 12 }); 2. 设置post请求头 instance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'; 3.http request 拦截器 /** * 请求拦截器 * 每次请求前,如果存在token则在请求头中携带token */ instance.interceptors.request.use( config => { // 登录流程控制中,根据本地是否存在token判断用户的登录情况 // 但是即使token存在,也有可能token是过期的,所以在每次的请求头中携带token // 后台根据携带的token判断用户的登录情况,并返回给我们对应的状态码 // 而后我们可以在响应拦截器中,根据状态码进行一些统一的操作。 const token = store.state.token || localStorage.getItem('token'); token && (config.headers.Authorization = token); return config; }, error => Promise.error(error) ) 4.http response 拦截器 instance.interceptors.response.use( // 请求成功 res => res.status === 200 ? Promise.resolve(res) : Promise.reject(res), // 请求失败 error => { const { response } = error; if (response) { // 请求已发出,但是不在2xx的范围 errorHandle(response.status, response.data.message); return Promise.reject(response); } else { // 处理断网的情况 // eg:请求超时或断网时,更新state的network状态 // network状态在app.vue中控制着一个全局的断网提示组件的显示隐藏 // 关于断网组件中的刷新重新获取数据,会在断网组件中说明 // store.commit('changeNetwork', false); } } ); /** * 跳转登录页 * 携带当前页面路由,以期在登录页面完成登录后返回当前页面 */ const toLogin = () => { router.replace({ path: '/login', query: { redirect: router.currentRoute.fullPath } }); } /** * 请求失败后的错误统一处理 * @param {Number} status 请求失败的状态码 */ const errorHandle = (status, other) => { // 状态码判断 switch (status) { // 401: 未登录状态,跳转登录页 case 401: toLogin(); break; // 403 token过期 // 清除token并跳转登录页 case 403: tip('登录过期,请重新登录'); localStorage.removeItem('token'); // store.commit('loginSuccess', null); setTimeout(() => { toLogin(); }, 1000); break; // 404请求不存在 case 404: tip('请求的资源不存在'); break; default: console.log(other); } } ## 路由拦截 //登录拦截 router.beforeEach((to, from, next) => { console.log('state', store.state) if (store.state.userInfo || to.path === "/login") { next() } else { next({ path: "/login" }) } }) # 问题点 ## 一些 npm 包名为什么要用 @ 开头? 新的包名规则对于包的命名方式进行了一些修改,为的是更好的防御「误植」攻击,同时帮助包开发者们挑选出更加合适的包名。 如果因为你起的包名与现有的包名太相近而被阻止发布这个包,那么找到一个独一无二包名最简单方法就是使用你的作用域。你可以使用@+你的 npm 用户名加在包名前面将包划到你的 npm 账户作用域下。 如@xiaomajia/xxx-xxxx ## webpack 在 CLI 3 中的应用 https://blog.csdn.net/guozhangqiang/article/details/87197870 ## webacpk ,none ,chrome Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时, webapck 是支持node api 所以 chrome浏览器能访问的,node 也可以,webpack 也可以,webpack export default ,import 这个是es6 不是node ,所以在node ,否则是普通页面 是不能访问的, 如果要访问的必须引用babel库的 ,如 :babel-plugin-dynamic-import-node 就可以 用于引入import