视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
VueCli3构建TS项目的方法步骤
2020-11-27 22:04:21 责编:小采
文档


关闭不能cosole:

"no-console": false

tslint的函数前后空格:

"space-before-function-paren": ["error", {
 "anonymous": "always",
 "named": "always",
 "asyncArrow": "always"
}]

tslint分号的配置:

"semicolon": [true, "never"]
eslint配置

在项目中是使用eslint

规范空格:'indent': 0

路由改造

引入组件方式

dev使用require:

/**
 * 开发环境载入文件
 * @param fileName 文件路径,不包括文件名
 * @param viewPath 视图目录
 */

module.exports = (file: string, viewPath: string = 'views') => {
 return require(`@/${viewPath}/${file}.vue`).default
}

prod使用import:

/**
 * 生产环境载入文件
 * @param fileName 文件路径,不包括文件名
 * @param viewPath 视图目录
 */

module.exports = (file: string, viewPath: string = 'views') => {
 return import(`@/${viewPath}/${file}.vue`)
}
路由处理逻辑

改文件在app.vue中引入:

/**
 * 路由处理逻辑
 */

import router from '@/router/index'


router.beforeEach((to: any, from: any, next: any) => {
 if (to.name === 'login') {
 next({name: 'home/index'})
 } else {
 next()
 }
})
router-view

一个<router-view />对应一个路由层级,下一级<router-view /> 对应路由表中的children路由

router 中的meta

配置每个路由的单独特性

title, keepalive, main, desc, icon, hidden, auth

keep-alive

vue中的<keep-alive></keep-alive>其它生命周期不执行,只执行:activateddeactivated

axios改造

npm i axios --save

typings

在根目录创建typings文件,里面定义, 全局注入。

需要哪些接口引入哪些接口文件。

创建ajax.d.ts文件,并声明后台返回的数据格式。

declare namespace Ajax {
 // axios return data
 export interface AxiosResponse {
 data: AjaxResponse
 }

 // reqposne interface
 export interface AjaxResponse {
 id: number
 error: null | object
 jsonrpc: string
 result: any
 }
}

使用,在src根目录下都可以使用。

let res: Ajax.AxiosResponse = {
 data: {"id": "1533610056745", "result": 1, "error": null, "jsonrpc": "2.0"}
}
cookies的处理

安装cookies的包:npm i js-cookie --save

增加项目前缀,封装cookie, localStorage, sessionStorage 增删改等方法

/**
 * 操作 cookie, localStorage, sessionStorage 封装
 */
import Cookies from 'js-cookie'
import { isNil } from 'lodash'

const prefix = process.env.VUE_APP_PREFIX

/**
 * ============ Cookie ============
 */

export function getCookie (name: string): string {
 return Cookies.get(prefix + name)
}

export function setCookie (name: string, value: any, params= {}): void {
 if (isEmpty(value)) return
 Cookies.set(prefix + name, value, params)
}

export function removeCookie (name: string, params= {}): void {
 Cookies.remove(prefix + name, params)
}

/**
 * ============ localStorage ============
 */

export function setLocalStorage (name: string, value: any): void {
 if (isEmpty(value)) return
 window.localStorage.setItem(prefix + name, value)
}

export function getLocalStorage (name: string) {
 return window.localStorage.getItem(prefix + name)
}

export function removeLocalStorage (name: string) {
 window.localStorage.removeItem(prefix + name)
}

export function clearLocal () {
 window.localStorage.clear()
}

/**
 * ============ sessionStorage ============
 */

export function setSessionStorage (name: string, value: any): void {
 if (isEmpty(value)) return
 window.sessionStorage.setItem(prefix + name, value)
}

export function getSessionStorage (name: string) {
 window.sessionStorage.getItem(prefix + name)
}

export function removeSessionStorage (name: string) {
 window.sessionStorage.removeItem(prefix + name)
}

/**
 * 判断值是否为null或者undefined或者''或者'undefined'
 * @param val value
 */
function isEmpty (val: any) {
 if (isNil(val) || val === 'undefined' || val === '') {
 return true
 }
 return false
}
fetch

axios进行二次封装,增加请求前后的拦截

import axios from 'axios'

/**
 * 创建 axios 实例
 */
const service = axios.create({
 timeout: 3000
})

