【知识整理】vue-cli3.0+typescript+vuex+axios+router项目搭建步骤

什么是typescript

TypeScriptJavaScript 的强类型版本。然后在编译期去掉类型和特有语法,生成纯粹的JavaScript 代码。由于最终在浏览器中运行的仍然是JavaScript ,所以TypeScript并不依赖于浏览器的支持,也并不会带来兼容性问题。

TypeScriptJavaScript的超集,这意味着他支持所有的JavaScript语法。并在此之上对JavaScript添加了一些扩展,如 class / interface / module 等。这样会大大提升代码的可阅读性。

与此同时,TypeScript也是JavaScript ES6 的超集,GoogleAngular 2.0也宣布采用 TypeScript 进行开发。这更是充分说明了这是一门面向未来并且脚踏实地的语言。

强类型语言的优势在于静态类型检查,概括来说主要包括以下几点:

  1. 静态类型检查
  2. IDE 智能提示
  3. 代码重构
  4. 可读性

静态类型检查可以避免很多不必要的错误, 不用在调试的时候才发现问题

前言

Vue CLI 是一个基于 Vue.js 进行快速开发的完整系统。有三个组件:

  1. CLI:@vue/cli 全局安装的 npm 包,提供了终端里的vue命令(如:vue create 、vue serve 、vue ui 等命令)
  2. CLI 服务:@vue/cli-service是一个开发环境依赖。构建于 webpackwebpack-dev-server 之上(提供 如:serve、build 和 inspect 命令)
  3. CLI 插件:给Vue 项目提供可选功能的 npm 包 (如: Babel/TypeScript 转译、ESLint 集成、unit和 e2e测试 等)

初始化项目

1.安装vue-cli3.0

如果你之前安装的是vue-cli2.0版本的,那么你需要先卸载2.0版本,再安装3.0版本。

// cnpm 为淘宝镜像
cnpm uninstall vue-cli -g // 卸载
cnpm install -g @vue/cli // 安装新版本
2.创建项目
vue create my-vue-cli3-ts

选择Manually select features回车
在这里插入图片描述
按照下图所示选中(空格选中)回车安装插件
在这里插入图片描述
然后一路回车,放一下配置图
在这里插入图片描述安装完以后,进入项目并启动项目

cd my-vue-cli3-ts
npm run serve

启动后显示如下:
在这里插入图片描述
代码的工作目录如下:
在这里插入图片描述

3.配置文件并改变文件结构
  • 打开根目录下的vue.config.js,如果没有就自己创建一个,放在根目录下,并添加以下内容
const path = require('path')

const resolve = dir => {
 return path.join(__dirname, dir)
}

// 线上打包路径,请根据项目实际线上情况
const BASE_URL = process.env.NODE_ENV === 'production' ? '/' : '/'

