Initialize the project

  • Quickly build the project vue create ant-design-Vue-pro with vue-CLI

  • cd ant-design-vue-pro/

  • Installation necessary to rely on NPM I ant-design-Vue moment

  • Delete/initialize files that are not needed

    / / the clear └ ─ ─ SRC / ├ ─ ─ ─ the router / │ └ ─ ─ ─ index. The js ├ ─ ─ ─ views / │ └ ─ ─ ─ Home. Vue └ ─ ─ ─ App. VueCopy the code
  • The introduction of ant – design – vue

    import Antd from "ant-design-vue";
    import "ant-design-vue/dist/antd.css";
    Copy the code

    debugger

    import "ant-design-vue/dist/antd.less";
    
    / / an error
    Syntax Error:
    
    // https://github.com/ant-design/ant-motion/issues/44
      .bezierEasingMixin();
    
    // Solution: enable javascript
    css: {
      loaderOptions: {
        less: {
          loader: "less-loader".options: {
            javascriptEnabled: true,},},},},Copy the code

Introduce UI components as needed

import Button from "ant-design-vue/lib/button";
import "ant-design-vue/lib/button/style";
Copy the code
  • babel-plugin-import
    • Modify the babel.config.js file and configure babel-plugin-import
      module.exports = {
        presets: ["@vue/app"],
        +  plugins: [
        +    [
        +      "import",
        +      { libraryName: "ant-design-vue".libraryDirectory: "es".style: true} +] +]};Copy the code
    • src/main.js
      - import Button from 'ant-design-vue/lib/button';
      + import { Button } from 'ant-design-vue';
      - import 'ant-design-vue/dist/antd.css'
      Copy the code
    • bug
      // ❌ Cannot import import Antd from 'antd-design-vue globallyCopy the code

Highly scalable routing

  • Existing programs

    • Based on the configuration
    • Convention based: Wheels generate routes based on the file structure
  • component

    const routes = [
      {
        path: "/user".component: () = >
          import(/* webpackChunkName: user */ "./component/RenderRouterView.vue"),
        children: [
          / /...],},];Copy the code
    const routes = [
      {
        path: "/user".component: { render: (h) = > h("router-view")},children: [
          / /...],},];Copy the code
  • NProgress

    • NProgress.start()— Shows the Progress bar
    • NProgress. Set (0.4)– sets a percentage
    • NProgress.inc()— Increments by a little
    • NProgress.done()– of the progress

Dynamically changing page layout

  • Transfer configuration variables through routes

How to combine menus and routes

  • convention

    • Add flag bits to routes to filter the routing items that need to be rendered to the menu.hideInMenu: true
    • Handles embedded routines in routes by logic,conventionThere arenameField is rendered
    • Hide child routeshideChildrenMenu, to handle the “page on the child route, the menu is still highlighted” logic
    • Add the displayed meta informationmetaIcon/Title…
  • Dynamic menus are generated by convention

    const menuData = getMenuData(this.$router.options.routes);
    getMenuData(routes){}Copy the code
  • Render processed Routes objects using functional components (stateless, only taking arguments) + component recursion.

  • .syncThe modifier

    • In some cases, we may need to “bi-bind” a prop. Unfortunately, true bidirectional binding can cause maintenance problems, because children can change their parents, and there is no obvious source of change in either parent or child.
    • This is why we recommend the pattern trigger event of Update :myPropName instead.
    • For example, in a hypothetical component containing a title prop, we can express the intent to assign a new value to it in the following way:
      • this.$emit('update:title', newTitle)
      • The parent component
        <text-document
          v-bind:title="doc.title"
          v-on:update:title="doc.title = $event"
        ></text-document>
        Copy the code
    • For convenience, we provide an abbreviation for this pattern, the.sync modifier:
      <text-document v-bind:title.sync="doc.title"></text-document>
      Copy the code

