VueCli3构建TS项目的方法步骤


Posted in Javascript onNovember 07, 2018

使用vue-cli3构建Typescript项目

import 和 require

require: 以同步的方式检索其他模块的导出 (开发)

import: 动态地加载模块 (生产)

相关文档:module methods

vue-cli3

vue create project-name

vue-cli3配置, 生成目录结构:

│ .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

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

VueCli3构建TS项目的方法步骤

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

VueCli3构建TS项目的方法步骤

  • 数据加载策略
  • 细节/全局构造请求
  • 导航响应
  • 权限(配合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

VueCli3构建TS项目的方法步骤

全局注入

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 => {}
 }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
js类后台管理菜单类-MenuSwitch
Sep 12 Javascript
jquery ui dialog ie8出现滚动条的解决方法
Dec 06 Javascript
SOSO地图API使用(一)在地图上画圆实现思路与代码
Jan 15 Javascript
Javascript单元测试框架QUnitjs详细介绍
May 08 Javascript
Jquery实现仿腾讯微博发表广播
Nov 17 Javascript
js判断当前页面在移动设备还是在PC端中打开
Jan 06 Javascript
js利用for in循环获取 一个对象的所有属性以及值的实例
Mar 30 Javascript
es7学习教程之Decorators(修饰器)详解
Jul 21 Javascript
JQuery和html+css实现带小圆点和左右按钮的轮播图实例
Jul 22 jQuery
详解Vue取消eslint语法限制
Aug 04 Javascript
element中的$confirm的使用
Apr 26 Javascript
在Angular中实现一个级联效果的下拉框的示例代码
May 20 Javascript
vue调试工具vue-devtools安装及使用方法
Nov 07 #Javascript
vue+webpack中配置ESLint
Nov 07 #Javascript
利用jqgrid实现上移下移单元格功能
Nov 07 #Javascript
React 源码中的依赖注入方法
Nov 07 #Javascript
监听angularJs列表数据是否渲染完毕的方法示例
Nov 07 #Javascript
详解react native页面间传递数据的几种方式
Nov 07 #Javascript
微信小程序使用npm支持踩坑
Nov 07 #Javascript
You might like
PHP生成静态页
2006/11/25 PHP
php expects parameter 1 to be resource, array given 错误
2011/03/23 PHP
PHP连接Access数据库的方法小结
2013/06/20 PHP
PHP根据图片色界在不同位置加水印的方法
2015/07/01 PHP
php性能分析之php-fpm慢执行日志slow log用法浅析
2016/10/17 PHP
php获取excel文件数据
2017/04/21 PHP
快速解决FusionCharts联动的中文乱码问题
2013/12/04 Javascript
js对象继承之原型链继承实例
2015/01/10 Javascript
jQuery实现友好的轮播图片特效
2015/01/12 Javascript
JS使用ajax方法获取指定url的head信息中指定字段值的方法
2015/03/24 Javascript
window.onload使用指南
2015/09/13 Javascript
js 点击a标签 获取a的自定义属性方法
2016/11/21 Javascript
hovertree插件实现二级树形菜单(简单实用)
2016/12/28 Javascript
浅谈通过JS拦截 pushState和replaceState事件
2017/07/21 Javascript
浅谈关于angularJs中使用$.ajax的注意点
2017/08/12 Javascript
JSON创建键值对(key是中文或者数字)方式详解
2017/08/24 Javascript
解决layui表格的表头不滚动的问题
2019/09/04 Javascript
Python同时向控制台和文件输出日志logging的方法
2015/05/26 Python
Python中Iterator迭代器的使用杂谈
2016/06/20 Python
Python中装饰器兼容加括号和不加括号的写法详解
2017/07/05 Python
Python使用getpass库读取密码的示例
2017/10/10 Python
Python 实现引用其他.py文件中的类和类的方法
2018/04/29 Python
Python动态语言与鸭子类型详解
2019/07/01 Python
Python字符编码转码之GBK,UTF8互转
2020/02/09 Python
Python基于当前时间批量创建文件
2020/05/07 Python
Tensorflow加载Vgg预训练模型操作
2020/05/26 Python
python怎么判断素数
2020/07/01 Python
简单了解python关键字global nonlocal区别
2020/09/21 Python
python3.9实现pyinstaller打包python文件成exe
2020/12/13 Python
Pure Collection美国官网:来自英国羊绒专家的奢华羊绒
2017/11/19 全球购物
为什么要有struct关键字
2012/05/08 面试题
恶意软件的定义
2014/11/12 面试题
网络专业学生个人的自我评价
2013/12/16 职场文书
关于护士节的演讲稿
2014/05/26 职场文书
第28个世界无烟日活动总结
2015/02/10 职场文书
导游词之青岛太清宫
2019/12/13 职场文书