/**
 * req 
 */
service.interceptors.request.use((config: object): object => {
 return config
}, (error: any): object => {
 return Promise.reject(error)
})

/**
 * res 
 */
service.interceptors.response.use((response: any) => {
 const res = response.data
 if (res.error) {
 if (process.env.NODE_ENV !== 'production') {
 console.error(res)
 }
 return Promise.reject(res)
 }
 return Promise.resolve(res)
})

export default service
请求参数统一处理
/**
 * 统一参数处理
 * 请求url处理
 */

const qs = require('qs')
import { merge, isPlainObject } from 'lodash'
import { getCookie } from '@/utils/cookies'

/**
 * 接口参数拼接
 * @param opts 接口参数
 * @param opsIdParams 是否传递opsId
 * @param requestType post 还是 get 参数处理
 * @param otherParams 是否传有其它参数
 * @example
 * commonParams({
 * 'method': cmdName.login,
 * 'params': params
 * }, false, undefined, false)
 */
export function commonParams (opts: object, opsIdParams: boolean= true, requestType: string= 'post', otherParams: boolean= true): object {
 const params = {
 json: JSON.stringify(merge({
 id: new Date().getTime(),
 jsonrpc: '2.0',
 params: dealParams(opsIdParams, otherParams),
 }, opts || {})),
 }
 return requestType === 'post' ? qs.stringify(params) : params
}

/**
 * 请求接口的地址处理
 * @param urlData 请求接口
 * @param type 请求路径
 * @example url(cmdName.login)
 */
export function url (urlData: string, type: any = process.env.VUE_APP_API_PATH) {
 // @example https://example.com + agsgw/api/ + auth.agent.login
 return process.env.VUE_APP_API_URL + type + urlData
}

/**
 * params 参数的处理
 * @param opsIdParams 是否传递opsId
 * @param otherParams 是否传有其它参数
 */
function dealParams (opsIdParams: boolean, otherParams: boolean | object): object {
 let obj: any = {}
 // opsIdParams 默认传opsId
 if (opsIdParams) {
 obj.opsId = getCookie('token') || ''
 }
 // otherParams其他默认参数, 如sn
 if (otherParams === true) {
 // obj.sn = getCookie('switchSn') || ''
 } else {
 // 其他object
 if (isPlainObject(otherParams)) {
 obj = {...obj, ...otherParams}
 }
 }
 return obj
}
接口名称单独作为一个文件
/**
 * 后台接口名称
 */

const cmdName = {
 login: 'auth.agent.login'
}

export default cmdName
组合文件
/**
 * 组合请求http的请求
 */

import fetch from '@/utils/fetch'
import cmdName from './cmdName'
import { commonParams, url } from './commonParams'

export {
 fetch,
 cmdName,
 commonParams,
 url
}
导出的请求文件
import { fetch, cmdName, url, commonParams } from '@/api/common'

export function login (params: object) {
 return fetch({
 url: url(cmdName.login),
 method: 'post',
 data: commonParams({
 method: cmdName.login,
 params
 })
 })
}
使用接口方式
import * as API from '@/api/index'

API.login(params).then(res => {
})

store改造