module.exports = {
 publicPath: BASE_URL,
 outputDir: 'dist', // 打包生成的生产环境构建文件的目录
 assetsDir: '', // 放置生成的静态资源路径,默认在outputDir
 indexPath: 'index.html', // 指定生成的 index.html 输入路径,默认outputDir
 pages: undefined, // 构建多页
 lintOnSave: true,// 是否在保存的时候检查
 productionSourceMap: false, // 开启 生产环境的 source map?
 chainWebpack: config => {
   // 配置路径别名
   config.resolve.alias
     .set('@', resolve('src'))
     .set('_c', resolve('src/components'))
 },
 css: {
   modules: false, // 启用 CSS modules
   extract: true, // 是否使用css分离插件
   sourceMap: false, // 开启 CSS source maps?
   loaderOptions: {} // css预设器配置项
 },
 devServer: { // 环境配置
   open: process.platform === "darwin",
   host: 'localhost',
   port: 8080, // 端口
   https: false,
   hotOnly: false,
   open: true, //配置自动启动浏览器
   proxy: {
    "/api": {
       target: '<url>',//设置你调用的接口域名和端口号 别忘了加http
       changeOrigin: true,
       pathRewrite: {
         "/api": "" // 这里理解成用‘/api’代替target里面的地址,后面组件中我们掉接口时直接用api代替 比如我要调用'http://40.00.100.100:3002/user/add',直接写‘/api/user/add’即可
       }
     }
   }, 
   // string | Object
  before: app => {}
 },
  pluginOptions: {// 第三方插件配置
       // ...
   }
}
  • 配置一下根目录下tslint.json,编码习惯还是根据团队的要求来,这里有一份参考的tslint.json配置,如下:
{
 "defaultSeverity": "warning",
 "extends": [
   "tslint:recommended"
 ],
 "linterOptions": {
   "exclude": [
     "node_modules/**"
   ]
 },
 "rules": {
   "quotemark": false, // 字符串文字需要单引号或双引号。
   "indent": false, // 使用制表符或空格强制缩进。
   "member-access": false, // 需要类成员的显式可见性声明。
   "interface-name": false, // 接口名要求大写开头
   "ordered-imports": false, // 要求将import语句按字母顺序排列并进行分组。
   "object-literal-sort-keys": false, // 检查对象文字中键的排序。
   "no-consecutive-blank-lines": false, // 不允许连续出现一个或多个空行。
   "no-shadowed-variable": false, // 不允许隐藏变量声明。
   "no-trailing-whitespace": false, // 不允许在行尾添加尾随空格。
   "semicolon": false, // 是否分号结尾
   "trailing-comma": false, // 是否强象添加逗号
   "eofline": false, // 是否末尾另起一行
   "prefer-conditional-expression": false, // for (... in ...)语句必须用if语句过滤
   "curly": true, //for if do while 要有括号
   "forin": false, //for in 必须用if进行过滤
   "import-blacklist": true, //允许使用import require导入具体的模块
   "no-arg": true, //不允许使用 argument.callee
   "no-bitwise": true, //不允许使用按位运算符
   "no-console": false, //不能使用console
   "no-construct": true, //不允许使用 String/Number/Boolean的构造函数
   "no-debugger": true, //不允许使用debugger
   "no-duplicate-super": true, //构造函数两次用super会发出警告
   "no-empty": true, //不允许空的块
   "no-eval": true, //不允许使用eval
   "no-floating-promises": false, //必须正确处理promise的返回函数
   "no-for-in-array": false, //不允许使用for in 遍历数组
   "no-implicit-dependencies": false, //不允许在项目的package.json中导入未列为依赖项的模块
   "no-inferred-empty-object-type": false, //不允许在函数和构造函数中使用{}的类型推断
   "no-invalid-template-strings": true, //警告在非模板字符中使用${
   "no-invalid-this": true, //不允许在非class中使用 this关键字
   "no-misused-new": true, //禁止定义构造函数或new class
   "no-null-keyword": false, //不允许使用null关键字
   "no-object-literal-type-assertion": false, //禁止object出现在类型断言表达式中
   "no-return-await": true, //不允许return await
   "arrow-parens": false, //箭头函数定义的参数需要括号
   "adjacent-overload-signatures": false, //  Enforces function overloads to be consecutive.
   "ban-comma-operator": true, //禁止逗号运算符。
   "no-any": false, //不需使用any类型
   "no-empty-interface": true, //禁止空接口 {}
   "no-internal-module": true, //不允许内部模块
   "no-magic-numbers": false, //不允许在变量赋值之外使用常量数值。当没有指定允许值列表时,默认允许-1,01
   "no-namespace": [true, "allpw-declarations"], //不允许使用内部modules和命名空间
   "no-non-null-assertion": true, //不允许使用!后缀操作符的非空断言。
   "no-parameter-reassignment": true, //不允许重新分配参数
   "no-reference": true, // 禁止使用/// <reference path=> 导入 ,使用import代替
   "no-unnecessary-type-assertion": false, //如果类型断言没有改变表达式的类型就发出警告
   "no-var-requires": false, //不允许使用var module = require("module"),import foo = require('foo')导入
   "prefer-for-of": true, //建议使用for(..of)
   "promise-function-async": false, //要求异步函数返回promise
   "max-classes-per-file": [true, 2], // 一个脚本最多几个申明类
   "variable-name": false,
   "prefer-const": false // 提示可以用const的地方
 }
}

顺便贴一份自己的配置

