Vue-Cli 3.0 создает проект с нуля (часть 1)

Vue.js
Создание проекта с 0, я полагаю, что больше людей сделали это, но действительно ли вы построили весь проект самостоятельно? Вы внимательно рассмотрели его, будь то выбор UI-фреймворка, разрешений, значков, маршрутизации, перехвата входа в систему, третьего -party Библиотека инструментов, оптимизация производительности и другие аспекты создали персонал и среду, подходящие для проекта компании. В этой статье кратко излагается проект сборки Vue-Cli3.0.
Построить проект

В соответствии с реальной ситуацией. Примечательно, что проект Vue-CLi должен инициализироватьvue create ××, вместо предыдущегоvue init webpack ××Я примерно выбрал маршрутизацию истории, Vuex, less, eslint, unit test и т.д.

Официальный адрес Vue-Cli

Конфигурация webpack, babel, vue.config.js
Связанная конфигурация vue.config.js
// 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, // 构建多页
  productionSourceMap: false, // 开启 生产环境的 source map?
  configureWebpack: {   // webpack 的配置
    plugins: [
      new MyAwesomeWebpackPlugin()
    ]
  },
  chainWebpack: config => { // webpack的配置(链式操作)
    // 配置路径别名
    // 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: {
      less: {
          modifyVars: {   // 定制主题
                 'primary-color': '#1DA57A',
                 'link-color': '#1DA57A',
                 'border-radius-base': '2px',
                  },
          javascriptEnabled: true,

      }
  }
  },
  devServer: {
    port: 8080, // 端口
    proxy: '' // 设置代理
  }
}

Официальный адрес Vue.config.js

babel.config.js

использоватьbabel-plugin-import(Загрузка кода компонента и подключаемого модуля babel CCTV по запросу), с использованием этого подключаемого модуля вводится следующая конфигурация.vue-antd-design

// babel.config.js
module.exports = {
  presets: ["@vue/app"],
   plugins: [
     [
       "import",
     { libraryName: "ant-design-vue", libraryDirectory: "es", style: true }
    ]
  ]
};
Фреймворк пользовательского интерфейса (Ant-design-vue)
глобальный импорт

Нечего сказать. Я хочу сказать, что глобальный импорт имеет 13 МБ и более 50 компонентов, и все они немного велики. Фактически, в проектах, которые я делал раньше, они в основном импортируются глобально.Интересно, будут ли у больших парней «чистота», когда они пишут код, независимо от того, импортируются ли они локально или написаны сами по себе, ха-ха

местное знакомство
// main.js
import { Button } from "ant-design-vue"
import "ant-design-vue/dist/antd.less"
// 或者是
import "ant-design-vue/lib/button.less"
Vue.use(Button)
Используйте babel-plugin-import (расширенная конфигурация)

официальный адрес vue-and-designконфигурация вышеbabel.config.jsсередина. давайте посмотрим нижеmain.jsкак это используется

// main.js
 import { Button,Menu,Drawer,Radio,Layout,Icon} from 'ant-design-vue';
 
 Vue.use(Drawer)
 Vue.use(Button)
 Vue.use(Menu)
 Vue.use(Radio)
 Vue.use(Layout)
 Vue.use(Icon)

Упс, вроде бы очень длинно, но размер загруженного файла действительно намного меньше

конфигурация маршрутизации

Обязательно настройте роутинг, надо подумать, как настроить каталог файлов. Вот каталог строительного проекта г-на Танга.

Конфигурация маршрутизации, место ограничено. Я выбираю только часть

// router.js
import Vue from "vue";
import Router from "vue-router";
import { notification } from "ant-design-vue";
import NotFound from "./views/404";
import Forbidden from "./views/403";
Vue.use(Router);

