From the front-end perspective, Vue can be said to be the most ideal front-end MVVM framework at present. Everything serves the interface and is difficult to get started. This article will record the process of using Vue family bucket (Vue+Vue-router+Vuex) to reconstruct a jQuery+template project and the gains during the period.
getting Started
Vue's official document is the best tutorial for learning Vue. None of them, maybe because the framework author is a design background and has no back-end background, various abstract concepts can be explained in the most easy-to-understand way in Vue. Here we will briefly introduce the concepts of Vue, Vue-router, and Vuex. We need to learn comprehensively and recommend it.Official documentation.
Vue
The core function of Vue is two-way binding, which can automatically realize interface-driven data changes and data-driven interface changes, which can greatly reduce the development cost of front-end rich interactive applications. There is more than one similar framework, but the implementation of Vue has certain performance advantages with the help of ES5 native features.
Vue-router
Vue-router is an official route that organizes the mapping relationship between URLs and components, and automatically responds to changes in URLs to components, so that developers only need to focus on component development, and routing helps you solve related trivial problems.
Vuex
Vuex provides a centralized data management model to deal with complex data flow conditions. For example, multiple components share data but each of them is in charge, which may cause the synchronized data to be not synchronized, or because the hook of the Object object in js points to the same instance in memory, once the original data is operated, it will pollute other components. At this time, a more organized data operation mode is needed, that is Vuex.
Technical selection
Compare with jQuery
After understanding the basic concepts of Vue, I will definitely compare them with the jQuery technology stack unconsciously, wanting to know whether these things are really necessary for my business.
First of all, can the problem solved by MVVM be solved using jQuery? The answer is yes. Do you remember to use jQuery to get the value from one input after another when submitting the form? This is interface-driven data; if you have done any asynchronous interaction function, you should have had the experience of using jQuery to fill Ajax data into various elements in the interface, and this is the data-driven interface. Although it can be done, it is a bit cumbersome. Even if you use the form verification plug-in and the front-end template engine, you still need to manually call the verification method and rendering method on each running node. It is okay to make a website page, but when the requirements are complex to a certain extent, this will be a huge burden.
Then there is routing. The essence of routing is to implement interface switching and interface maintenance through operation of urls. A single-page application is essential. This actually has nothing to do with the technology stack. As long as routing needs are generated, even projects based on jQuery will only create a route. However, in the jQuery era, there are few single-page applications.
Vuex is something that is extended based on two-way binding. It is equivalent to adding a broker between the data and the component. The component cannot directly operate the data. It can only submit operation requirements like the broker, and the broker implements the operation to solve various unpredictable problems caused by the complexity of people. The data is moved out of the application and a store is specially established, which eliminates the problem of data pollution between components. jQuery should be said to have little need, because jQuery operates data manually and there is no unexpected situation at all.
Applicable scenarios
After comparing with jQuery, the applicable scenario of Vue is very obvious. From a development perspective, the more complex the interaction, the more suitable the project, the more suitable it is. Single page is the most suitable, and content websites are the least suitable. If there are demands for individual pages in the website, you can also use them locally, such as shopping cart pages.
Of course, all this must be based on the premise that it is incompatible with IE8. I am a little confused about this because I see that some 2C sites are using Vue. How do these front-end ers fool the boss?
Project Analysis
Project background
The project refactored this time is a front-end component management system developed for the previous company. The project was chosen to refactor because it is familiar with the needs. This is a typical single-page application and has a moderate complexity, which is more suitable for use as a starting exercise.
The project background is in an outsourcing website building company. A large number of reusable components have been accumulated in the design link. Designers often only need to fine-tune the components to piece together the page and deliver it to the front end. Theoretically, these components can also be reused on the front end, but in fact, the front end has to re-implement the entire page every time, which wastes a lot of manpower.
Functional Requirements
The idea of this project is to develop all components and enter them into a platform for management. The designer can select components on the platform and preview and adjust components in real time. What you see in the whole process is what you get. The platform will generate a string of code from the adjustment results. As long as the code is handed over to the front-end, this string of code can be used to reproduce the modified components of the designer on the platform, and can copy the component's html/css/js code with one click, quickly apply it to the project, so that the front-end development cost of the component part is close to zero. The platform needs to implement the following functions:
- Management components, supporting classification, search, sorting
- Display components, support online preview/editing of components
- Component handover, support for generating component code and reproducing components based on code
- Usage statistics support the use of components, and facilitate further optimization of components
Functional Analysis
The first version is implemented using jQuery+template. This technology stack is too flexible. The advantage is that it is easy to do whatever needs, and the disadvantage is that it can do whatever it wants. It is not conducive to clarifying the ideas and is often accompanied by changes while doing it.
Components are placed in a widgets/ folder, and are called component libraries. Because they are pure front-end projects that do not have file operation capabilities, the component's reading depends on a static json file. This file acts as a directory of component library, including component classification, label, name, date and other information. The data structure is roughly like this:
[{ "title": "Navigation Class", "list": [{ "widget": "bread-1", "title": "Icon Breadcrumbs", "tag": "Breadcrumbs/icons", "author": "UI", "date": "2015-06-04" }, ...] }, ...]
Components are stored in the component library in the form of columns/numbered secondary folders, and it is agreed to use the storage directory as the component code. For example, component bread-1 means that the component storage address is widgets/bread/1/ folder.
Of course, the internal file structure of the component must also be agreed upon, as follows:
widgets |-bread |-1 |- //Thumbnail |- //Configuration file |- //Script template |- //Style template `- //Interface template
With these agreements, the program can obtain information about all components through directory files, and the acquisition, display and retrieval of components can be achieved.
The most critical thing in the component is the file, which contains the configurable items and their default values of the component. The platform will read this configuration file when displaying the component and generate a configuration panel based on the configuration information. This can define all variables in the component interface, style, and script. The configuration file is roughly like this:
{ "cssConfig": { "fontSize": { "name": "Font Size", "value": "12px", "type": "text" }, ... }, "jsConfig": { ... }, "showConfig": { "viewWidth": { "name": "Grid Width", "value": 12, "type": "number" }, ... } }
The three branches of cssConfig, showConfig, and jsConfig in the configuration file are all the variables that can be modified in the component. To apply these variables to the component, you need to use the front-end template engine. Therefore, the three major components of the component are written in template syntax when developing. After the template engine parsing, you can get the configured actual html/css/js content. For example, the style template is roughly like this:
.widget-bread-1 { font-size: ${}; color: ${}; } .widget-bread-1 a { color: ${}; } .widget-bread-1 a:hover{ color:${}; } .widget-bread-1 .ion { font-size: ${}; margin: 0 ${}; }
After obtaining the actual code of the component, just insert the result into the page and update it in time. HTML and css can directly replace the text content. Because js is introduced in modularity, replacing the module only does not overload the module. The entire module must be renamed and replaced as a whole. Therefore, the name of the js module is random.
There will be a problem here. Some components need to be used multiple times on the page, so the js selector of this component will conflict. The solution to this problem can be done by the random name of the js module. We agree that in component development, the id is used as a reserved variable, and the platform will automatically assign a random string. This string is the same inside the component instance, and it will be different after multiple calls. In this way, as long as ${id} is used as the id or class of the component's parent node, the selector conflict problem can be solved. It can also be used as the component's css namespace, so that the possible css naming conflicts can also be resolved invisibly.
The above are the core functions of the project.
In addition, localStorage is used as a storage method to implement stand-alone version data statistics, which can collect the current browser component usage records and the configuration status of each use. This is mainly for local storage operations, but the project itself also uses front-end templates. Add component templates to the first load, and localStorage will be cached after the first load. The cache strategies of these contents are different. User data should be permanently stored, and the project templates should be manually updated. The component templates need to be determined according to the situation. If there is too much stored content, it needs to be cleaned. It is unrealistic to delete them one by one during cleaning. All deletion may accidentally harm the storage of other applications. The method here is to encapsulate the localStorage operation. The storage method will add a special prefix before the key. When deleting, just traverse the local stored key and determine whether it matches the prefix, you will know whether it is a storage in the application. The corresponding value method must also reversely prefix the key and then get the value.
In addition, localStorage only supports string access. In order to facilitate our access to object types, the encapsulation method also supports automatic conversion. However, this conversion cannot be blindly converted to characters when encountering objects. When the value is matched, the object will be automatically converted. Because sometimes the user may really save an object string and enter it. When the object is taken out, it also hopes to get it back as it is. To solve this problem, it needs to make a small hack. When the storage method detects that the value is an object, it will be converted into a string and then spelled a marking string in front. The value method will only restore the subsequent string to an object after detecting this identifier. Although this method can meet the needs, it is not very safe, because this prefix is fixed, and in theory, it is always possible to encounter winning prizes. I wonder if there are any other better solutions to this problem.
These are the main functions of the project.
Reconstruction
A refactoring
The first refactoring only used Vue. The first thing I experienced during the refactoring process was various conveniences. I originally wanted to call the template engine to do the framework. I originally wanted to bind events in js and now I can bind directly in the template, and there are various other syntax sugars.
Of course, the most important thing is two-way binding. Based on two-way binding, the interface and data can be automatically correlated, making people feel that the program has a certain degree of autonomy, but in order for this autonomy to run normally, developers must plan every step in advance, which will appear less free than jQuery. Take bricks for example. jQuery is like a particularly flexible crane that can lift heavy weights and move bricks in a fancy way; Vue is like a universal remote control, you tell him that you want to move bricks from a certain place to a certain place, and how to deal with what happens during the period. Press the button to automatically move bricks.
The two methods have their own advantages and disadvantages. If the crane is good, it can be very flexible. It is easy to avoid pits on the road. The disadvantage is that you have to drive it one by one; the button can be programmed and automatically run at one time. The disadvantage is that you must inspect the pits on the road in advance, schedule all other cars, and explain all the situations clearly, otherwise you will overturn or crash. You will definitely feel this sense of restraint when you switch from jQuery to Vue. You must "plan and move" and you cannot get on the car first.
A large part of the work during the reconstruction period is to establish Vue instances, collect data scattered in all corners of JS into data, concentrate the process of operating data into methods bit by bit, and concentrate the data filtering process into computed. This whole process can clearly review every implementation details and reflect whether each implementation method is reasonable. In fact, it is to summarize the original crane process into remote control buttons one by one. After all the summary is completed, the Vue example becomes our final project and can be automatically run.
After reconstruction, relying on various functions of Vue, the amount of code in the logical part has been reduced. In addition, there is no improvement to the project itself. The problem of loss of refreshing page status still exists because there is no route. Because there is no data pollution pitfall without Vuex, it can only be solved with deep copy; and the component-based development model makes the code organization more fragmented, and these problems require secondary reconstruction.
Secondary reconstruction
The goal of secondary reconstruction is to improve routing, Vuex, code organization, and Wild Dog Cloud backend.
Although I have the experience of the first reconstruction, the secondary reconstruction was still a little confused at the beginning. Which one should I use for routing or Vuex first? After thinking about it, the route does "demolition" and Vuex does "demolition". I feel that the workload of demolition will be smaller after the modification, so I go to Vuex first.
The concept of Vuex is a bit abstract, but once you use it, you feel it is easy to use. Moreover, this thing is not like routing, and it can be used without any distinction between scenarios. The problem of data pollution after Vuex is naturally solved. Moreover, the action => mutation => store process brought by Vuex will really make things simple once it is accepted. The process of introducing Vuex is basically transferring data to the store and scattering data operations into actions, getters, mutations. At the same time, many synchronous data operations are no longer needed, which reduces the amount of code.
After that, we started to introduce routes. At the beginning, we were not sure how to divide the views. The large views must be login, registration, and main interfaces. The problem is whether the main interface needs to be further subdivided. Theoretically, it can be divided very finely. However, based on the actual application scenarios, it was found that the interface switching is relatively frequent, and the overhead of frequent loading and unloading of components will be very high. Moreover, when we disassemble the closely coupled components into different views, a lot of status information is required, which is a bit unworthy of the loss. In the end, we gave up and did not continue to divide the main view. Considering that the access overlap of the three views is not high, it is natural that the components need to be loaded asynchronously, and the components are loaded only when they are accessed. Vue itself supports asynchronous components, so this matter becomes very simple. As long as you can return a promise, you can obtain components in any way.
Next, we need to connect to Wild Dog Cloud to realize real user management and data statistics. Wild Dog Cloud can provide a series of functions such as user authentication and data storage. Through it, we only need to use js to develop a complete WEB application. In this way, all previous operations on localStorage must be changed to operations on Wild Dog Cloud, and the data will become more reliable when it reaches the cloud.
At this point, the secondary reconstruction has been completed. The overall business code feels reduced a lot, but the total code volume is estimated to be quite large. After all, three framework files have been added. However, after repeated splits, the number of files has changed from three or two js to more than ten js. Seajs is used instead of webpack in modularity, because I still have a wait-and-see attitude towards webpack, and I still don’t feel the necessity of using it. The key is that the code developed based on webpack will be mixed with a lot of private goods, making your code unnative and cannot run without it. I cannot accept this. Moreover, seajs and local cache are more advantageous than webpack in multi-page scenarios. Of course, their differences are the same as the difference between jQuery and Vue. The essence is not the same thing. The key lies in the usage scenario, and the suitable one is the best.
postscript
After two refactoring practices and pitfalls, I have a deeper understanding of the Vue framework. Vue wants to use it flexibly and freely, and has a minimum requirement for the developer's project architecture capabilities. If Vue is to be introduced to the underlying layer, there is also a minimum requirement for the infrastructure builder's planning capabilities. These are not available in the jQuery technology stack. The process of using Vue is also a process of accepting these constraints. They can guide developers to establish their own rules system. This is a good thing and the general trend. After all, true freedom only exists in the rules.
See the full code of this articleGithub。
The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.