{
  "defaultSeverity": "warning",
  "extends": [
    "tslint:recommended"
  ],
  "linterOptions": {
    "exclude": [
      "node_modules/**"
    ]
  },
  "rules": {
    "quotemark": false,
    "semicolon": false,
    "indent": [true, "spaces", 4],
    "interface-name": false,
    "ordered-imports": false,
    "object-literal-sort-keys": false,
    "no-consecutive-blank-lines": false,
    "no-var-keyword": true,
    "no-var-requires": false,
    "triple-equals": true,
    "prefer-const": true,
    "no-sparse-arrays": true,
    "no-duplicate-imports": true,
    "no-mergeable-namespace": true,
    "encoding": true,
    "trailing-comma": false,
    "no-console": false,
    "no-debugger": false,
    "no-empty": false,
    "no-string-literal": false,
    "no-trailing-whitespace": false,
    "comment-format": [
      false,
      "check-space"
    ],
    "max-line-length": [
      false,
      120
    ]
  }
}
  • 改变文件结构(按照个人习惯来改变的)
    1.在./src目录下创建store文件夹,并将原来./src目录下的store.ts挪到该文件夹下,同时修改./src目录下的main.ts中的store路径为import store from './store/store'
    2.在./src目录下创建axios文件夹,并添加api.tshttp.ts
    3.在./src目录下创建util文件夹,并添加utils.ts用于存放公共的函数
4.编写demo

以View UI(即Iview)为例

npm install view-design --save
  • main.ts中引入ViewUI,如下:
import ViewUI from 'view-design';
import 'view-design/dist/styles/iview.css';
Vue.use(ViewUI);
  • ./src目录下的views文件夹下,新建一个Demo.vue文件,在components文件夹里面新建一个HelloDemo.vue文件,两个文件里面的代码如下:
// Demo.vue
<template>
  <div class="demo">
      <HelloDemo></HelloDemo>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import HelloDemo from '@/components/HelloDemo.vue';


@Component({
  components: {
    HelloDemo,
  },
})
export default class Demo extends Vue {}
</script>
// HelloDemo.vue
<template>
  <div class="hello-demo">
    <Button>Default</Button>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';


@Component({
  components: {
   
  },
})
export default class HelloDemo extends Vue {}
</script>
  • Demo.vue添加路由,在router.ts里面添加demo路由,可以不删除已有的代码,在后面添加
// router.ts
import Vue from 'vue';
import Router from 'vue-router';
import Home from './views/Home.vue';

Vue.use(Router);

export default new Router({
 mode: 'history',
 base: process.env.BASE_URL,
 routes: [
   {
     path: '/',
     name: 'home',
     component: Home,
   },
   {
     path: '/about',
     name: 'about',
     // route level code-splitting
     // this generates a separate chunk (about.[hash].js) for this route
     // which is lazy-loaded when the route is visited.
     component: () => import(/* webpackChunkName: "about" */ './views/About.vue'),
   },
   {
     path: '/demo',
     name: 'demo',
     // route level code-splitting
     // this generates a separate chunk (about.[hash].js) for this route
     // which is lazy-loaded when the route is visited.
     component: () => import(/* webpackChunkName: "about" */ './views/Demo.vue'),
   },
 ],
});
  • 最后在App.vue文件里添加一个路由跳转,实现点击Demo时,可以跳转到Demo页面
// App.vue
<template>
 <div id="app">
   <div id="nav">
     <router-link to="/">Home</router-link> |
     <router-link to="/about">About</router-link> |
     <router-link to="/demo">Demo</router-link>
   </div>
   <router-view/>
 </div>
</template>

<style lang="less">
#app {
 font-family: 'Avenir', Helvetica, Arial, sans-serif;
 -webkit-font-smoothing: antialiased;
 -moz-osx-font-smoothing: grayscale;
 text-align: center;
 color: #2c3e50;
}
#nav {
 padding: 30px;
 a {
   font-weight: bold;
   color: #2c3e50;
   &.router-link-exact-active {
     color: #42b983;
   }
 }
}
</style>
  • 启动程序
npm run serve
  • 效果如下,当点击Demo的时候,跳转到demo页面,里面的按钮是ViewUI里面的样式效果

在这里插入图片描述

5.使用vuex

vuex在ts文件中的使用主要是利用vuex-class,vuex-class可以包装vuex的写法,使代码简化

  • 安装vuex-class
    关于vuex-class介绍,可以参考vuex-class
npm install vuex-class -save
  • ./src文件夹下面的store文件夹里面新建modules文件夹,在modules文件夹里面新建demo.ts,在demo.ts里面定义变量,同时也修改一下store.ts(以模块化的形式引进来),代码如下
