Vue + TypeScript 实战项目(二)

388 阅读3分钟

本系列将从零开始创建一个项目,文章将持续更新

项目代码: https://github.com/no-pear/edu-fed.git

三、基础样式处理

1)导入 element 组件库

Element - 网站快速成型工具

  • 安装 npm i element-ui -S
  • 完整引入
// 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)
});

2)样式处理

src/styles
├── index.scss # 全局样式(在⼊⼝模块被加载⽣效) 
├── mixin.scss # 公共的 mixin 混⼊(可以把重复的样式封装为 mixin 混⼊到复⽤ 的地⽅) 
├── reset.scss # 重置基础样式 5 └── variables.scss # 公共样式变量

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;

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;
  }
}

3) 共享全局样式变量

向预处理器-loader-传递选项

module.exports = {
    css: {
      loaderOptions: {
        // 给 sass-loader 传递选项
        // sass: {
        //   // @/ 是 src/ 的别名
        //   // 所以这里假设你有 `src/variables.sass` 这个文件
        //   // 注意:在 sass-loader v8 中,这个选项名是 "prependData"
        //   additionalData: `@import "~@/variables.sass"`
        // },
        // 默认情况下 `sass` 选项会同时对 `sass` 和 `scss` 语法同时生效
        // 因为 `scss` 语法在内部也是由 sass-loader 处理的
        // 但是在配置 `prependData` 选项的时候
        // `scss` 语法会要求语句结尾必须有分号,`sass` 则要求必须没有分号
        // 在这种情况下,我们可以使用 `scss` 选项,对 `scss` 语法进行单独配置
        scss: {
            prependData: `@import "~@/styles/variables.scss";`
        },
        
      }
    }
  }

四、与服务端交互

1)配置后端代理

后台为我们提供了数据接⼝,分别是:

这两个接⼝都没有提供 CORS 跨域请求,所以需要在客户端配置服务端代理处理跨域请求。

配置客户端层⾯的服务端代理跨域可以参考官方文档中的说明:

2)封装请求模块

  • 安装 axios npm i axios
  • src/utils/request.ts
import axios from 'axios'

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

// 请求拦截器

// 响应拦截器

export default request

五、布局

1)初始化路由页面组件

路径说明
/首页
/login用户登录
/role角色管理
/menu菜单管理
/resource资源管理
/course课程管理
/user用户管理
/advert广告管理
/advert-space广告位管理
*404

src/router/index.ts

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/index.vue')
  }
]

const router = new VueRouter({
  routes
})

export default router

页面目录结构

2)Container 布局容器

src/layout/index.vue

<template>
  <el-container>
    <el-aside width="200px">Aside</el-aside>
    <el-container>
      <el-header>Header</el-header>
      <el-main>Main</el-main>
    </el-container>
  </el-container>
</template>

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

export default Vue.extend({
  name: 'LayoutIndex'
})
</script>

<style lang="scss" scoped>
.el-container {
    min-height: 100vh;
}
.el-aside {
    background-color: #D3DCE6
}
.el-header {
    background-color: #B3C0D1
}
.el-main {
    background-color: #E9EEF3
}
</style>