vue TS项目

本文详细介绍了如何使用vue-cli搭建一个Vue TS项目,包括环境配置、代码规范、Element UI的导入、样式处理、接口处理、路由配置、权限管理等方面。通过该项目,读者将学习到Vue.js结合TypeScript的实践技巧,以及如何使用ESLint和Vue CLI工具来维护代码质量。
摘要由CSDN通过智能技术生成

使用到的资源
vue官网: https://cn.vuejs.org/
element-ui : https://element.eleme.cn/#/zh-CN/component/icon
ESLint
TS
SCSS

源码地址: https://github.com/qifutian/learngit/tree/main/TSvue-DEMO/edu-boss-fed

一 、 搭建项目架构

使用vue-cli创建项目

  1. vue create edu-boss-fed
  2. 使用自定义选项,选择babel,ts,route,vuex,css预处理,linter
  3. 使用class风格描述组件
  4. 选择ts和babel编译
  5. 不选择history路由模式
  6. 选择预处理器Sass,建议选择 dart-sass
  7. 选择ESlint
  8. 单独存放个自的配置文件
  9. 进入项目中,npm run serve 启动,默认打开8080地址

加入git 版本管理

  1. 创建远程仓库
  2. 本地代码提交远程仓库
  3. 生成git本地仓库 git init
  4. git status 查看当前状态
  5. git add . 将所有文件放到暂存区
  6. git status 查看暂存区内容,是否选中
  7. git commit -m "init " 记录提交日志
  8. git log 查看历史记录
  9. git remote add origin 远程地址 关联远程地址
  10. git remote -v 查看远程地址
  11. git push -u origin master 第一次记录当前origin中的master分支

目录结构

main.ts — 整个系统的入口
public — 纯静态资源文件,放index.html,不被webpack打包的
App.vue — 项目中的根组件,router-view是根路由出口
shims.tsx.d.ts 和 shims-vue.d.ts — 都是整个项目中ts的配置
Home.vue — home组件,组件中是ts规范
store — vuex目录,存放vuex的配置
route — 放置路由表,存放对应的ts路由,严格描述
components — 放置公共的组件文件夹
assets — 放置静态资源
node_modules — 第三方包
.gitignore — 放置不会被git 提交的文件
babel.config.js — babel 的配置
tsconfig.json – ts的配置

调整初始目录结构

App.vue 删除样式,删除多余模板
route/index.ts 清空路由表
删除Home.vue 和 about.vue
删除Hello.vue,删除log.png
创建utils目录,存放一些功能模块,请求等
创建styles目录,全局样式
创建services,放接口部分

环境说明

在Vue中如何启动 typescript 支持
两种方式: 1. 在使用vue-cli创建项目中选择typescript
2. 已有项目,添加vue官方配置的ts适配插件

vue  add  @vue/typescript

使用TS开发,编辑器推荐VS Code
如果是vue项目,推荐安装 vetur插件

相关配置说明
ts相关的配置
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

使用Options APIs
定义组件的方式

要让 TypeScript 正确推断 Vue 组件选项中的类型,您需要使用 Vue.component 或 Vue.extend 定义组件:

import Vue from 'vue'
const Component = Vue.extend({
   
  // 类型推断已启用
})

const Component = {
   
  // 这里不会有类型推断,
  // 因为 TypeScript 不能确认这是 Vue 组件的选项
}

基于类的 Vue 组件

import Vue from 'vue'
import Component from 'vue-class-component'

// @Component 修饰符注明了此类为一个 Vue 组件
@Component({
   
  // 所有的组件选项都可以放在这里
  template: '<button @click="onClick">Click!</button>'
})
export default class MyComponent extends Vue {
   
  // 初始数据可以直接声明为实例的 property
  message: string = 'Hello!'

  // 组件方法也可以直接声明为实例的方法
  onClick (): void {
   
    window.alert(this.message)
  }
}

装饰器语法

在这里插入图片描述

代码格式规范

良好的代码格式有利于维护,多人协作,阅读
约束代码规范
默认阅读不可靠,需要工具强制执行

  • JSLint
  • JSHint
  • ESLint 等等

项目中的代码规范

module.exports = {
   
  root: true,
  env: {
   
    node: true
  },
  // 使用插件的编码校验规则
  extends: [
    'plugin:vue/essential',
    '@vue/standard',
    '@vue/typescript/recommended'
  ],
  parserOptions: {
   
    ecmaVersion: 2020
  },

  // 自定义编码校验规则
  rules: {
   
    'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    // 'semi': ['error', 'always']
    '@typescript-eslint/member-delimiter-style': ['error', {
   
      "multiline": {
   
        "delimiter": "none",
        "requireLast": true
      }
    }]
  }
}