// demo.ts
// 公用的内容
import { Commit, Dispatch } from "vuex";
export interface State {
   name: string,
}

const state: State = {
   name: "jf",
};

const getters = {};

const mutations = {};

const actions = {
   changeName(context: { state: State }) {
       state.name = "joanna"
   }
};

export default {
 namespaced: true,
 state,
 mutations,
 actions,
 getters
};
// store.ts
import Vue from 'vue';
import Vuex from 'vuex';
import demo from '@/store/modules/demo';

Vue.use(Vuex);

export default new Vuex.Store({
  modules: {
    demo
  },
});
  • HelloDemo.vue里面调用demo.ts里面的变量和函数
// HelloDemo.vue
<template>
 <div class="hello-demo">
   <Button @click="change">change name</Button>
   <div>name: {{this.demo.name}}</div>
 </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import { State, Action } from "vuex-class";

@Component({
 components: {
  
 },
})
export default class HelloDemo extends Vue {
   @State((state) => state.demo) private demo: any;
   @Action("demo/changeName") private changeName: any; // 改变姓名
   // 改变姓名
   private change() {
       this.changeName()
   }
}
</script>
  • 实现效果
    界面如下,当在Demo页面,点击change name按钮时,name会由jf变成joanna
    在这里插入图片描述
6.使用axios
  • 安装axios
// 下载axios
npm i axios --S
  • http.ts文件里面添加如下代码,我是以ViewUI界面返回来的接口来测试,有没有调通的
// http.ts
import * as Axios from "axios";
import QS from "qs";

// let baseURL: string = "https://api.github.com/repos/iview/iview";
let baseURL: string = "https://api.github.com/repos";
const axios = Axios.default.create({
   baseURL: baseURL, // api请求的baseURL
   timeout: 0,
   withCredentials: true, // 允许跨域 cookie
   headers: {
     "X-Requested-With": "XMLHttpRequest",
     "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
   },
   maxContentLength: 2000,
   transformResponse: [
     (resdata, resheader) => {
       let data: any;
       try {
         data = JSON.parse(resdata);
       } catch (e) {
         data = JSON.parse(resdata);
       }
       return data;
     }
   ]
 });
 axios.interceptors.response.use(
   (response: any) => {
     return response;
   },
   error => {
     return Promise.reject(error);
   }
 );
 // get
 export const get = (req: any) => {
   return axios.get(req.url, { params: req.data });
 };

 // post
 export const post = (req: any) => {
   if (req.url.indexOf('saveGroupPersonRule') > 0) {
     return axios({ method: 'post', url: `/${req.url}`, data: req.data });
   } else {
     return axios({ method: 'post', url: `/${req.url}`, data: QS.stringify(req.data) });
   }
 };
 
 // patch
 export const put = (req: any) => {
   return axios({
     method: "put",
     url: `/${req.url}`,
     data: QS.stringify(req.data)
   });
 };
 
 // delete
 export const _delete = (req: any) => {
   return axios({
     method: "delete",
     url: `/${req.url}`,
     data: QS.stringify(req.data)
   });
 };
  • http.ts文件里会有如下的提示,那是因为qs模块没有声明,所以在./src文件里新建一个typings文件夹,在该文件夹里面新建types.d.ts文件,将declare module 'qs';写在里面(文件夹的名字可以随意取)
    在这里插入图片描述
  • api.ts文件里面添加接口api,如下:
// api.ts
import { get, post, _delete} from "@/axios/http";

// 获取用户信息
export const getIview = (data: any) => {
   const req = {
     data,
     url: 'iview/iview',
   };
   return get(req);
 };

补充说明:上面代码是以ViewUI界面返回来的接口来测试,接口地址是:https://api.github.com/repos/iview/iview,在http.ts文件里let baseURL: string = "https://api.github.com/repos";api.ts文件里url: 'iview/iview',将地址拆开了

  • demo.ts文件里引进api里面的接口,并在action里面添加请求接口的函数getIview
// demo.ts
// 公用的内容
import { Commit, Dispatch } from "vuex";
import { getIview } from '@/axios/api';
export interface State {
    name: string,
}

const state: State = {
    name: "jf",
};

const getters = {};

const mutations = {};

