写点什么

前端项目配置 ts,axios,router,vuex

用户头像
关注
发布于: 2021 年 05 月 06 日
1.使用 tslint.json,如下配置仅供参考
{    "rules": {        // TS特性        "member-access": true, // 设置成员对象的访问权限(public,private,protect)        "member-ordering": [// 设置修饰符顺序            true,            {                "order": [                     "public-static-field",                    "public-static-method",                    "protected-static-field",                    "protected-static-method",                    "private-static-field",                    "private-static-method",                    "public-instance-field",                    "protected-instance-field",                    "private-instance-field",                    "public-constructor",                    "protected-constructor",                    "private-constructor",                    "public-instance-method",                    "protected-instance-method",                    "private-instance-method"                ]            }        ],        "no-empty-interface":true,// 不允许空接口        "no-parameter-reassignment":true,// 不允许修改方法输入参数        "prefer-for-of":true,// 如果for循环中没有使用索引,建议是使用for-of
// 功能特性 "await-promise":true,// 不允许没有Promise的情况下使用await "curly":true,// if/for/do/while强制使用大括号 "forin":true,// 使用for in语句时,强制进行hasOwnProperty检查 "no-arg":true,// 不允许使用arguments.callee // "no-bitwise":true, // 不允许使用特殊运算符 &, &=, |, |=, ^, ^=, <<, <<=, >>, >>=, >>>, >>>=, ~ "no-conditional-assignment":true,// do while/for/if/while 语句中将会对例如if(a=b)进行检查 // "no-console":true,// 不允许使用console对象 "no-debugger":true,// 不允许使用debugger "no-duplicate-super":true,// 不允许super() 两次使用在构造函数中 "no-empty":true,// 函数体不允许空 "no-eval":true,// 不允许使用eval "no-for-in-array":true,// 不允许对Array使用for-in "no-invalid-template-strings":true,// 只允许在模板字符串中使用${ "no-invalid-this":true,// 不允许在class之外使用this "no-null-keyword":true,// 不允许使用null,使用undefined代替null,指代空指针对象 "no-sparse-arrays":true,// 不允许array中有空元素 "no-string-throw":true,// 不允许throw一个字符串 "no-switch-case-fall-through":true,// 不允许case段落中在没有使用breack的情况下,在新启一段case逻辑 "no-unsafe-finally":true,// 不允许在finally语句中使用return/continue/break/throw "no-unused-expression":true,// 不允许使用未使用的表达式 "no-use-before-declare":true,// 在使用前必须声明 "no-var-keyword":true,// 不允许使用var "radix":true,// parseInt时,必须输入radix精度参数 "restrict-plus-operands":true,// 不允许自动类型转换,如果已设置不允许使用关键字var该设置无效 "triple-equals":true,// 必须使用恒等号,进行等于比较 "use-isnan":true,// 只允许使用isNaN方法检查数字是否有效
// 维护性功能 "indent":[true, "spaces", 4],// 每行开始以4个空格符开始 "linebreak-style":[true,"CR/LF"],// 换行符格式 CR/LF可以通用使用在windows和osx "max-classes-per-file":[true,1],// 每个文件中可定义类的个数 "max-file-line-count":[true,500],// 定义每个文件代码行数 "max-line-length":[true,120],// 定义每行代码数 "no-default-export":true,// 禁止使用export default关键字,因为当export对象名称发生变化时,需要修改import中的对象名。https://github.com/palantir/tslint/issues/1182#issue-151780453 "no-duplicate-imports":true,// 禁止在一个文件内,多次引用同一module
// 格式 "align":[true,"parameters","arguments","statements","members","elements"],// 定义对齐风格 "array-type":[true,"array"],// 建议使用T[]方式声明一个数组对象 "class-name":true,// 类名以大驼峰格式命名 "comment-format":[true, "check-space"],// 定义注释格式 "encoding":true,// 定义编码格式默认utf-8 "import-spacing":true,// import关键字后加空格 "interface-name":[true,"always-prefix"],// interface必须以I开头 "jsdoc-format":true,// 注释基于jsdoc风格 "new-parens":true,// 调用构造函数时需要用括号 "no-consecutive-blank-lines":[true,2],// 不允许有空行 "no-trailing-whitespace": [// 不允许空格结尾 true, "ignore-comments", "ignore-jsdoc" ], "no-unnecessary-initializer":true,// 不允许没有必要的初始化 "variable-name":[true,"check-format",// 定义变量命名规则 "allow-leading-underscore", "allow-trailing-underscore", "ban-keywords"] }}
复制代码


{    "defaultSeverity": "warning",    "extends": [        "tslint:recommended"    ],    "linterOptions": {        "exclude": [            "node_modules/**",        ]    },    "rules": {        "quotemark": [            true,            "single"        ],        "indent": [            true,            "spaces",            4        ],        "interface-name": false,        "ordered-imports": false,        "object-literal-sort-keys": false,        "no-consecutive-blank-lines": false,        "no-console": [            false        ],        "only-arrow-functions": [            false        ],        "member-access": [            true,            "no-public"        ],        "no-unused-expression": [            true,            "allow-fast-null-checks",            "allow-new",            "allow-tagged-template"        ],        "arrow-parens": [            "as-needed"        ],        "max-line-length": [            true,            {                "limit": 180,                "ignore-pattern": "^import |^export {(.*?)} |import(.*?)"            }        ],        "no-empty": [            true,            "allow-empty-catch",            "allow-empty-functions"        ],        "space-before-function-paren": {            "severity": "off"        },        "eofline": false,        "no-shadowed-variable": false    }}
复制代码
2.使用 axios
  1. 接口域名放在.env 文件里 process.env.VUE_APP_BASE_URL

  2. 封装一个 axios

import axios from 'axios';import Qs from 'qs';
import { hideLoading, showLoading } from '../units/index'const instance: any = axios.create({ baseURL: process.env.VUE_APP_BASE_URL, timeout: 1000, validateStatus: function (status) { return status >= 200 && status < 300; }, transformRequest: [function (data) { // 对 data 进行任意转换处理 return Qs.stringify(data) }],});
export enum ApiRequestMethod { get = 'get', post = 'post', delete = 'delete', put = 'put',}export interface ApiRequestParam { url: string; method?: ApiRequestMethod; data?: object; params?: object; headers?: object; timeout?: number; responseType?: string; [propName: string]: any;}
// 添加请求拦截器instance.interceptors.request.use((config: any) => { let { use } = config; // 1,加载loading // 2.配置Token // 在发送请求之前做些什么 // config.headers.Authorization = Token; console.log(config); if (use.autoLoading) { showLoading(); } return config;}, (error: any) => { // 对请求错误做些什么 return Promise.reject(error);});
instance.interceptors.response.use((response: any) => { let { data, config } = response; // 对响应数据做点什么 console.log(response, 'succ'); hideLoading() // 是否请求成功 if (data.statusCode === '000000') { return Promise.resolve(response); } else { data.desc ? alert(data.desc) : config.use.autoTipError ? alert(config.use.autoTipError) : ''; return Promise.reject(response); } }, (error: any) => { // 1.关闭loading // 2.全局处理报错信息 const { response, status } = error if (response) { // 3.服务器的状态码处理(validateStatus配置相关):401 500 switch (status) { case 401: // 未登录
break;
case 403: // 拒绝访问
break; case 404: // 请求失败
break; } } else { // 是否未连接网络 if (!window.navigator.onLine) { alert('请检查网络'); } } return Promise.reject(error);});

export const apiRequest = ( params: ApiRequestParam, autoLoading: boolean = true, autoTipError: string = '', ) => { console.log(params, autoLoading, autoTipError, Qs.stringify({a:'9p掘金'})); instance.defaults.use = { autoLoading, autoTipError } return instance(params)}

复制代码


使用封装好的接口

// xx.tsimport { ApiRequestMethod, apiRequest } from '../axios';const index = (params: any) => {    return apiRequest({        params,        method: ApiRequestMethod.get,        url: '/common/weather/get15DaysWeatherByArea?apiKey=ZZGPUJJ6eaae98f6de9f6019aab2909ef47612004bf3cd0',    }, false, 'errrrrr')};
export default { index,};
// xxx.vue使用封装好的接口import {getToken} from 'xx'getToken({}).then().catch((err) =>{})
复制代码
3.使用 router
  1. 普通路由

  {    path: '/vip',    name: 'vip',    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')  },
复制代码

2.嵌套路由

  {    path: '/test',    name: 'test',    component: () => import(/* webpackChunkName: "test" */ '../views/test.vue')    children: [      {        path: '', // 第一个展示为空        name: '',        component: '',      }    ]  },      test.vue<templeat>    <p>我是test.vue组件</p>    <router-view> // 渲染子组件里面的内容</templeat>
复制代码

3.动态路由匹配

  {    path: '/vip/:id',    name: 'vip',    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')  },
// xx.vue this.$router.push({ name: 'vip', // 路由名称,唯一 params: { id: '123' } // 动态匹配id: http://localhost:8080/#/vip/123 })
复制代码

4.动态传参 query

// 带查询参数,变成 /register?plan=privatethis.$router.push({ name: 'vip', query: { plan: 'private' }})
复制代码

5.操作路由的几种方式

this.$router.push() // 入栈this.$router.replace({}) // 替换当前路由this.$router.router.go(n) // 前进后退步数,更换指针位置,与 window.history.go(n)相似
复制代码

6.路由组件传参

布尔模式:用于动态路由,模板渲染对象模式:静态的时候有用函数模式:    {      path: '/search',      component: SearchUser,      props: route => {        return {          	          // 返回参数        }			}    }
复制代码

7.导航守卫

路由守卫: 写在routes配置里面	beforeEnter:路由只独享这一个钩子,在rutes里配置;用的少
组件内的守卫: 注意:这类路由钩子是写在组件内部: beforeRouteEnter(to, from, next) 进入路由前,此时实例还没创建,无法获取到zhis beforeRouteUpdate (to, from, next) 路由更新时触发的钩子函数 beforeRouteLeave(to, from, next) 离开当前路由,此时可以用来保存数据,或数据初始化,或关闭定时器等等
全局守卫:router.beforeEach 全局前置守卫 // 这个用的多router.beforeResolve 全局解析守卫(2.5.0+) 在beforeRouteEnter调用之后调用.router.afterEach 全局后置钩子 进入路由之后 注意:不支持next(),只能写成这种形式router.afterEach((to, from) => {});
复制代码

8.路由元信息:meta:any

9.滚动行为

// 这个功能只在支持 history.pushState 的浏览器中可用  scrollBehavior (to, from, savedPosition) {    // 浏览器的前进后退才会触发    if (savedPosition) {      return savedPosition;    } else if (to.hash) { // 跳到hash的位置      return {        selector: to.hash,        behavior: 'smooth',      }    } else {      return {        x: 0,        y: 0,      }    }    // return 期望滚动到哪个的位置  }
复制代码

10.使用 vue-class-component 提供的 Component.registerHooks 来注册钩子

import Component from 'vue-class-component'
Component.registerHooks([ 'beforeRouteEnter', 'beforeRouteLeave', 'beforeRouteUpdate' // for vue-router 2.2+])
xx.vuebeforeRouteEnter(to: unknown, from: unknown, next: any) { console.log('beforeRouteEnter',to) next() // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 `this` // 因为当守卫执行前,组件实例还没被创建}
复制代码
4.使用 vuex
  1. 安装引用

import Vue from 'vue'import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({ state: { count: 0 }, getters(){ name(state){ return val; } }, mutations: { increment (state, val) { state.count++ } }, // 异步操作 actions: { name(ctx, obj){} }})
xx.vue使用辅助函数 jsimport { mapState, mapMutations, mapGetters } from 'vuex'computed: { ...mapState([ // 映射 this.count 为 store.state.count 'count' ])}methods: { ...mapMutations([name]), ...mapGetters([name]) // 类似于计算属性,组合,全局数据}
复制代码

2.命名空间

const moduleA = {	namespaced: true,  state: () => ({ ... }),  mutations: { ... },  actions: { ... },  getters: { ... }}
const moduleB = { namespaced: true, state: () => ({ ... }), mutations: { ... }, actions: { ... }}
const store = new Vuex.Store({ modules: { a: moduleA, b: moduleB }})
xx.vue使用computed: { ...mapState('some/nested/module', { a: state => state.a, b: state => state.b })},methods: { ...mapActions('some/nested/module', [ 'foo', // -> this.foo() 'bar' // -> this.bar() ])}
复制代码

3.在 ts 中使用 vuex-class

import Vue from 'vue'import Component from 'vue-class-component'import {  State,  Getter,  Action,  Mutation,  namespace} from 'vuex-class' const someModule = namespace('path/to/module') @Componentexport class MyComp extends Vue {  @State('foo') stateFoo  @State(state => state.bar) stateBar  @Getter('foo') getterFoo  @Action('foo') actionFoo  @Mutation('foo') mutationFoo  @someModule.Getter('foo') moduleGetterFoo   // If the argument is omitted, use the property name  // for each state/getter/action/mutation type  @State foo  @Getter bar  @Action baz  @Mutation qux   created () {    this.stateFoo // -> store.state.foo    this.stateBar // -> store.state.bar    this.getterFoo // -> store.getters.foo    this.actionFoo({ value: true }) // -> store.dispatch('foo', { value: true })    this.mutationFoo({ value: true }) // -> store.commit('foo', { value: true })    this.moduleGetterFoo // -> store.getters['path/to/module/foo']  }}
复制代码

发布于: 2021 年 05 月 06 日阅读数: 29
用户头像

关注

还未添加个人签名 2020.08.05 加入

还未添加个人简介

评论

发布
暂无评论
前端项目配置ts,axios,router,vuex