vuex的作用:分离远程记录加载到本地存储(操作)和 检索从store 中的getter

  • 数据加载策略
  • 细节/全局构造请求
  • 导航响应
  • 权限(配合router控制权限)
  • 使用:

  • 使用module形式
  • 全局的一些操作,方法,放入store中,业务逻辑尽量少放,项目全局方法可以放入。例如:cookie, global cache
  • action(异步): api的操作, 调用方式:this.$store.dispatch(functionName, data)

    mutations(同步): dom相关操作,方法名一般使用常量,
    调用方式: this.$store.commit(mutationsName, data)

    this.$store.getters[XXX] => this.$store.getters[namespaced/XXX]
    this.$store.dispatch(XXX, {}) => this.$store.dispatch(namespaced/XXX, {})
    this.$store.commit(XXX, {}) => this.$store.commit(namespaced/XXX, {})

    组件内的Vue

    <template>
     <div>
     <div>用户名:<input type="text" v-model="username" /></div>
     <div>密码:<input type="password" v-model="passwd" /></div>
    
     <div>{{computedMsg}}</div>
     </div>
    </template>
    
    <script lang="ts">
    import { Component, Prop, Vue, Provide } from 'vue-property-decorator'
    
    // 引入组件
    @Component({
     components: {
     // input
     }
    })
    export default class Login extends Vue {
     // data
     @Provide() private username: string = ''
     @Provide() private passwd: string = ''
    
     // methods
     login (u: string, p: string) {
     }
    
     // computed
     get computedMsg () {
     return 'username: ' + this.username
     }
    
     // life cycle
     mounted () {
     }
    }
    </script>

    other

    公用组件: dateRange, pagination, icon-font, clock, proxyAutocomplete, dialog

    全局注入

    Vue.component(modal.name, modal) // dialog
    Vue.component(pagination.name, pagination) // 分页
    Vue.component(dateRange.name, dateRange) // 日期
    Vue.component(proxyAutocomplete.name, proxyAutocomplete) // 远程模糊搜索
    Vue.component(card.name, card) // el-tabs
    Vue.component(tabLoad.name, tabLoad) // el-tabs

    main.ts中引入公用组件文件夹下的useElement

    import '@/components/useElement'
    一些问题

    不能直接new

    // 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.
    // 不能直接new一个函数,通过重新as一个变量,或者new其原型的constructor 都可以解决
    // const encodePsw = new Encode.prototype.constructor().encodePsw(this.passwd)
    const E = Encode as any
    const encodePsw = new E().encodePsw(this.passwd)

    不能直接导入文件后再追加属性或方法

    import * as filters from '@/filters/index'
    
    // 全局filter
    const F = filters as any
    Object.keys(filters).forEach(item => {
     Vue.filter(item, F[item])
    })
    declare var Chart: any;
    
    @Component({
     selector: 'my-component',
     templateUrl: './my-component.component.html',
     styleUrls: ['./my-component.component.scss']
    })
    
    export class MyComponent {
     //you can use Chart now and compiler wont complain
     private color = Chart.color;
    }

    vue.config.js

    const path = require('path')
    const debug = process.env.NODE_ENV !== 'production'
    const VueConf = require('./src/assets/js/libs/vue_config_class')
    const vueConf = new VueConf(process.argv)
    
    module.exports = {
     baseUrl: vueConf.baseUrl, // 根域上下文目录
     outputDir: 'dist', // 构建
    输出目录 assetsDir: 'assets', // 静态资源目录 (js, css, img, fonts) pages: vueConf.pages, lintOnSave: true, // 是否开启eslint保存检测,有效值:ture | false | 'error' runtimeCompiler: true, // 运行时版本是否需要编译 transpileDependencies: [], // 默认babel-loader忽略mode_modules,这里可增加例外的依赖包名 productionSourceMap: true, // 是否在构建生产包时生成 sourceMap 文件,false将提高构建速度 configureWebpack: config => { // webpack配置,值位对象时会合并配置,为方法时会改写配置 if (debug) { // 开发环境配置 config.devtool = 'cheap-module-eval-source-map' } else { // 生产环境配置 } Object.assign(config, { // 开发生产共同配置 resolve: { alias: { '@': path.resolve(__dirname, './src'), '@c': path.resolve(__dirname, './src/components'), 'vue$': 'vue/dist/vue.esm.js' } } }) }, chainWebpack: config => { // webpack链接API,用于生成和修改webapck配置,https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md if (debug) { // 本地开发配置 } else { // 生产开发配置 } }, css: { // 配置高于chainWebpack中关于css loader的配置 modules: true, // 是否开启支持‘foo.module.css'样式 extract: true, // 是否使用css分离插件 ExtractTextPlugin,采用样式文件载入,不采用<style>方式内联至html文件中 sourceMap: false, // 是否在构建样式地图,false将提高构建速度 loaderOptions: { // css预设器配置项 css: { localIdentName: '[name]-[hash]', camelCase: 'only' }, stylus: {} } }, parallel: require('os').cpus().length > 1, // 构建时开启多进程处理babel编译 pluginOptions: { // 第三方插件配置 }, pwa: { // 单页插件相关配置 https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa }, devServer: { open: true, host: '0.0.0.0', port: 8080, https: false, hotOnly: false, proxy: { '/api': { target: '<url>', ws: true, changOrigin: true } }, before: app => {} } }

    下载本文
    显示全文
    专题