const router = new Router({
  mode: "history",
  base: process.env.BASE_URL,
  routes: [
    {
      path: "/user",
      hideInMenu: true,
      component: () =>
        import( "./layouts/UserLayout"),
      children: [
        {
          path: "/user",
          redirect: "/user/login"
        },
        {
          path: "/user/login",
          name: "login",
          component: () =>
            import( "./views/User/Login")
        }
      ]
    },
    {
      path: "/",
      meta: { authority: ["user", "admin"] },  // 用来做权限管理
      component: () =>
        import( "./layouts/BasicLayout"),
      children: [
        // dashboard
        {
          path: "/",
          redirect: "/dashboard/analysis"
        },
        {
          path: "/dashboard",
          name: "dashboard",
          meta: { icon: "dashboard", title: "仪表盘" },
          component: { render: h => h("router-view") },
          children: [
            {
              path: "/dashboard/analysis",
              name: "analysis",
              meta: { title: "分析页" },
              component: () =>
                import( "./views/Dashboard/Analysis")
            }
          ]
        },
        // form
        {
          path: "/form",
          name: "form",
          component: { render: h => h("router-view") },
          meta: { icon: "form", title: "表单", authority: ["admin"] },
          children: [
            {
              path: "/form/basic-form",
              name: "basicform",
              meta: { title: "基础表单" },
              component: () =>
                import("./views/Forms/BasicForm")
            },
            {
              path: "/form/step-form",
              name: "stepform",
              hideChildrenInMenu: true,
              meta: { title: "分布表单" },
              component: () =>
                import( "./views/Forms/StepForm"),
              children: [
                {
                  path: "/form/step-form",
                  redirect: "/form/step-form/info"
                },
                {
                  path: "/form/step-form/info",
                  name: "info",
                  component: () =>
                    import( "./views/Forms/StepForm/Step1")
                }
              ]
            }
          ]
        }
      ]
    },
    {
      path: "/403",
      name: "403",
      hideInMenu: true,
      component: Forbidden
    },
    {
      path: "*",
      name: "404",
      hideInMenu: true,
      component: NotFound
    }
  ]
});

export default router;

Резюме разделено на три части: пользовательский модуль, основной контент, страница 403/404. Под пользователем есть подмодуль входа, а основной контент (обычно контент навигационного меню) имеет дашбордdashboardи формаform, под панелью управления есть страница анализаanlysis, под формой находится базовая формаbasicForm

// App.vue
  <div id="app">
        <router-view />
  </div>

BasicForm.vue

Маршрут наверное тут Это написание очень умное

охранник маршрута

Если у вас нет разрешения на переход на целевую страницу, Нет разрешения на вход на страницу 403 после успешного входа в систему, больше знаний о защите маршрутизациинажмите

router.beforeEach((to, from, next) => {
 
   // to 即将要进入的目标 路由对象
   // from 当前导航正要离开的路由
   // next 
  if (to.path !== from.path) {
    NProgress.start();
  }
  const record = findLast(to.matched, record => record.meta.authority);
  if (record && !check(record.meta.authority)) {
    if (!isLogin() && to.path !== "/user/login") {
      next({
        path: "/user/login"
      });
    } else if (to.path !== "/403") {
      notification.error({
        message: "403",
        description: "你没有权限访问,请联系管理员咨询。"
      });
      next({
        path: "/403"
      });
    }
    NProgress.done();
  }

  next();
});
// 全局后置钩子
router.afterEach(() => {
  NProgress.done();
});
управление полномочиями
маршрутизация меню

В конфигурации маршрутизации есть метаданные, у каких пользователей там задаются права доступа к меню. В реальной среде бэкэнд возвращает меню пользователя, и если оно есть, то оно будет отрисовано.

// 检查 用户的权限
export function check(authority){
    const current = getCurrentAuthority();
    return current.some(item => authority.includes(item));
}
кнопки разрешений

Вот способ пользовательской инструкции, больше параметров пользовательской инструкциинажмите

import { check } from "../utils/auth";

function install(Vue, options = {}) {
  Vue.directive(options.name || "auth", {
    inserted(el, binding) {
      if (!check(binding.value)) {
        el.parentNode && el.parentNode.removeChild(el);
      }
    }
  });
}

export default { install };

затем вmain.jsиспользуется в

// main.js
import Auth from './directives/auth';
Vue.use(Auth);
Другие связанные
Компонент перехода Nprogress
yarn add nprogress
npm install --save-dev nprogress

функциональные компоненты

Болеенажмите

Созданный ранее компонент заголовка привязки относительно прост, он не управляет никаким состоянием, не прослушивает переданное ему состояние и не имеет методов жизненного цикла. На самом деле это просто функция, которая принимает некоторые реквизиты. В таком сценарии мы можем пометить компонент как функциональный, что означает, что он не имеет состояния (нет реактивных данных) и не имеет экземпляра (нет этого контекста).

<script>
import { check } from '../utils/auth'
export default {
    functional: true,
    props: {
        authority: {
            type: Array,
            required: true
        }
    },
    render(h, context){
        const { props,scopedSlots } = context;
        return check(props.authority) ? scopedSlots.default(): null
    }

}
</script>

Функция render() по-прежнему очень интересна.

Лоаш библиотека

resize-detector

Наконец, спасибо учителю Geek Time Tang Jinzhou за видео.

Я не знаю, где я видел предложение, код без мышления опасен, мышление без кода опасно