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
- Modify the babel.config.js file and configure babel-plugin-import
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 barNProgress. Set (0.4)
– sets a percentageNProgress.inc()
— Increments by a littleNProgress.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 are
name
Field is rendered - Hide child routes
hideChildrenMenu
, to handle the “page on the child route, the menu is still highlighted” logic - Add the displayed meta information
meta
Icon/Title…
- Add flag bits to routes to filter the routing items that need to be rendered to the menu.
-
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.
-
.sync
The 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
- Insert the required chart components.
- Abstract configurable parameters.
- Optimization (anti-shaking)
- 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 called
wait
Call after millisecondsfunc
Methods. - To provide a
cancel
Method cancellations delayed function calls and the flush method is called immediately options.leading
And | oroptions.trailing
Decide how to trigger before and after the delay (note: call before wait or wait before call).
- This function is delayed since the last time it was called
-
created(){ this.resize = debounce(this.resize, 300)}Copy the code
- lodash/debounce
-
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}
- Deep listening: Performance consuming (Vue3 hijack entire object)
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 moduledelete 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.
- What is?
-
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
- request.js
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
- modules/form.js
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
-
import debounce from 'lodash/debounce' Copy the code
-
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
-
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?
-
Make sure the code is in ES6 format, i.e. Export, import
-
Json, set sideEffects
-
Make sure that tree-shaking’s functions have no side effects
-
Babelrc sets presets [[“env”, {“modules”: false}]] to disable module conversion and leave it to WebPack for modularization
-
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
- use
npm login
, log in to your NPM account; - use
npm publish
· Publish your own package to NPM; - Check whether the package you published was successful and go to another project to execute it
npm install
The name of the package you released was downloaded successfully.
Pay attention to
- 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;
- 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)