How do I use routes to manage rights

  • Permission verification related functions

    export async function getCurrentAuthority() {
      const { role } = await this.$axios.$get("/user");
      return ["admin"];
    }
    
    // The some() method tests whether at least one element in the array passes the provided function test. It returns a value of type Boolean.
    export function check(authority) {
      const current = getCurrentAuthority();
      return current.some((item) = > authority.includes(item));
    }
    
    export function isLogin() {
      const current = getCurrentAuthority();
      return current && current[0]! = ="guest";
    }
    Copy the code
  • Routing guard

    import findLast from "lodash/findLast";
    import { check, isLogin } from "utils/auth";
    router.beforeEach((to, from, next) = > {
      // ...
      const record = findLast(to.matched, (item) = > item.meta.authority);
      if(record && ! check(record.meta.authority)) {if(! isLogin() && to.path ! = ="/user/login") {
          next({ path: "/user/login" });
        } else if(to.path ! = ="/ 403") {
          next({ path: "/ 403" });
        }
        // loading = false
        // ...
      }
      // ...
    });
    Copy the code
  • Sidebar Authentication

    routes.forEach((item) = > {
      if(item.meta && item.meta.authority && ! check(item.meta.authority)) {return; }});Copy the code
  • 403 Add a pop-up notification

    import { notifiction } from "ant-deisgn-vue";
    if(to.path ! = ="/ 403") {
      notifiction.error({
        message: "403".description: "You do not have permission to access this page, please contact your administrator."}); next({path: "/ 403" });
    }
    Copy the code

More sophisticated permission design (permission components, permission directives)

  • Permission component – Functional component

    export default {
      functional: true.render: function (h, context) {
        const { props, scopeSlots } = context;
        return check(props.authority) ? scopeSlots.default() : null; }};Copy the code
  • Permission directives – plug-in

    export function install(Vue, options = {}) {
      const { name = "auth" } = options;
      Vue.directive(name, {
        // When the bound element is inserted into the DOM...
        inserted: function (el, binding) {
          if(! check(binding.value)) { el.parentNode && el.parentNode.removeChild(el); }}}); }Copy the code
  • To compare

    • After the directive is removed, an EL cannot be added again when the permission changes dynamically.
    • Component responses are more flexible, but use requires nested target EL.

How to use it in a componentECharts,AntvAnd other third-party libraries

  • vue-echarts

    1. Insert the required chart components.
    2. Abstract configurable parameters.
    3. Optimization (anti-shaking)
    4. Add more requirements (dynamically change data)
  • Echart render width beyond container?

    • Because Echart gets the height before the actual render is done.
    • Solution:
      • import { addListener, removeListener } from 'resize-detector'
  • When resize is used, add the stabilization

    • lodash/debounce
      • This function is delayed since the last time it was calledwaitCall after millisecondsfunc Methods.
      • To provide acancelMethod cancellations delayed function calls and the flush method is called immediately
      • options.leadingAnd | oroptions.trailingDecide how to trigger before and after the delay (note: call before wait or wait before call).
    • created(){
        this.resize = debounce(this.resize, 300)}Copy the code
  • Listen for option changes

    • Deep listening: Performance consuming (Vue3 hijack entire object)
      export default {
        watch: {
          option: {
            handler: () = > {},
            deep: true,}}};Copy the code
    • Manually replace the entire object

      option = {... option}

How can I develop efficiently with Mock data

  • Stripping mock data and business code
    • axios npm
    • Configuration webpack/devserver
  • Mock data not updated: clears the specified module cache
    • require.cache: Imported modules are cached in this object.
    • require.resolve: In Node, you can use require.resolve to query the full path of a module
    • delete require.cache[require.resolve(name)]
  • module.exports = {
      devServer: {
        proxy: {
          "/api": {
            target: "http://localhost:8081".bypass: function (req, res) {
              if (req.headers.accept.indexOf("html")! = = -1) {
                console.log("Skipping proxy for browser request.");
                return "/index.html";
              } else {
                // Look for files by convention
                const name = req.path.split("/api/") [1].split("/").join("_");
                const mock = require(`./mock/${name}`);
                const result = mock(req.method);
                // Clear the module cache
                require.cache(require.resolve(`./mock/${name}`));
                returnres.send(result); }},},},},},},};Copy the code