const actions = {
    changeName(context: { state: State }) {
        state.name = "joanna"
    },
    // 获取页面接口
  async getIview(
    context: { commit: Commit; dispatch: Dispatch; state: State },
    payload: any
  ) {
    await getIview(payload).then(
      (res: any): void => {
    //    debugger
      }
    );
  },
};

export default {
  namespaced: true,
  state,
  mutations,
  actions,
  getters
};
  • HelloDemo.vue里面调用demo.ts里的接口函数getIview
// HelloDemo.vue
<template>
 <div class="hello-demo">
   <Button @click="change">change name</Button>
   <div>name: {{this.demo.name}}</div>
 </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import { State, Action } from "vuex-class";

@Component({
 components: {
  
 },
})
export default class HelloDemo extends Vue {
   @State((state) => state.demo) private demo: any;
   @Action("demo/changeName") private changeName: any; // 改变姓名
   @Action("demo/getIview") private getIview: any; // 获取页面
   mounted () {
       this.getIview()
   }
   // 改变姓名
   private change() {
       this.changeName()
   }
}
</script>
  • 接口演示结果

在这里插入图片描述

总结

本片文章对vue-cli3.0+typescript+vuex+axios+router项目搭建步骤进行了简单的阐述,里面涉及到很多知识,以后会慢慢补充。

参考链接

  • 5
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面我为你提供一个简单的示例代码: 首先,我们需要在项目中安装需要的依赖: ``` npm install vue@next vue-router@next vuex@next axios json-server --save npm install --save-dev typescript @types/node @types/vue @types/vue-router @types/vuex ``` 接下来,我们先创建一个 `api.ts` 文件来处理登录请求: ```typescript import axios from "axios"; export const login = (username: string, password: string) => axios.post("/api/login", { username, password }); ``` 然后在 `main.ts` 中初始化 `axios`: ```typescript import { createApp } from "vue"; import App from "./App.vue"; import router from "./router"; import store from "./store"; import axios from "axios"; axios.defaults.baseURL = "http://localhost:3000"; createApp(App) .use(store) .use(router) .mount("#app"); ``` 接着,在 `store` 目录下创建一个 `auth.ts` 文件来管理用户登录状态: ```typescript import { Module } from "vuex"; import { login } from "../api"; interface AuthState { isLoggedIn: boolean; username: string; } const authModule: Module<AuthState, any> = { namespaced: true, state: { isLoggedIn: false, username: "", }, mutations: { login(state, username: string) { state.isLoggedIn = true; state.username = username; }, logout(state) { state.isLoggedIn = false; state.username = ""; }, }, actions: { async login({ commit }, { username, password }) { try { const response = await login(username, password); commit("login", response.data.username); } catch (error) { console.error(error); throw error; } }, logout({ commit }) { commit("logout"); }, }, }; export default authModule; ``` 最后,在 `views` 目录下创建一个 `Login.vue` 文件,用于用户登录: ```vue <template> <div> <form @submit.prevent="login"> <label> Username: <input type="text" v-model="username" /> </label> <label> Password: <input type="password" v-model="password" /> </label> <button type="submit">Submit</button> </form> </div> </template> <script lang="ts"> import { defineComponent } from "vue"; import { useStore } from "vuex"; export default defineComponent({ name: "Login", setup() { const store = useStore(); const username = ref(""); const password = ref(""); const login = async () => { try { await store.dispatch("auth/login", { username: username.value, password: password.value }); router.push("/"); } catch (error) { console.error(error); alert("Error logging in, please try again."); } }; return { username, password, login, }; }, }); </script> ``` 最后,在 `router` 目录下定义路由: ```typescript import { createRouter, createWebHistory } from "vue-router"; import Home from "../views/Home.vue"; import Login from "../views/Login.vue"; import { store } from "../store"; const routes = [ { path: "/", name: "Home", component: Home, meta: { requiresAuth: true, }, }, { path: "/login", name: "Login", component: Login, }, ]; const router = createRouter({ history: createWebHistory(process.env.BASE_URL), routes, }); router.beforeEach((to, from, next) => { const requiresAuth = to.matched.some((record) => record.meta.requiresAuth); if (requiresAuth && !store.state.auth.isLoggedIn) { next("/login"); } else { next(); } }); export default router; ``` 现在,你可以通过访问 `/login` 路径来尝试进行登录了。如果登录成功,你将被重定向到 `/` 路径,否则会提示错误信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值