美文网首页
Vue-Cli 3.0从0 开始搭建项目(篇1)

Vue-Cli 3.0从0 开始搭建项目(篇1)

作者: 南蓝NL | 来源:发表于2019-05-07 18:10 被阅读0次

    从0开始搭建项目,相信更多人都做过,但是你真的独立搭建整个项目了吗,有没有考虑周全,是否从UI的框架的选型、权限、图标、路由、登陆拦截、第三方工具库、性能优化等多方面搭建出适合本公司项目的人员和环境。本文总结的是Vue-Cli3.0构建项目

    搭建项目

    根据实际情况而定。 值得注意的Vue-Cli 初始化项目的命令是vue create 项目名称,而不是之前的Vue init webpack 项目名称
    我这边大致选了history路由、Vuex、less、eslint、unit test等

    [图片上传失败...(image-dc9626-1556976269888)]
    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插件),下面的配置使用该插件引入 vue-antd-design

    // babel.config.js
    module.exports = {
      presets: ["@vue/app"],
       plugins: [
         [
           "import",
         { libraryName: "ant-design-vue", libraryDirectory: "es", style: true }
        ]
      ]
    };
    

    UI框架(Ant-design-vue)

    全局引入

    不多说。想说的是全局引入有13MB,50多个组件,全部引入有点大。其实在我以前做过的项目当中基本上都是全局引入,不知大佬们写代码会不会有“洁癖”,局部引入或是自己写,哈哈

    [图片上传失败...(image-2208b0-1556976269888)]

    局部引入
    // 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)
    

    <div style="border-left: 4px solid #99cc00;padding-left:14px;"> 使用babel-plugin-import(高级配置)</div>

    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)
    

    哎呀,貌似篇幅很长,不过加载的文件大小确实小了很多

    image

    路由配置

    一定要配置路由,就得想好文件目录怎么设置。这里参考了唐老师的搭建项目的目录

    [图片上传失败...(image-f8195c-1556976269888)]
    路由配置,篇幅有限。我只选出一部分

    // 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页面。 用户下面有子模块login,主要内容(一般是导航菜单的内容)有仪表盘dashboard和表单form,仪表盘下面有分析页anlysis,表单下面有基础表单basicForm

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

    BasicForm.vue
    [图片上传失败...(image-e9b0ec-1556976269888)]

    路由大概到这里
    这个写法觉得很巧妙

    [图片上传失败...(image-77953-1556976269888)]

    路由守卫

    如果没有权限跳到登陆页面,
    登陆成功之后没有权限进入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));
    }
    

    <div style="border-left: 4px solid #99cc00;padding-left:14px;">按钮权限</div>

    这里是自定义指令的方式做的,更多自定义指令的参数点击

    [图片上传失败...(image-1f9a6f-1556976269888)]

    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
    

    [图片上传失败...(image-d158e3-1556976269888)]

    [图片上传失败...(image-a44ce3-1556976269888)]

    <div style="border-left: 4px solid #99cc00;padding-left:14px;">函数式组件</div>

    更多点击

    之前创建的锚点标题组件是比较简单,没有管理任何状态,也没有监听任何传递给它的状态,也没有生命周期方法。实际上,它只是一个接受一些 prop 的函数。
    在这样的场景下,我们可以将组件标记为 functional,这意味它无状态 (没有响应式数据),也没有实例 (没有 this 上下文)。

    <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>
    
    image

    render()函数还是一个挺有意思的存在

    loash库

    resize-detector

    不知道在哪里看过一句话,码而不思则殆,思而不码还是殆

    相关文章

      网友评论

          本文标题:Vue-Cli 3.0从0 开始搭建项目(篇1)

          本文链接:https://www.haomeiwen.com/subject/brgfoqtx.html