vue3.0项目从新建到 封装与运行

vue3+vueRouter + vueX 项目新建

vue create demo

在这里插入图片描述
按住

在这里插入图片描述

cd demo(cd 到项目)
npm run serve(此时已经运行起来)

安装插件

npm install element-plus
npm intsall @element-plus/icons-vue
npm install axios(axios)
npm install qs(序列化)

引入插件

引入element 和icons

// main.ts里
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
// 引入elementPlus
import ElementPlus from 'element-plus'
import zhCn from 'element-plus/es/locale/lang/zh-cn'
import 'element-plus/dist/index.css'
// 引入字体文件
import * as ElementPlusIconsVue from '@element-plus/icons-vue'

(async () => {
  const app = createApp(App)

  // 使用字体文件
  for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
    app.component(key, component)
  }
  app.use(store).use(router).use(ElementPlus, { locale: zhCn }).mount("#app")
})

vue.config.js(vue3.0需要自己建立vue.config.js,在根目录下,与src同级)

const path = require('path')
const webpack = require('webpack')
const IS_PROD = ['production', 'test'].includes(process.env.NODE_ENV)
module.exports = {
  // 部署应用包时的基本 URL,用法和 webpack 本身的 output.publicPath 一致
  publicPath: './',
  // 输出文件目录
  outputDir: 'dist',
  // eslint-loader 是否在保存的时候检查
  lintOnSave: true,
  // 是否使用包含运行时编译器的 Vue 构建版本
  runtimeCompiler: false,
  // 生产环境是否生成 sourceMap 文件
  productionSourceMap: false,
  // 生成的 HTML 中的 <link rel="stylesheet"> 和 <script> 标签上启用 Subresource Integrity (SRI)
  integrity: false,
  // webpack相关配置
  chainWebpack: (config) => {
    config.plugin('html')
      .tap(args => {
        args[0].title = '项目名称';
        return args;
      })
  },
  configureWebpack: (config) => {
    if (process.env.NODE_ENV === 'production') {
    //生产环境
      config.mode = 'production'
    } else {
      //开发环境
      config.mode = 'development'
    }
  },
  // css相关配置
  css: {
    // 是否分离css(插件ExtractTextPlugin)
    extract: IS_PROD,
    // 是否开启 CSS source maps
    sourceMap: false,
    // css预设器配置项
    loaderOptions: {
      sass: {
        // prependData: `@import "~@/assets/scss/variable.scss";`,
        // 公共css
      }
    },
    // 是否启用 CSS modules for all css / pre-processor files.
    modules: false
  },
  // 是否使用 thread-loader
  parallel: require('os').cpus().length > 1,
  // PWA 插件相关配置
  pwa: {},
  // webpack-dev-server 相关配置
  devServer: {
    open: false,
    host: 'XXX.XXX.X.XXX', // 服务器地址
    port: 8090, // 端口,可以自己改
    https: false,
    hotOnly: false,
    before: (app) => { }
  },
  // 第三方插件配置
  pluginOptions: {

  }
}

接口地址(public下建立serverconfig.json文件)

在这里插入图片描述

token 存储

将token存储到cookie里
新建文件untils->auth.ts

const TokenKey = 'PROJECTKEY'

export function getToken(): (string | null) {
  let arr: any
  let reg = new RegExp('(^| )' + TokenKey + '=([^;]*)(;|$)')
  if (arr = document.cookie.match(reg)) {
    console.log(arr)
    return unescape(arr[2])
  } else {
    return null
  }
}

export function setToken(token: string) {
  let Days = 30
  let exp = new Date()
  exp.setTime(exp.getTime() + Days * 24 * 60 * 60 * 1000)
  document.cookie = TokenKey + '=' + escape(token) + ';expires=' + exp.toUTCString() + '; path=/'
}

export function removeToken() {
  let exp = new Date()
  exp.setTime(exp.getTime() - 1)
  let cval = getCookieLocal(TokenKey)
  if (cval != null) {
    document.cookie = TokenKey + '=' + cval + ';expires=' + exp.toUTCString() + '; path=/'
  }
}

let getCookieLocal = function (name: string) {
  let arr, reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)')
  if (arr = document.cookie.match(reg))
    return unescape(arr[2])
  else
    return null;
}

接口地址

public下新建 serverconfig.json

{
  "ApiUrl": "xxxxxxxxxxxx", // 接口地址
  "Title": "Project" //项目名称
}

store 封装

①. store文件下新建 modules 文件夹(文件夹下新建 common.ts和user.ts) 和getters.ts
common.ts (来存储接口路径)

import axios from "axios";
import { Commit } from "vuex";

