Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What are the problems in the Vue project?

2025-01-19 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article focuses on "what are the problems in the Vue project". Interested friends may wish to take a look. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn what are the problems in the Vue project.

The problem of passing parameters when the list enters the details page

For example, if you go to the product details page on the item list page, you need to send a product id.

Go to the detail page to copy the code

The path of the c page is http://localhost:8080/#/detail?id=1. You can see that a parameter id=1 has been passed, and the id will still exist even if the page is refreshed. At this point, you can get the corresponding detailed data through id on the c page. The way to get id is this.$route.query.id.

Vue parameter transfer methods include: query and params+ dynamic routing.

Tell the difference between the two:

1.query switches routes through path, and params switches routes through name

/ / query via path switch route to Detail page / / params via name switch route to Detail page copy code

2.query receives parameters through this.$route.query, and params receives parameters through this.$route.params.

/ / query receives parameter created () {const id = this.$route.query.id;} / / params through this.$route.query to receive parameter created () {const id = this.$route.params.id;} copy code through this.$route.params

Url presentation of parameters passed by 3.query: / detail?id=1&user=123&identity=1& more parameters

Url mode of params+ dynamic routing: / detail/123

4.params dynamic routing parameters must be defined in the route, and then parameters must be added when the route is redirected, otherwise it will be a blank page:

{path:'/ detail/:id', name: 'Detail', component: Detail}, copy the code

Note that when params passes parameters, it can be passed and received if the parameter is not defined in the route, but once the page is refreshed, this parameter no longer exists. This doesn't work for behaviors that rely on parameters to do something, because you can't ask users not to refresh the page. For example:

/ / in the defined route, only one id parameter {path: 'detail/:id', name:' Detail', components: Detail} / / template is defined. / / An id parameter and a token parameter / / id are already defined in the route. However, token does not define going to the Detail page / / receiving created () {/ / below on the details page can be obtained normally / / but after the page is refreshed, id can still be obtained, while token does not exist at this time const id = this.$route.params.id Const token = this.$route.params.token;} copy the code

The problem of local development environment requesting server interface to cross-domain

The above error report is no stranger to everyone, which means that there is no access (cross-domain problem). When a local development project requests a server interface, it causes cross-domain problems because of the same origin policy of the client.

The following is an example of a situation where local cross-domain is not configured:

As you can see, at this point we click to get data, and the browser prompts us to cross-domain. So we can't access the data.

So next, let's demonstrate how to set the cross-domain data acquisition:

Note: after configuration, be sure to close the original server and restart the npm run dev startup project. Or it won't work.

We set to allow local cross-domain in 1 out. In 2, note that when we access the interface, we write / api, where / api refers to the domain name of the interface we want to request. If we don't want to bring / api with each interface, we can change the default configuration of axios axios.defaults.baseURL ='/ api'; so that we can request the interface to this.$axios.get directly ('app.php?m=App&c=Index&a=index'), which is very simple. At this point, if you look at the xhr request in network, you will find that the request address of localhost:8080/api is displayed. It's not a big deal, it's just an agent:

All right, finally, attach the code of proxyTable:

ProxyTable: {/ / start with'/ api' Agent all requests to the target server'/ api': {target: 'http://jsonplaceholder.typicode.com', / / interface domain name changeOrigin: true, / / whether to enable cross-domain pathRewrite: {/ /' ^ / api':'}} copy code

Note: after configuration, be sure to close the original server and restart the npm run dev startup project. Or it won't work.

Unified management of axios encapsulation and api interface

The encapsulation of axios is mainly used to help us intercept requests and responses.

In the interception of requests, we can carry userToken,post request headers, qs serialization of post submission data, and so on.

In the interception of the response, we can deal with the error uniformly according to the status code, and so on.

The unified management of axios interface is a necessary process when doing a project. This makes it easy for us to manage our interface, and we don't have to go back to our business code to modify the interface when the interface is updated.

Since there is a little more content here, put it in another article and send a link here.

Demand loading of the UI library:

There are few reasons why we should use on-demand loading instead of introducing it all at once. Here we take the demand loading of vant as an example to demonstrate how to load the ui library in vue on demand:

Installation: cnpm i vant-S

Install the babel-plugin-import plug-in to load on demand: cnpm I babel-plugin-import-D

Add the plug-in configuration to the .babelrc file:

IbraryDirectory {"plugins": [/ / here is the original code / /. / / here is the code for us to configure ["import", {"libraryName": "vant", "libraryDirectory": "es", "style": true}]} copy code

Load the plug-ins you need on demand in main.js:

/ / introduce vant components import {DatetimePicker, Button, List} from 'vant'; copy code as needed

Use components:

/ / use vant component Vue.use (DatetimePicker) .use (Button) .use (List); copy the code

Finally, in the page, use:

Button copy code

Ps: in addition to vant libraries, such as antiUi, elementUi, etc., many ui libraries support on-demand loading. You can view the documentation, which will be mentioned above. Basically through the installation of babel-plugin-import plug-ins to support demand loading, using the same way as vant, you can use it.

How to gracefully override only the styles of components in the ui library in the current page

First of all, the styles of our vue files are written in tags, and scoped is added to make the styles valid only on the current page. So here's the problem. Look at the picture:

All styles we normally write are appended with the attribute [data-v-23d425f8] (as shown in 1), but the tags inside the third-party component are not compiled with the attribute [data-v-23d425f8]. So if we want to change the style of the component, there's nothing we can do about it. What to do, some partners write a class to the third-party component, then write a style tag without socped attribute in a public css file or on the current page, and then directly modify the style of the third-party component. This is an approach, but there are problems of global pollution and naming conflicts. By prescribing specific naming methods, naming conflicts can be avoided. But still not elegant enough.

As an excellent (strong) show (forced), how can this situation be allowed to happen? All right, here's an elegant solution:

It is solved by depth selector. For example, to modify the style of the van-ellipsis class in the component in the above figure, you can do this:

.van-tabs / deep/. Van-ellipsis {color: blue}; copy the code

The result of the compilation is:

In this way, the [data-v-23d425f8] attribute is not added to van-ellipsis as well. At this point you can happily modify the style of third-party components.

Of course, the depth selector / deep/ here is because I use the less language, if you do not use less/sass, etc., you can use the > > symbol.

More about depth selectors is described later in the article.

Timer problem:

I write a timing on page a, ask him to print a 1 per second, and then jump to page b, where you can see that the timer is still running. This is very performance-consuming. As shown in the following figure:

Solution 1:

First, I define the timer name in the data function:

Data () {return {timer: null / / timer name}}, copy the code

Then use the timer like this:

This.timer = (() = > {/ / some actions}, 1000) copy the code

Finally, clear the timer during the beforeDestroy () life cycle:

BeforeDestroy () {clearInterval (this.timer); this.timer = null;} copy the code

Plan 1 has two disadvantages, and to quote, it is:

It needs to save the timer in the component instance, and it's best that only lifecycle hooks can access it if possible. This is not a serious problem, but it can be regarded as sundries.

Our build code is independent of our cleanup code, which makes it more difficult for us to programmatically clean up everything we build.

Solution 2:

This method clears the timer through the position of the event listener $once after the timer is defined. The following is the complete code: const timer = setInterval (() = > {/ / some timer operations}, 500); / / listen for timers through $once, where the beforeDestroy hook can be cleared. This.$once ('hook:beforeDestroy', () = > {clearInterval (timer);}) copy the code

Option 2 thanks to the solution provided by @ zzx18023 in the comments section. Similar to other components that need to be used on the current page, leaving the components that need to be destroyed (such as the picker components of some third-party libraries, etc.), you can use this approach to solve the problem of running behind after leaving.

Generally speaking, we prefer to use * solution 2 to make the code more readable and clear at a glance. * * if you are not clear about the use of $once, $on, and $off, here is the address tutorial on the official website, at the programmed event listener.

Problems with importing rem files:

When we do mobile phones, adaptation is a problem that must be dealt with. For example, our solution to deal with adaptation is to write a rem.js, the principle is very simple, that is, calculate the font-size size of the html according to the size of the web page. Basically, as we all know, the code is directly attached here without much introduction.

; (function (orientationchange d) {var e=document.documentElement | | document.body,a= "orientationchange" in window? "orientationchange": "resize", b=function () {var franke.clientWidthiste.style.fontSize = (f > = 750)? "100px": 100* (fcan750) + "px"}; b (); c.addEventListener (aZhong bfalse)}) (window); copy code

Here is the question of how to introduce it. It is very simple. In main.js, you can import import'. / config/rem' directly. The path of import is filled in according to your file path.

Vue-Awesome-Swiper can basically solve all your rotation needs.

In many ui libraries we use (vant, antiUi, elementUi, etc.), there are carousel components, which is sufficient for ordinary carousel. However, at some point, the effect of our carousel may be cool, and at this time the carousel in the ui library may be a little inadequate. Of course, if the technology and time are all right, you can build your own dazzling wheel.

Here I would like to talk about vue-awesome-swiper, a carousel component, which is really very powerful and can basically meet our carousel needs. Swiper believes that many people have used it, it is easy to use, and it is also very convenient for us to re-develop and customize the rotation effect we need. Vue-awesome-swiper components are essentially based on swiper, or swiper that can run in vue. Here's how to use it:

Install cnpm install vue-awesome-swiper-- save

The global use of the methods used in components does not make much sense:

/ / introduce the component import 'swiper/dist/css/swiper.css' import {swiper, swiperSlide} from' vue-awesome-swiper' / / register the component components in components: {swiper, swiperSlide} / / use carousel in template / / ref is the current carousel / / callback is callback / / more parameter usage Please refer to document 1 2 3 to copy the code / / parameters to be written in data data () {return {/ / swiper rotation parameter swiperOption: {/ / scroll bar scrollbar: {el: '.swiper-scrollbar' }, / / previous one Next navigation: {nextEl: '.swiper-button-next', prevEl:' .swiper-button-prev',}, / / other parameters. }, copy the code

Swiper needs to configure which functional requirements, according to the documentation to add or delete. Attached documents: npm documents, swiper3.0/4.0 documents, more usage, please refer to the documentation instructions.

The problem of generating a large .map file after packaging

After the project is packaged, the code is compressed and encrypted. If an error is reported at run time, the output error information can not be accurately known where the code reported the error. And the generated .map suffix file, like unencrypted code, the exact output of which line and column is wrong can be set not to generate this kind of file. However, we do not need .map files in the build environment, so we can not generate these files at packaging time:

In the config/index.js file, set productionSourceMap: false so that the .map file can not be generated

FastClick's 300ms delay solution

When developing a mobile project, the click event will have the problem of 300ms delay. As for why there is this problem, please do it on your own. Here we only talk about the common solution, whether it is a vue project or a jq project, can use fastClick solution.

Install fastClick:

Cnpm install fastclick-S copy code

Introduce fastClick and initialization in main.js:

Import FastClick from 'fastclick'; / / introduce the plug-in FastClick.attach (document.body); / / copy the code using fastclick

The order in which options are written in components

Why should the options be written in a uniform order? It's simple to minimize the cost of choice and cognition.

1. Side effects (effects outside the trigger component)

El

two。 Global awareness (requires knowledge other than components)

Name

Parent

3. Component type (change the type of component)

Functional

4. Template modifier (change the way the template is compiled)

Delimiters

Comments

5. Template dependencies (resources used within the template)

Components

Directives

Filters

6. Combine (merge attributes into options)

Extends

Mixins

7. Interface (interface of a component)

InheritAttrs

Model

Props/propsData

8. Local status (local responsive properties)

Data

Computed

9. Event (callback triggered by responsive event)

Watch

Lifecycle hooks (in the order in which they are called)-beforeCreate- created- beforeMount- mounted- beforeUpdate- updated- activated- deactivated- beforeDestroy- destroyed

10. Non-responsive properties (independent of the instance properties of the response system)

-`methods`

11. Rendering (declarative description of component output)

-`template` / `render`

-`renderError`

Check the volume of the packaged files to help you quickly locate large files

If you are a project initialized by vue-cli, the webpack-bundle-analyzer plug-in will be installed by default, which can help us view the volume and structure comparison of the project and all the dependencies used in the project. You can also directly see the proportion of each module volume in the whole project. It's very bossy, isn't it?

Npm run build-- report / / run directly, and then open http://127.0.0.1:8888/ in the browser to view the copied code

Remember to turn off the local switch that was previously turned on by * * npm run dev** when running.

Routing lazy loading (also known as deferred loading)

Routing lazy loading can help us not to load excessive resources when entering the first screen, thus reducing the loading speed of the first screen.

In the routing file

Non-lazy loading method:

Import Index from'@ / page/index/index'; export default new Router ({routes: [{path:'/', name: 'Index', component: Index}]}) copy the code

Route lazy loading method:

Export default new Router ({routes: [{path:'/', name: 'Index', component: resolve = > require ([' @ / view/index/index'], resolve)}]) copy the code

Enable gzip compression code

For a single-page application like spa, the loading speed of all the first screens is very slow because all the resources are loaded at once. One of the most effective ways to solve this problem is to turn on gizp at the front and back end (among other things, caching, routing lazy loading, etc.). Gizp actually helps us reduce the file size to about 30%, that is, 100k files are only about 30k after gizp.

This configuration is available by default in projects initialized by vue-cli, and you only need to open it. However, you need to install the plug-in first:

The version setting of / / 2.0 is different. At the time of writing, this article is v1. V2 needs to cooperate with vue-cli3cnpm I compression-webpack-plugin@1.1.11 to copy the code

Then open it in config/index.js:

Build: {/ / other code. ProductionGzip: true, / / false do not enable gizp,true Open / / other code} copy code

Now when you package, you will generate not only the previous file, but also the file after the .gz end of gzip. The specific implementation is that if the client supports gzip, the backend returns the file after gzip, and if it does not support it, it returns the normal file without gzip.

* * Note: the gzip is packaged at the front end here, but the configuration of the backend server is also required. Configuration is relatively simple, just configure a few lines of code. Generally, this operation can be done by asking the operation and maintenance staff to do it. If there is no operation and maintenance staff, ask the backend to help with the configuration.

The details page returns the list page to cache data and browse location, and other pages enter the list page to refresh the data.

Such a scenario: there are three pages, home page / or search page, product classification page, product details page. We hope that when we enter the classification page from the home page, the classification page will refresh the data, and when we enter the details page from the classification page and then return to the classification page, we do not want to refresh it. We hope that the classification page at this time can cache the loaded data and automatically save the location where the user last browsed. Previous searches in Baidu are basically handled by keep-alive, but there are always some imperfections, so I have carried out the following practice after summing up.

To address this scenario requirement, we can use the keepAlive attribute provided by vue. Send another portal to deal with this problem directly here.

CSS's coped private scope and depth selector

Everyone knows that when a tag has a scoped attribute, its CSS only acts on elements in the current component. So how did he implement it? let's take a look at the code before and after compilation.

Before compilation:

.example {color: red;} copy the code

After compilation:

.example [data-v-f3f3eg9] {color: red;} copy the code

After reading it, you will understand that it is actually adding an attribute to the style of the component you write, thus implementing the so-called private scope. However, there are drawbacks. Given the way browsers render various CSS selectors, it will be many times slower when p {color: red} is scoped (that is, when used in combination with a property selector). If you use class or id instead, such as .example {color: red}, the performance impact will be eliminated. So, in your style, avoid using the tag directly. Instead, you can give the tag a class name.

If you want a selector in the scoped style to work "deeper", such as affecting subcomponents, you can use the > > operator:

.parent > > .child {/ *... * /} copy the code

The above code will be compiled into:

.parent [data-v-f3f3eg9] .child {/ *... * /} copy the code

For precompiling such as less or sass, the > > operator is not supported. You can use / deep/ to replace the > operator, for example: .parent / deep/ .child {/ *... * /}

Updates will continue later:

Unified management of axios encapsulation and api interfaces (updated, link above)

Hiper Open Speed Test

Two ways to obtain vue data + skeleton screen

Two-way data binding for custom components (parent and child components)

Split management of rout

Mixins blending simplifies common operations

The file, picture, background image resource does not exist or the path is wrong after packaging.

Vue plug-in development, publish to github, set display address, publish npm package

Hiper: a delightful performance analysis tool

As shown in the figure above, are the test results of the hiper tool, from which we can see the DNS query time, the TCP connection time, the first Byte time to the browser, the page download time, the time spent downloading resources after DOM Ready, the white screen time, the DOM Ready time, and the total page load time.

Install globally in our editor terminal:

Cnpm install hiper-g copy code

* * use: * * Terminal input command: URL of hiper test

# when we omit the protocol header, the default is to add `https://` # the simplest use, hiper baidu.com # how to include any parameters in url, before url Please use double quotation marks to enclose hiper "baidu.com?a=1&b=2" # load specified page 100times hiper-n 100 "baidu.com?a=1&b=2" # disable cache load specified page 100times hiper-n 100 "baidu.com?a=1&b=2"-no-cache # prohibit JavaScript loading specified page 100times hiper-n 100 "baidu.com?a=1&b=2"-- no-javascript # use Load specified page 100times in GUI form hiper-n 100 "baidu.com?a=1&b=2"-H false # load web page 100times using specified useragent hiper-n 100 "baidu.com?a=1&b=2"-u "Mozilla/5.0 (Macintosh Intel Mac OS X 10-13-4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36 "copy code"

This usage example, I directly copied the document description, the specific can take a look at the document, here is a link. When the opening speed of our project is slow, this tool can help us quickly locate at which step the page loading speed is affected.

Usually, the way we look at performance is to look at the data in performance and network, record several key performance metrics, and then refresh them a few times and then look at them. Sometimes we find that due to the small number of samples, it is seriously affected by the current busy degree of "network", "CPU" and "memory", and sometimes the optimized project is slower than before.

If there is a tool that requests a web page N times at a time, and then averages each performance indicator, we can know very accurately whether the optimization is "positive optimization" or "negative optimization".

Hiper is the solution to this pain point.

Practice of two ways of obtaining data by vue + implementation of simple Skeleton screen

There are two ways to get data in vue, especially if you introduce:

Get after the navigation is complete: complete the navigation first, and then get the data in the next component lifecycle hook. Displays an indication such as "loading" during data acquisition.

Get before the navigation is completed: before the navigation is completed, the data is obtained from the guard that routes into, and the navigation is performed after the data acquisition is successful.

From a technical point of view, both approaches are good-depending on what kind of user experience you want. So let's practice these two ways of obtaining data, as well as a little bit of thinking about user experience optimization.

* * first, the first is the first: get it after the navigation is completed. * * this method is used by most of us (because maybe we only know this method ^ V ^ at the beginning). When using this approach, we immediately navigate and render the component, and then get the data in the component's created hook. This gives us the opportunity to present a loading state during data acquisition, as well as different loading states between different views. Everyone knows how to get data. Here are some things about the user experience:

Before the data is obtained, the page component has been loaded, but the data has not been obtained and rendered, so in the process, we cannot load the component that displays the data on the page, but need to have a loaded component or skeleton screen of loading.

When the page data acquisition fails, which can be understood as the request timeout, what we want to show is the component of the disconnected network.

If it is a list page, also take into account the case of empty data, that is, the component of the empty prompt.

So, our page should have these three basic parts, put the code:

Copy the code empty

In this case of obtaining data, the default is to display the contents of loading or skeleton screen, and then if the data acquisition fails (i.e. request timeout or network disconnection), load the component of error and hide other components. If the data request is successful, the component of the content is loaded and the other components are hidden. If it is a list page, there may also be a list and an empty prompt in the content component, so it is also necessary to determine whether to load the content or an empty prompt based on the obtained data.

Second, the second way: get before the navigation is completed.

In this way, the data is requested in the beforeRouteEnter hook of the page, and the navigation page is not redirected until the data has been successfully obtained.

BeforeRouteEnter (to, from, next) {api.article.articleDetail (to.query.id) .then (res= > {next (vm = > {vm.info = res.data; vm.loadFinish = true})})}, copy the code

1. We all know that this in the beforeRouteEnter hook in the hook cannot be used, so to assign a value or call a method, we can only handle it in the callback function of the next () method. The first parameter of this callback function represents this, which will operate after the component is initialized successfully.

two。 I think most of the time our api or axios methods are mounted on the prototype of vue. Since we can't use this here, we can only introduce api or our axios into the page component.

3. The assignment operation can also be written in the method method, but calling this assignment method is still the way to vm.yourFunction ().

4. The null prompt, network disconnection, and so on are all the same as the first way, but since we get the data first and then jump to the loading component, we do not need to display the skeleton screen or loading components in the expected page. Yes, we need to have a prompt to load before the current page enters, that is, the previous page, such as the progress bar at the top of the page. In this way, the user experience will be more friendly, and the result will not be unresponsive for half a day and the user does not know because the s speed of the request is slower. The global progress bar at the top of the page can be set in main.js through router.beforeEach (to, from, next) {}. When the page route changes, the progress bar at the top of the page is displayed, and the progress bar is hidden after entering the new route.

About how to add a degree bar, because it has already been written in another article, send a link here directly, and there will be no more waste of space. The operation is also relatively simple and can be checked by yourself.

In fact, at this point, then the matter of the skeleton screen has been solved by the way, the general page skeleton screen is a picture of the page skeleton, but pay attention to this picture as small as possible.

Two-way data binding for custom components (parent and child components)

When it comes to communication between parent and child components, everyone must be familiar: the parent component passes values to the child component through props, and the child component triggers the parent component custom event through emit. But what I'm talking about here is the communication between the parent and child components using v-model. I believe that when using other people's component libraries, we often use v-model to control a component to show hidden effects, such as pop-up windows. Let's unravel the mystery of v-model step by step. Grab ~ steady ~ ~, the old driver is going to step on the throttle in the bend.

The first thing that comes to mind when it comes to v-model is our two-way data binding for form user data, which is very simple and rough, for example:

Data () {return {msg:''}} copy the code

In fact, v-model is a syntax sugar, and the above code has the same effect as the following code:

Data () {return {msg:''}}, copy the code

From this, we can see that v msg model = "msg" is actually the grammatical sugar of value= "msg" @ input= "msg = $event.target.value". This is actually listening for the input event of the form, and then changing the value corresponding to: value. In addition to being able to use v-model on the input form, it can also be used on components, which is mentioned on the official website, but the introduction is not very detailed, resulting in a feeling of confusion among new contacts. Now that we understand the use of the sugar nature of the v-model syntax, we can implement two-way data binding between parent and child components:

The above principle realization method, writing method 1:

Parent component usage:

Copy the code

How to write subcomponents:

/ / Click this button to trigger the data synchronization of the parent and child components to determine / / receive the value passed by the parent component / / Note, this implementation method Only the value attribute name props: {value: {type: Boolean, default: false} can be used here. Methods: {confirm () {/ / bidirectional data binding parent component: the value corresponding to value / / triggers the parent component input event through $emit The second parameter is the value passed to the parent component. Here you pass a false value / / which can be understood as the @ input= "msg = $event.target.value" event shown above / that is, the input event that triggers the parent component, and assigns the passed value 'false' to msg this.$emit (' input', false)}} copy code.

This way to achieve the parent and child components see v-model two-way data binding operation, for example, you can try to achieve a global pop-up window component operation, through the v-model control pop-up window hidden, because you have to do some operations in the page to show it, control its hidden code is written in the component, when the component hides the corresponding value of the parent component to change.

The v-model communication between parent and child components implemented in this way is feasible, but it limits that the attribute name that must be received by popos is value and the property triggered by emit must be input, so it is prone to conflict, especially in the form. So, in order to resolve conflicts by using v-model communication more elegantly, we can use the * * model** option in the subcomponents, which shows how to write 2:

The parent component is written:

Copy the code

How to write subcomponents:

Determine the / / model option to avoid conflicts / / the prop attribute is used to specify which value in the props attribute is used to receive the value passed by the parent component v-model / / for example, here the show in props is used to receive the v-model value / / event passed by the parent component: for ease of understanding, it can be simply understood as the alias of the parent component @ input, so as to avoid conflicts / / event value corresponds to the event name to be submitted when you emit. You can call it aa. It can also be called bb, but it should be named with meaning! Model: {prop: 'show', event:' changed'}, props: {/ / because the prop attribute in the model option specifies the So show receives the value passed by the parent component v-model: show: {type: Boolean, default: false}} Methods: {confirm () {/ / the value passed by the parent component of bidirectional data binding / / the first parameter Corresponding to the event value of the model option, you can call it aa,bbb,ccc and name it this.$emit ('changed', false)}} to copy the code.

This method of implementing parent-child components see v-model binding values is actually very common in our development, especially when you want to encapsulate common components.

Finally, there is a * * .sync * * way to implement two-way data binding. At first, this attribute existed, but later it was deleted because it was considered or destroyed one-way data flow, but it was finally proved to be meaningful. So it was added back in version 2.3.

For example: parent component:

Data () {return {msg:''}} copy the code

Subcomponents:

Change the msg value props: {oneprop: {type: String, default: 'hello world'}}, methods: {changeMsg () {/ / bidirectional data flow this.$emit (' update:msg' 'helow world')}} copy the code

This allows you to update the data of the parent component in the child component. Because v-model is used only once, .sync is used in certain scenarios when there are multiple values that need to be bound in both directions. .sync is the syntactic sugar of the following writing, designed to simplify our operations:

Copy the code

Now that you have mastered the v-model writing of components, it will be easier to encapsulate some common components.

I would like to mention again here:

Vm.$emit (event, [... args]) this api is mainly used to trigger events on the current instance. The additional parameters are passed to the listener for callback. The subcomponent also belongs to the current instance. The first parameter: the name of the event to trigger. The subsequent parameters are optional: they are passed as parameters to the event to be triggered. Document

Listen for custom events on the current instance. Events can be triggered by $emit or hook functions can be listened to through hook.

Vm.$on (event, callback): always monitor; document

Vm.$once (event, callback): monitor once; document

Vm.$off ([event, callback]): remove snooping; documentation

Listen for custom events triggered by $emit, which has already been used, and the listening hook function is also demonstrated in the timer section above. The scenario of listening for hook functions is not used much, but it is important to know.

Vm.$attrs: you can get all the custom properties passed by the parent component except class and style.

Vm.$listeners: you can get all custom events passed by the parent component

For example: parent component:

Copy the code

You can get the properties and events passed by the parent component in the child component without having to define it in props. The subcomponents are briefly demonstrated as follows:

Created () {const msg = this.$attrs.msg; / / get the msg this.$listeners.confirm & & this.$listeners.confirm () passed by the parent component; / / execute} if the component passes the event confirm, and copy the code

This will be useful when we write some advanced components.

Route split management

The route split here refers to the split of the routing file according to the module, so as to facilitate the management of the route and, more importantly, to facilitate the development of many people. Specific split, it depends on your project situation to decide, if the project is small, there are only 10 or 20 routes, then the split is very unnecessary. But if you develop some mall projects with more function points, there can be a hundred or even hundreds of routes, so it is necessary to split the routing files at this time. Otherwise, it would be bad for you to look at a long list of routes in the index.js file.

First, we create an index.js in the router folder as the routing entry file, and then create a new modules folder in which the routing files of each module are stored. For example, there is a routing file for the vote.js voting module and a routing file for the common module. Let's go directly to index.js, and then give a brief introduction:

Import Vue from 'vue' import Router from' vue-router' / / the route file of the public page import PUBLIC from'. / modules/public' / / the route file of the voting module import VOTE from'. / modules/vote' Vue.use (Router) / / defines the route const router = new Router ({mode: 'history', routes: [. PUBLIC,. VOTE ]}) / / router.beforeEach ((to, from, next) = > {if (document.title! = = to.meta.title) {document.title = to.meta.title when the route changes } next ()}) / / Export export default router copy code

First introduce vue and router and finally export, which is needless to say, the basic operation.

Here, the operation of router.beforeEach is written in the index.js file of router, and some people may write it in main.js, which is not wrong, but personally, since it is a routing operation, it is better to manage it in the routing file. Here, by the way, demonstrates how to automatically modify the page title when the page is switched.

Then introduce the js files that you divide according to the routing module, and then when instantiating the route, take out the imported files through the structure assignment method in the routes array. The final result is the same as the normal way of writing.

Then take a look at the vote.js we imported:

/ * router list of voting module * / export default [/ / Home page of voting module {path:'/ vote/index', name: 'VoteIndex', component: resolve = > require ([' @ / view/vote/index'], resolve) Meta: {title: 'voting'}, / / details page {path:'/ vote/detail', name: 'VoteDetail', component: resolve = > require ([' @ / view/vote/detail'], resolve) Meta: {title: 'voting details'}}] copy the code

Here is to export the route of the voting module in an array. The whole operation of route splitting is either the knowledge of vue or a syntax of es6 import, export and structure. Whether to split it or not depends on the project and the environment.

The route here uses the way of lazily loading routing, if it is not clear, it is described in the text above.

Also, in the meta meta-field here, a title information is defined to store the page title of the current page, that is, document.title.

Mixins blending simplifies common operations

We often encounter money retention of two decimal places, timestamp conversion and other operations in development. Each time we write a public function and filter it in the filters on the page. This method every time, but I feel that every time I need to use it, I have to write it again in filters, it is also quite annoying! However, the ultimate pursuit of our apes is laziness, so how can this work?

Guys, copy! Go to mixins, please!

Import {u_fixed} from'. / tool' const mixins = {filters: {/ / retain two decimal places mixin_fixed2 (val) {return u_fixed (val)}, / / convert digits to Chinese characters 16000 = > 16000 mixin_num2chinese (val) {return val > 9999? U_fixed (val/10000) + 'ten thousand': val;}} export default mixins copy code

Create a new mixins.js, write all the content we need to mix in, for example, here mixed with filters, write several commonly used operations in it, you can expand it yourself.

In that case, import the js on the page we need, and then declare that it can be mixed in, and then you can use it in a normal way.

For example, I can now use our filtering operation {{1000 | mixin_fixed2}} directly within the page

The file, picture, background image resource does not exist or the path is wrong after packaging.

First take a look at the index.js file under the config folder of the project. This configuration option allows us to package the resource public path. The default value is'/', that is, the root path, so the packaged resource path is the static under the root directory. The problem arises: if your packaged resources are not placed in the root directory of the server, but in folders such as mobile in the root directory, then the packaged path will conflict with the path in your code, resulting in the resource cannot be found.

So, to solve this problem, you can change the above path from the root directory of'/'to the relative path of'. / 'when packing.

In this case, the packaged image, ah, js and other paths are relative paths such as'. / static/img/asc.jpg', no matter where you put it, there will be no mistake. However, everything is there, but everything is normal here, but the path of the background map is still wrong. Because at this time the relative becomes the static/img/xx.jpg under the static/css/ folder, but in fact there is no static/img/xx.jpg under the static/css/ folder, that is, static/css/static/img/xx.jpg does not exist. The path to the current css file relative to this time. So in order to solve this problem, add a common path'.. /.. /'to the background map in our css, that is, let it return two levels up to the same level as the index.html file, then the relative path static/img/xx.jpg at this time can find the corresponding resources. So how to modify the common path of the background image? because the background image is parsed through loader, it is naturally modified in the configuration of loader. Open the utils file under the build folder, find the function of exports.cssLoaders, and find the following configuration in the function:

Find this location, add a configuration, that is, the code in the red box above, and change its public path to return two levels up. If you pack it again in this way, it will be ok!

Finally, solemnly speaking, if your route pattern is history, then packaging on the server, you must have the cooperation of the background server, you can see the official documents, this is very important. Otherwise, you will find all kinds of inexplicable problems such as the white screen. Remember!

At this point, I believe you have a deeper understanding of "what are the problems in the Vue project?" you might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report