How to write code more elegantly when developing drag and drop visualization projects recently
How can I reduce GIT conflicts and duplicate code import files in a multi-party project
// Inject the file
const moduleFiles = require.context('./src/route'.true./\.js$/)
const modules = moduleFiles.keys().reduce((modules, path) = > {
const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/.'$1')
const value = moduleFiles(path)
module[moduleName] = value.default
return modules
}, {})
export default modules
Copy the code
Those of you who are developing the front end know that when we use require to import some resources, the path can’t be a dynamic variable, it has to be a template string or an addition. Actually, this is not a problem with the framework you use, it’s a problem with webpack, it can’t dynamically resolve a variable. If you use a template string or a plus sign, it’s because it imports resources from this folder
Zhihu address: www.zhihu.com/question/42…
How can I be more elegant when encapsulating classes
// For example, when we encapsulate a class, we often need to use chain calls
class Map {
constructor() {
this.mapList = []
}
addCom(comName){
this.mapList.push({
comName,
styleList: [].dataList: []})return this
}
addComData(comName, comDataName, path) {
for (const com of this.mapList) {
if (com.comName === comName) {
com.dataList.push({
name: comDataName,
path
})
}
}
return new Add()
}
addStyleCom(comName, comStyleName, path) {
for (const com of this.mapList) {
if (com.comName === comName) {
com.dataList.push({
name: comStyleName,
path
})
}
}
return this
}
getComList() {
console.log(this.comList)
return this.comList
}
}
// The usage mode
const map = new Map()
map.addCom('test')
.addComData('test'.'testData'.'./src/components/test/data.vue')
.addStyleCom('test'.'testStyle1'.'./src/components/test/style1.vue')
.addStyleCom('test'.'testStyle2'.'./src/components/test/style2.vue')
Copy the code
If you think about it a little bit more elegantly, passing the same arguments every time
Well, let’s do it gracefully
class Map {
constructor() {
this.comList = []
}
addCom(comName) {
this.comList.push({
comName,
comDataList: [].comStyleList: []})return {
addComData: this.addComData.bind(this, comName),
addComStyle: this.addComStyle.bind(this, comName)
}
}
addComData(comName, name, path) {
for (const com of this.comList) {
if (com.comName === comName) {
com.comDataList.push({
name,
path
})
}
}
return {
addComStyle: this.addComStyle.bind(this, comName)
}
}
addComStyle(comName, name, path) {
for (const com of this.comList) {
if (com.comName === comName) {
com.comStyleList.push({
name,
path
})
}
}
return {
addComStyle: this.addComStyle.bind(this, comName)
}
}
getComList() {
console.log(this.comList)
return this.comList
}
}
const map = new Map()
map.addCom('test')
.addComData('testComData'.'./src/components/test/data.vue')
.addComStyle('testComStyle1'.'./src/components/test/style1.vue')
.addComStyle('testComStyle2'.'./src/components/test/style2.vue')
map.addCom('test1')
.addComData('testComData'.'./src/components/test/data.vue')
.addComStyle('testComStyle1'.'./src/components/test/style1.vue')
.addComStyle('testComStyle2'.'./src/components/test/style2.vue')
map.getComList()
Copy the code
Of course, another solution is to return a subclass in retune and pass in comName when instantiating the subclass
Code sample
class Add {
constructor(comName, comList) {
this.comName = comName
this.comList = comList
}
_addComData(name, path) {
for (const com of this.comList) {
if (com.comName === this.comName) {
com.comDataList.push({
name,
path
})
}
}
return this
}
_ddComStyle(name, path) {
for (const com of this.comList) {
if (com.comName === this.comName) {
com.comStyleList.push({
name,
path
})
}
}
return this}}class Map {
constructor() {
this.comList = []
}
addCom(comName) {
this.comList.push({
comName,
comDataList: [].comStyleList: []})return new Add(comName, this.comList)
}
getComList() {
return this.comList
}
}
const map = new Map()
map
.addCom('test')
._addComData('data.vue'.'/xxx/xxx')
._ddComStyle('style1.vue'.'/xxx/xxx')
._ddComStyle('style2.vue'.'/xxx/xxx')
map
.addCom('jen')
._addComData('data.vue'.'/xxx/xxx')
._ddComStyle('style1.vue'.'/xxx/xxx')
._ddComStyle('style2.vue'.'/xxx/xxx')
const mapList = map.getComList()
console.log(mapList)
Copy the code
Of course this code isn’t elegant enough, but if you’re familiar with the back end, or the front end of Typescript, you already know about function overloading, so there are more elegant ways to override functions to make your code more elegant
What is function overloading
When a function or method has the same name but different argument lists, such functions or methods with the same name and different arguments are called overloaded functions or methods.
There is no such thing as overloading in JavaScript, but you can tell by arguments.length
function heavyLoad() {
if (arguments.length === 1) {
console.log('One parameter')}if (arguments.length === 2) {
console.log('Two arguments')}// ...
}
Copy the code
This way we can implement function overloading, but this does not meet our needs
Classic example (from Nuggets article)
Let’s start with a requirement, we have a Users object, the Users object values property has some names, a name has two parts
[last-name] [first-name] [last-name] [last-name] [last-name
const users = {
values: ["Dean Edwards"."Alex Russell"."Dean Tom"]}// We will add a method to the Users object
// Return the whole users.values when no arguments are worn
// When passing a parameter, we match first-name with the parameter when the element is returned
// When two arguments are passed, both first-name and last-name are matched when the element is returned
function addMethod(object, name, callback) {
// Add the original object[name] method to the object
const old = object[name]
// Redefine the object[name] method
object[name] = function () {
// If the function needs the same number of arguments as it actually passed, it calls fn directly
if (callback.length === arguments.length) {
return callback.apply(this.arguments)}else if (typeof old === 'function') {
// If not, determine if old is a function
return old.apply(this.arguments)}}}The addMethod function takes three arguments
// First: the method object to bind
// Second: binding method name
// Third: the method that needs to be bound
// The addMethod function not only determines the length of the parameter, but also determines the length attribute of the function definition (which defines several parameters).
// Next we use the addMethod method
// Do not pass parameters
function find0() {
// TODO
return console.log('Return all')}// Pass a parameter
function find1(arg1) {
// TODO
return console.log('Return matched')}// Pass two arguments
function find2(arg1, arg2) {
// TODO
return console.log('Return head and tail')
}
addMethod(users, 'find', find0)
addMethod(users, 'find', find1)
addMethod(users, 'find', find2)
Copy the code
So that’s how you can overload functions
Every time addMethod is called, it overwrites the previous method, but old stores the previous method, and when the parameter is passed in, it goes back to old to find the method that was overwritten last time. The scope is actually preserved using closures
So let’s do it this way
class Map {
constructor() {
this.comMap = {
comList: []}}_init(object) {
Map.addMethod(object, 'addComData'.this.addComData)
Map.addMethod(object, 'addComData'.this.addComDataByComName)
Map.addMethod(object, 'addComStyle'.this.addComStyle)
Map.addMethod(object, 'addComStyle'.this.addComStyleByComName)
}
addCom(comName) {
const name = comName
return (function (that) {
const com = {
comName: name,
comDataList: [].comStyleList: []
}
that.comMap.comList.push(com)
that._init(com)
return com
})(this)}static addMethod(object, fnName, callback) {
const old = object[fnName]
object[fnName] = function () {
if (callback.length === arguments.length) {
return callback.apply(this.arguments)}else {
return old.apply(this.arguments)}}}addComData(name, path) {
console.log(this.comName)
console.log('addComData -- I didn't pass comName')}addComStyle(name, path) {
console.log(this.comName)
console.log('addComStyle - I didn't pass comName')}addComDataByComName(comName, name, path) {
// TODO
console.log('addComDataByComName')}addComStyleByComName(comName, name, path) {
// TODO
console.log('addComStyleByComName')}getComList() {
console.log(this.comMap)
}
}
const map = new Map(a)const list = map.addCom('test')
list.addComData(1.2)
const list1 = map.addCom('jen')
map.getComList()
Copy the code
In summary, the second method is better, and the third method produces a closure every time it is executed
About Code Splitting
If there is too much code, split mixins or separate them into common JS files to keep the code clean and unified
About VUE communication
- Parent-child communication: the parent passes data to the child through props and the child passes data to the parent through events (emit). Can also communicate via parent/child chain (EMIT); Can also communicate via parent/child chain (EMIT); Communication is also possible through parent/child chains (parent/children); Ref can also access component instances; Dojo.provide/injectAPI; The children); Ref can also access component instances; Provide/inject API; The children); Ref can also access component instances; Dojo.provide/injectAPI; attrs/$listeners
- Brother communication: Bus; Vuex
- Cross-level communication: Bus; Vuex; Dojo.provide/inject API, attrs/attrs/attrs/listeners
The importance of a unified approach
In real projects, where requirement changes are quite common, what about reducing global changes due to requirement changes?
A couple of suggestions
- Global unification of variables
- Function independence
- Single component function
In fact, the summary is that
High cohesion, low coupling reduced because other factors cause you to rewrite your code, or even refactor it, to make your code extensible
For the API layer multi-interface caching implementation, see next time. Consider the typescript version
About Subsequent updates
I can only say that I have been very busy recently, and there are a lot of things to learn. I may update some more practical contents in the future, such as how to use VUEX in the project, realize unified configuration, etc., or the analysis of some principles, etc. Please look forward to !!!!!