How to interact with the server (Axios)

  • MOCK the environment variable

    • cross-env

      • What is?

        Run scripts that set up and use environment variables (environment variables in Node) across platforms.

      • Why?

        Context When you configure environment variables, the configuration methods vary in different environments. For example, configure environment variables in Windows and Linux.

    • package.json

    • {
        "scripts": {
          "serve:no-mock": "cross-env MOCK=NONE "}}Copy the code
      const app = new (require("koa"()));const mount = require("koa-mount");
      
      app.use(
        mount("/api/dashboard/chart".async (ctx) => {
          ctx.body = [10.20.30.40.50]; })); app.listen(8081);
      Copy the code
    Copy the code
  • Axios interception: Secondary encapsulation, unified error handling

    • request.js
      import axios from "axios";
      function request(options) {
        return axios(options)
          .then((res) = > {
            return res;
          })
          .catch((error) = > {
            const {
              response: { status, statusText },
            } = error;
            notifiction.error({
              message: status,
              describtion: statusText,
            });
            return Promise.reject(error);
          });
      }
      Copy the code
    • Vue.prototype.$request = request
    • jsx: @vue/babel-preset-jsx

Create a step-by-step form

  • Vuex: Temporarily stores form data
    • modules/form.js
      const state = () = > ({ step: { payAccount: ""}});const mutation = {
        saveStepFormData(state, payload) {
          state.step = { ...state.step, ...payload };
        },
      };
      const actions = {
        async submitStepForm({ commit }, payload) {
          await request({ method: "POST".url: "".data: payload });
          // Shouldn't the form be empty?
          commit("saveStepFormData", payload);
          router.push(""); }};export default {
        namespaced: true,
        state,
        mutations,
        actions,
      };
      Copy the code

How do I manage ICONS in the system

  • fromiconfont
    import { Icon } from "ant-design-vue";
    const IconFont = Icon.createFromIconfontCN({ scriptUrl: "" });
    Copy the code
    <icon-font type="icon-404" />
    Copy the code
  • svg
    • <image url>
    • Manually register the Component/convert it to a Component using the SVG-Loader
  • View vUE CLI internal configuration vue inspect > output.js

How to customize themes and dynamically switch themes

  • Global: config configuration

    module.exports = {
      css: {
        loaderOption: {
          less: {
            modifyVars: {
              "primary-color": "#1DA57A"."link-color": "#1DA57A"."border-radius-base": "2px",},},},},},};Copy the code
  • Local: Depth action selector

    If you want one of the selectors in the scoped style to work “deeper”, such as affecting subcomponents, you can use the >>> operator:

    <style scoped>
    .a >>> .b { / *... * / }
    </style>
    Copy the code
  • Compile topic colors dynamically online

    • The performance,
    • If desired, you can compile several theme style files locally and pull them from the server
    • antd-theme-webpack-plugin
      • The WebPack plug-in is used to generate color-specific LESS/CSS and inject it into the index.html file so that you can change Ant Design-specific color themes in your browser.

internationalization

  • Antd – VUE component library internationalization: localProvider -> configProvider

    <template>
      <div id="app">
        <a-config-provider :locale="locale"> </a-config-provider>
      </div>
    </template>
    Copy the code
    import zhCN from "ant-design-vue/lib/locale-provider/zh_CN";
    import enUS from "ant-design-vue/lib/locale-provider/en_US";
    
    export default = {
      data(){
        return {
          locale: enUS
        }
      },
      watch: {"$route.query.locale"(val){
          this.locale = val === 'enUS'? enUS : zhCN
        }
      }
    }
    Copy the code
  • My moment of internationalization

     import moment from 'moment';
     export default= {watch: {"$route.query.locale"(val){
          moment.locale(val==='enUS'?'en':'zh_cn'); }}}Copy the code
  • Internationalization of business code: VueI18n

    • main.js

      import VueI18n from "vue-i18n";
      import zhCN from "./locale/zhCN";
      import enUS from "./locale/enUS";
      import queryString from "query-string";
      
      const i18n = new VueI18n({
        locale: queryString.parse(location.search).locale || "zhCN".message: {
          zhCN: {
            message: zhCN,
          },
          enUS: {
            message: enUS,
          },
        },
      });
      
      new Vue({
        router,
        store,
        i18n,
        render: (h) = > h(App),
      }).$mount("#app");
      Copy the code
    • zhCN.js / enUS.js

      export default {
        "app.workspace.title": "Time"};Copy the code
      export default {
        "app.workspace.title": "TIME"};Copy the code
    • workspace.vue

      <template> {{$t('message')['app.workspace.title']}} </template>
      Copy the code
    • handleLocale

      export default {
        watch: {
          "$route.query.locale"(val) {
            this.$i18n.locale = val; ,}}};Copy the code

