VueCli3构建TS项目的方法步骤
使用vue-cli3
构建typescript
项目
import 和 require
require
: 以同步的方式检索其他模块的导出 (开发)
import
: 动态地加载模块 (生产)
相关文档:
vue-cli3
vue create project-name
, 生成目录结构:
│ .browserslistrc │ .gitignore │ .postcssrc.js // postcss 配置 │ babel.config.js │ cypress.json │ package.json // 依赖 │ readme.md │ tsconfig.json // ts 配置 │ eslint.json // eslint 配置 │ yarn.lock │ ├─public // 静态页面 │ │ favicon.ico │ │ index.html │ │ manifest.json │ │ robots.txt │ │ │ └─img │ └─icons │ ├─src // 主目录 │ │ app.vue // 页面主入口 │ │ main.ts // 脚本主入口 │ │ registerserviceworker.ts // pwa 配置 │ │ router.ts // 路由 │ │ shims-tsx.d.ts // 相关 tsx 模块注入 │ │ shims-vue.d.ts // vue 模块注入 │ │ store.ts // vuex 配置 │ │ │ ├─assets // 静态资源 │ │ logo.png │ │ │ ├─components // 组件 │ │ helloworld.vue │ │ │ └─views // 页面 │ about.vue │ home.vue │ └─tests // 测试用例 ├─e2e │ ├─plugins │ │ index.js │ ├─specs │ │ test.js │ └─support │ commands.js │ index.js └─unit helloworld.spec.ts
改造后的目录结构:
│ .browserslistrc │ .gitignore │ .postcssrc.js // postcss 配置 │ babel.config.js │ cypress.json │ package.json // 依赖 │ readme.md // 项目 readme │ tsconfig.json // ts 配置 │ eslint.json // eslint 配置 │ vue.config.js // webpack 配置 │ yarn.lock │ ├─public // 静态页面 │ │ favicon.ico │ │ index.html │ │ manifest.json │ │ robots.txt │ │ │ └─img │ └─icons ├─scripts // 相关脚本配置 ├─src // 主目录 │ │ app.vue // 页面主入口 │ │ main.ts // 脚本主入口 │ │ registerserviceworker.ts // pwa 配置 │ │ shims-tsx.d.ts │ │ shims-vue.d.ts │ │ │ ├─assets // 静态资源 │ │ logo.png │ │ │ ├─components │ │ helloworld.vue │ │ │ ├─filters // 过滤 │ ├─lib // 全局插件 │ ├─router // 路由配置 │ │ index.ts │ │ │ ├─scss // 样式 │ ├─store // vuex 配置 │ │ index.ts │ │ │ ├─typings // 全局注入 │ ├─utils // 工具方法(axios封装,全局方法等) │ └─views // 页面 │ about.vue │ home.vue │ └─tests // 测试用例 ├─e2e │ ├─plugins │ │ index.js │ │ │ ├─specs │ │ test.js │ │ │ └─support │ commands.js │ index.js │ └─unit helloworld.spec.ts
eslint 和 tslint
tslint配置
关闭不能cosole
:
"no-console": false
"space-before-function-paren": ["error", { "anonymous": "always", "named": "always", "asyncarrow": "always" }]
的配置:
"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>
其它生命周期不执行,只执行:activated
和 deactivated
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 => {} } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。