const state = {
  axiosBaseUrl: ''
}
const mutations = {
  SET_BASEURL: (state: any, baseUrl: string) => {
    state.axiosBaseUrl = baseUrl
  }
}
const actions = {
  getConfigJson(context: { commit: Commit }) {
    return new Promise((resolve, reject) => {
      axios.get("../../../public/serverconfig.json").then((result: any) => {
        context.commit('SET_BASEURL', result.data.ApiUrl)
        // resolve 改变promise对象的状态为成功
        resolve(result.data);
      })
        .catch((error: any) => {
          // reject 改变promise对象的状态为失败
          reject(error)
        })
    })
  }
}

user.ts 来存储 用户信息以及token

getter.ts 引入modules文件夹下的所有存储

const getters = {
  axiosBaseUrl: (state: any) => state.common.axiosBaseUrl
};
export default getters

②. store-> index.ts 中,引入 getters.ts 和modules 下的所有ts文件

import { createStore } from "vuex";
import getters from "./getter";

// 动态引入模块文件
// require.context('./modules', true, /\.ts$/)
// require.context('读取的文件路径',是否循环读取子目录,文件匹配的正则)
const modulesFiles = require.context('./modules', true, /\.ts$/)

export function isValidKey(key: string | number | symbol, object: object): key is keyof typeof object {
  return key in object
}

const modules = modulesFiles.keys().reduce((modules: any, modulePath) => {
  // set './app.js' => 'app'
  const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
  const value = modulesFiles(modulePath)
  modules[moduleName] = value.default;
  return modules

}, {})
export default createStore({
  modules,
  getters
});

axios 封装

axios->新建文件夹config
config->新建 types.ts

/**
 * request配置
 */
export interface ConfigOptions {
  result_code: any
  default_headers: any
  request_timeout: any
}

config->新建index.ts

/**
 * request全局配置
 */
 import { ConfigOptions } from './types'
 const config: ConfigOptions = {
  /**
   * 接口成功返回状态码
   */
  result_code: '0000',

  /**
   * 接口请求超时时间
   */
  request_timeout: 15000,

  /**
   * 默认接口请求类型
   * 可选值:application/x-www-form-urlencoded multipart/form-data
   */
  default_headers: 'application/json'
};
export default config

axios->request.ts

import store from "@/store";
import axios, { AxiosError, AxiosInstance, AxiosResponse, InternalAxiosRequestConfig } from "axios";
import config from "./config";
import qs from 'qs'
import { ElMessage } from "element-plus";
import { reactifyObject } from "@vueuse/shared";

// 创建axios实例
const service: AxiosInstance = axios.create({
  timeout: config.request_timeout // 请求超时时间
})

// request 拦截器
service.interceptors.request.use(
  async (config: InternalAxiosRequestConfig) => {
    config.url = (store.getters.axiosBaseUrl ? store.getters.axiosBaseUrl : (await store.dispatch('common/getConfigJson')).ApiUrl) + config.url
    if (config.method === 'post' && config.headers ? config.headers['Content-Type'] === 'application/x-www-form-urlencoder' : '') {
      // post方法的数据序列化
      config.data = qs.stringify(config.data)
    }
    return config
  },
  (error: AxiosError) => {
    console.log(error)
    Promise.reject(error)
  }
)

// response 拦截器
service.interceptors.response.use(
  (response: AxiosResponse) => {
    let res: any = response.data
    // 改变登录状态
    store.dispatch('loading/hideloader')
    if (res && res.code == -100) {
      // 登录超时
      ElMessage({
        showClose: true,
        message: `登录超时`,
        type: 'error'
      })
      // 改变token以及用户信息 (调用store/user 里的resetToken方法)
      store.dispatch('user/resetToken')
      location.reload()
    } else {
      return res
    }
  },
  (error: AxiosError) => {
    // 改变登录状态
    store.dispatch('loading/hideloader')
    ElMessage({
      showClose: true,
      message: error.message,
      type: 'error'
    })
    return Promise.reject(error)

  }
)
export default service

axios->index.ts

import store from "@/store"
import { getToken } from "@/utils/auth"
import { AxiosPromise, ResponseType } from "axios"
import request from './request'
import config from "./config"
const { default_headers } = config

interface Config {
  params?: any
  data?: any
  url: string
  method: 'get' | 'post' | 'delete' | 'put'
  headersType?: string
  responseType?: ResponseType
}

function fetch({ url, method, params, data, headersType, responseType }: Config): AxiosPromise {
  return request({
    url: url,
    method,
    params,
    data,
    responseType: responseType,
    headers: {
      'Content-Type': headersType || default_headers,
      token: store.getters.token ? store.getters.token : getToken()
    }
  })
}

export {
  fetch
}

接口封装

src->Api->user.ts

import { fetch } from "@/axios"

interface PropsData {
  params?: any
  data?: any
}

export const login = ({ data }: PropsData): any => {
  return fetch({ url: '/Login', method: 'post', data })
}
export const userInfo = ({ params }: PropsData): any => {
  return fetch({ url: '/userInfo', method: 'get', params })
}
  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值