How to build packages efficiently

Package analysis report :(VUE CLI) NPM run build — –report

  • UI components are loaded on demand/Babel

  • The webpackChunkName is used on the router to lazily load and unpack routes.

  • Introduce Lodash on demand

    1. import debounce from  'lodash/debounce'
      Copy the code
    2. Use the plugin lodash-webpack-plugin

      npm i lodash-webpack-plugin babel-plugin-lodash -D
      Copy the code

      babel.config.js

      module.exports = {
        presets: ["@vue/cli-plugin-babel/preset"."@vue/babel-preset-jsx"].plugins: ["lodash"]};Copy the code

      vue.config.js

      const LodashModuleReplacementPlugin = require("lodash-webpack-plugin");
      module.exports = {
        chainWebpack: (config) = > {
          config
            .plugin("loadshReplace")
            .use(newLodashModuleReplacementPlugin()); }};Copy the code
    3. Lodash – es combining tree – shaking

      import { debounce } from 'lodash-es'
      Copy the code

      The role of Tree-shaking to remove dead code that is not referenced in the context

      It is safe to do shaking only when a function gives input and produces output without modifying anything external

      How to usetree-shaking?

      1. Make sure the code is in ES6 format, i.e. Export, import

      2. Json, set sideEffects

      3. Make sure that tree-shaking’s functions have no side effects

      4. Babelrc sets presets [[“env”, {“modules”: false}]] to disable module conversion and leave it to WebPack for modularization

      5. Combined with uglifyjs webpack — the plugin

How do I build an interactive component document

  • raw-loader + highlightjs main.js
    import hljs from "highlight.js";
    import "highlight.js/styles/github.css";
    Vue.use(hljs.vuePlugin);
    Copy the code

    view.vue

    <highlightjs language="javascript" :code="ChartCode" />
    Copy the code
  • Write your own loader: such as MD-Loader (high cost)

How to unit test components

  • auth.spec.js

    import { authCurrent, check } from "@/utils/auth.js";
    
    describe("auth test".() = > {
      it("empty auth".() = > {
        authCurrent.splice(0, authCurrent.length);
        expect(check(["user"])).toBe(false);
        expect(check(["admin"])).toBe(false);
      });
    });
    Copy the code
  • jest.config.js

    module.exports = {
      preset: "@vue/cli-plugin-unit-jest".moduleNameMapper: {
        "^ @ / (. *) $": "<rootDir>/src/$1",},resolver: null.collectCoverage: process.env.COVERAGE === "true".collectCoverageFrom: ["src/**/*.{js,vue}".! "" **/node_modules/**"]};Copy the code

How do I publish components to NPM

  • Register NPM account, fill in user name, password and email;
  • Go to the project folder
  • usenpm login, log in to your NPM account;
  • usenpm publish· Publish your own package to NPM;
  • Check whether the package you published was successful and go to another project to execute itnpm installThe name of the package you released was downloaded successfully.

Pay attention to

  1. Before publishing your own package, you should first go to the NPM official website to search whether the package name you want to publish already exists, the existing package name will fail to submit;
  2. When you update your own published package, you need to change the version to package.json every time, for example, from 1.0.0 to 1.0.1. Then perform an NPM Publish update.

GitHub related ecological applications (CI continuous integration, bike coverage, document publishing, issue management)

  • CI Continuous integration
    • travis-ci.org/
    • circleci.com/
  • Single test coverage (report as an important reference for user selection)
    • coveralls.io/
    • about.codecov.io/
  • Document hosting
    • github.io
    • gitee.io
    • www.netlify.com/
  • Manage issues (bugs & feature requests)
    • Github.com/offu/close-… (Automatically close the issue)
    • Vuecomponent. Making. IO/issue – helpe… (Issue template)
    • Github.com/dessant/loc… (Lock closed issue)