自定义的校验规则

// 自定义编码校验规则
  rules: {
   
    'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    // 'semi': ['error', 'always']
    '@typescript-eslint/member-delimiter-style': ['error', {
   
      "multiline": {
   
        "delimiter": "none",
        "requireLast": true
      }
    }]
  }

导入element

安装: npm i element-ui -S
引入element-ui
两种方式: 1.全部引入 2. 按需引入

在 main.js 中写入以下内容:

import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue';

Vue.use(ElementUI);

new Vue({
   
  el: '#app',
  render: h => h(App)
});

样式处理

在使用element,进行组件定制
在src/styles中新增

index.scss 全局样式,在入口模块被加载
mixin.scss 公共的mixin混入
reset.scss 重置默认样式
variables.scss 公共样式变量

index.scss

@import './variables.scss';

// globals
html {
   
  font-family: $font-family;
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
  // better Font Rendering
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body {
   
  margin: 0;
  background-color: $body-bg;
}

// custom element theme
$--color-primary: $primary-color;
$--color-success: $success-color;
$--color-warning: $warning-color;
$--color-danger: $danger-color;
$--color-info: $info-color;
// change font path, required
$--font-path: '~element-ui/lib/theme-chalk/fonts';
// import element default theme
@import '~element-ui/packages/theme-chalk/src/index';
// node_modules/element-ui/packages/theme-chalk/src/common/var.scss

// overrides

// .el-menu-item, .el-submenu__title {
   
//   height: 50px;
//   line-height: 50px;
// }

.el-pagination {
   
  color: #868e96;
}

// components

.status {
   
  display: inline-block;
  cursor: pointer;
  width: .875rem;
  height: .875rem;
  vertical-align: middle;
  border-radius: 50%;

  &-primary {
   
    background: $--color-primary;
  }

  &-success {
   
    background: $--color-success;
  }

  &-warning {
   
    background: $--color-warning;
  }

  &-danger {
   
    background: $--color-danger;
  }

  &-info {
   
    background: $--color-info;
  }
}

variables.scss

$primary-color: #40586F;
$success-color: #51cf66;
$warning-color: #fcc419;
$danger-color: #ff6b6b;
$info-color: #868e96; // #22b8cf;

$body-bg: #E9EEF3; // #f5f5f9;

$sidebar-bg: #F8F9FB;
$navbar-bg: #F8F9FB;

$font-family: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

样式处理 – 共享全局样式变量

在全局配置,节省组件加载,注入到全局

增加vue.config.js

// vue.config.js
module.exports = {
   
  css: {
   
    loaderOptions: {
   
      // 默认情况下 `sass` 选项会同时对 `sass` 和 `scss` 语法同时生效
      // 因为 `scss` 语法在内部也是由 sass-loader 处理的
      // 但是在配置 `prependData` 选项的时候
      // `scss` 语法会要求语句结尾必须有分号,`sass` 则要求必须没有分号
      // 在这种情况下,我们可以使用 `scss` 选项,对 `scss` 语法进行单独配置
      scss: {
   
        prependData: `@import "~@/styles/variables.scss";`
      }
    }
  },

  
}

接口处理

使用proxy设置代理接口地址
在vue.config.js 在添加

devServer: {
   
    proxy: {
   
      '/boss': {
   
        target: 'http://eduboss.lagou.com',
        changeOrigin: true // 把请求头中的 host 配置为 target
      },
      '/front': {
   
        target: 'http://edufront.lagou.com',
        changeOrigin: true
      }
    }
  }

封装请求模块

安装 axios
npm i axios
创建请求模块,src/utils/request.js

import axios from 'axios'

const request = axios.create({
   
  // 配置选项
  // baseURL,
  // timeout
})

// 请求拦截器

// 响应拦截器

export default request

初始化路由组件

view下新创建对应的文件
在route/index.ts 下配置 路由懒加载,进行lauout布局,路由嵌套
layout 布局,src下新建layout文件夹,将除了登录页和404页面外全部是layout的子路由

import Vue from 'vue'
import VueRouter, {
    RouteConfig } from 'vue-router'
import Layout from '@/layout/index.vue'

Vue.use(VueRouter)

// 路由配置规则
const routes: Array<RouteConfig> = [
  {
   
    path: '/login',
    name: 'login',
    component: () => import(/* webpackChunkName: 'login' */ '@/views/login/index.vue')
  },
  {
   
    path: '/',
    component: Layout,
    children: [
      {
   
        path: '', // 默认子路由
        name: 'home',
        component: () => import(/* webpackChunkName: 'home' */ '@/views/home/index.vue')
      },
      {
   
        path: '/role',
        name: 'role',
        component: () => import(/* webpackChunkName: 'role' */ '@/views/role/index.vue')
      },
      {
   
        path: '/menu',
        name: 'menu',
        component: () => import(/* webpackChunkName: 'menu' */ '@/views/menu/index.vue')
      },
      {
   
        path: '/resource',
        name: 'resource',
        component: () => import(/* webpackChunkName: 'resource' */ '@/views/resource/index.vue')
      },
      {
   
        path: '/course',
        name: 'course',
        component: () => import(/* webpackChunkName: 'course' */ '@/views/course/index.vue')
      },
      {
   
        path: '/user',
        name: 'user',
        component: () => import(/* webpackChunkName: 'user' */ '@/views/user/index.vue')
      },
      {
   
        path: '/advert',
        name: 'advert',
        component: () => import(/* webpackChunkName: 'advert' */ '@/views/advert/index.vue')
      },
      {
   
        path: '/advert-space',
        name: 'advert-space',
        component: () => import(/* webpackChunkName: 'advert-space' */ '@/views/advert-space/index.vue')
      }
    ]
  },
  {
   
    path: '*',
    name: '404',
    component: () => import(/* webpackChunkName: '404' */ '@/views/error-page/404.vue')
  }
]

const router = new VueRouter({
   
  routes
})

export default router

侧边栏组件

使用container布局容器
在app-aside.vue中使用el-menu标签,加入route进入导航资源

<template>
  <div class="aside">
    <el-menu
      default-active="4"
      @open="handleOpen"
      @close="handleClose"
      background-color="#545c64"
      text-color="#fff"
      active-text-color="#ffd04b"
      router
    >
      <el-submenu index="1">
        <template slot="title">
          <i class="el-icon-location"></i>
          <span>权限管理</span>
        </template>
        <el-menu-item index="/role">
          <i class="el-icon-setting"></i>
          <span slot="title">角色管理</span>
        </el-menu-item>
        <el-menu-item index="/menu">
          <i class="el-icon-setting"></i>
          <span slot="title">菜单管理</span>
        </el-menu-item>
        <el-menu-item index="/resource">
          <i class="el-icon-setting"></i>
          <span slot="title">资源管理</span>
        </el-menu-item>
      </el-submenu>
      <el-menu-item index="/course">
        <i class="el-icon-menu"></i>
        <span slot="title">课程管理</span>
      </el-menu-item>
      <el-menu-item index="/user">
        <i class="el-icon-document"></i>
        <span slot="title">用户管理</span>
      </el-menu-item>
      <el-submenu index="4">
        <template slot="title">
          <i class="el-icon-location"></i>
          <span>广告管理</span>
        </template>
        <el-menu-item index="/advert">
          <i class="el-icon-setting"></i>
          <span slot="title">广告列表</span>
        </el-menu-item>
        <el-menu-item index="/advert-space">
          <i class="el-icon-setting"></i>
          <span slot="title">广告位列表</span>
        </el-menu-item>
      </el-submenu>
    </el-menu>
  </div>
</template>

<script lang="ts">
import Vue from 'vue'

export default Vue.extend({
   
  name: 'AppAside',
  methods: {
   
    handleOpen (key: string, keyPath: string): void {
   
      console.log(key, keyPath)
    },

    handleClose (key: string, keyPath: string): void {
   
      console.log(key, keyPath)
    }
  }
})
</script>

<style lang="scss" scoped>
.aside {
   
  .el-menu {
   
    min-height: 100vh;
  }
}
</style>

头部导航

采用面包屑导航,新建app-header.vue组件
采用下拉菜单作为用户信息

<template>
  <div class="header">
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
      <el-breadcrumb-item>活动管理</el-breadcrumb-item>
      <el-breadcrumb-item>活动列表</el-breadcrumb-item>
      <el-breadcrumb-item>活动详情</el-breadcrumb-item>
    </el-breadcrumb>
    <el-dropdown>
      <span class="el-dropdown-link">
        <el-avatar
          shape="square"
          :size="40"
          src="https://cube.elemecdn.com/9/c2/f0ee8a3c7c9638a54940382568c9dpng.png"
        ></el-avatar>
        <i class="el-icon-arrow-down el-icon--right"></i>
      </span>
      <el-dropdown-menu slot="dropdown">
        <el-dropdown-item>用户ID</el-dropdown-item>
        <el-dropdown-item divided>退出</el-dropdown-item>
      </el
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值