前端项目搭建实战(Vue)

2022-08-03 21:04:15 浏览数 (1)

网上开源的前端框架都写得很好,但是功能比较庞杂,于是着手搭建了一套自己的模板:

1.路由配置

首先我们要通过路由配置整体的页面结构(Home、About、Login)

代码语言:javascript复制
Vue.use(VueRouter);

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home,
  },
  {
    path: '/about',
    name: 'About',
    component: () => import('../views/About.vue'),
  },
  {
    path: '/login',
    name: 'Login',
    component: () => import('../views/Login.vue'),
  },
];

const router = new VueRouter({
  routes,
});

同时我们需要对路由做一定的控制,比如未登录时只允许访问登录页,以及对页面跳转做一些样式上的优化。

代码语言:javascript复制
router.beforeEach((to, from, next) => {
  // 虚拟进度条,采用 NProgress 组件
  NProgress.start();
  let token = cookies.get('token');
  // 如果没有 token 则跳到登录页
  if (!token) {
    if (to.fullPath !== '/login') {
      next({ path: '/login' });
    } else {
      next();
    }
    return NProgress.done();
  } else {
    // 如果有 token 访问登录页则跳到首页;刷新时自动获取角色信息保存在 vuex 中
    if (!store.state.role) {
      const role = GET_ROLE();
      store.commit('setState', role);
    }
    if (to.fullPath === '/login') {
      next({ path: '/' });
    } else {
      next();
    }
    NProgress.done();
  }
});

2.Vuex 全局状态管理

在路由配置中我们将角色信息存储在了 Vuex 中,Vuex 的配置如下:

代码语言:javascript复制
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    // 角色信息
    role: '',
  },
  mutations: {
    setState(state, role) {
      state.role = role;
    },
  },
  actions: {},
  modules: {},
});

在页面中我们可以通过 mapState 访问 store 中的数据

代码语言:javascript复制
import { mapState } from 'vuex';
computed: mapState(['role']),

<h3>我是:{{ role }}</h3>

3.组件库选用 Element-ui

组件库的选用纯看个人喜好

代码语言:javascript复制
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);

4.自定义过滤器

自定义时间过滤器,在 main.js 全局注册时间过滤器,传入模板字符串解析为对应格式

代码语言:javascript复制
// 定义时间过滤器
Vue.filter('dateFormat', function (originDate, pattern) {
  // 根据给定的时间字符串,得到特定的时间
  var dt = new Date(originDate);
  var y = dt.getFullYear();
  var m = (dt.getMonth()   1).toString().padStart(2, '0');
  var d = dt.getDate().toString().padStart(2, '0');
  var hh = dt.getHours().toString().padStart(2, '0');
  var mm = dt.getMinutes().toString().padStart(2, '0');
  var ss = dt.getSeconds().toString().padStart(2, '0');
  return eval('`'   pattern   '`');
});

在页面中使用

代码语言:javascript复制
<h3>当前时间:{{ time | dateFormat('${y}-${m}') }}</h3>
timetime

5.自定义指令

在 main.js 中注册全局指令

代码语言:javascript复制
// 权限指令
Vue.directive('perm', {
  // 绑定元素插入父节点时触发
  inserted: (el, binding) => {
    const hasPermission = (roleArr) => {
      return roleArr.includes(store.state.role);
    };
    if (!hasPermission(binding.value)) {
      // 如果不满足条件,则移除当前绑定节点
      el.parentNode.removeChild(el);
    }
  },
});

在页面中使用,当角色为 admin 时,第一行不显示

代码语言:javascript复制
<h3>学生可以看到: 我是<span v-perm="['student']">{{ role }}</span></h3>
<h3>大家可以看到: 我是<span v-perm="['student', 'admin']">{{ role }}</span></h3>
directivedirective

6. svg 封装

新建 SvgIcon.vue 文件

代码语言:javascript复制
<template>
  <svg :class="svgClass" aria-hidden="true" v-on="$listeners">
    <use :xlink:href="iconName" />
  </svg>
</template>

<script>
export default {
  name: 'SvgIcon',
  props: {
    // svg图标名称
    name: {
      default: '',
    },
    // 自定义样式
    className: {
      type: String,
      default: '',
    },
  },
  computed: {
    iconName() {
      return `#icon-${this.name}`;
    },
    svgClass() {
      return ['svg-icon', this.className ? this.className : ''];
    },
  },
};
</script>

<style scoped>
.svg-icon {
  vertical-align: -0.15em;
  fill: currentColor;
  overflow: hidden;
}
</style>

全局注册该组件

代码语言:javascript复制
Vue.component('SvgIcon', SvgIcon);

这样我们就可以通过 SvgIcon 访问内存中存在的 svg 图标了,我们还需要做的就是将 svg 文件加载到内存中,

svg-sprite-loader 的官方解释是:一个用于创建 svg 雪碧图的 Webpack 加载器。这个加载器现在已经被 JetBrains 公司收录和维护了。通俗的讲:svg-sprite-loader 会把你引入的 svg 塞到一个个 symbol 中,合成一个大的 svg,最后将这个大的 svg 放入 body 中。symbol 的 id 如果不特别指定,就是你的文件名。

代码语言:javascript复制
chainWebpack(config) {
  // 配置路径别名
  config.resolve.alias.set('components', resolve('src/components'));
  // 已有配置排除掉svg
  config.module.rule('svg').exclude.add(resolve('src/svg'));
  // 添加svg-sprite-loader
  config.module
    .rule('icons')
    .test(/.svg$/) // 设置test
    .include.add(resolve('src/svg')) // 加入include
    .end() // add完上下文进入数组,使用end回退
    .use('svg-sprite-loader') // 添加loader
    .loader('svg-sprite-loader') // 切换上下文到loader
    .options({ symbolId: 'icon-[name]' })
    .end();
},

// main.js -- 将 svg 文件引入内存中
import '@/svg/icons';
// icons.js
const req = require.context('../svg', false, /.svg$/);
req.keys().map(req);

这样就可以通过 name 属性访问 svg 了

代码语言:javascript复制
<SvgIcon name="404" className="icon-style" />
svgsvg

7.axois 封装

axios 建议只做简单封装即可

代码语言:javascript复制
import axios from 'axios';
import cookies from '@/utils/js-cookie';
// 创建请求实例
function createRequest() {
  const request = axios.create({
    baseURL: '/api',
    timeout: 10000,
  });

  request.interceptors.request.use((config) => {
    // 自动携带 token
    const token = cookies.get('token');
    config.headers.token = token;
    return config;
  });

  return request;
}

export const request = createRequest();

// api.js
import { request } from './service';

export function GET_BOOK_LIST() {
  return request({
    url: '/catalog/book/',
    method: 'get',
    headers: { 'content-type': 'application/x-www-form-urlencoded' },
    params: {
      type: 'book',
    },
  });
}

0 人点赞