Vue advanced knowledge key understanding

Scaffolding file structure

├── node_modules 
├── public
│ ├── favicon.ico: tab icon
│ └── index.html: main page
├── src
│ ├── assets: store static resources
│   │   └── logo.png
│ │── component: storage component
│   │   └── HelloWorld.vue
│ │── App.vue: Summarize all components
│ │── main.js: entry file
├── .gitignore: configuration ignored by git version control
├── babel.config.js: babel configuration file
├── package.json: application package configuration file
├── README.md: application description file
├── package-lock.json: package version control file

About different versions of Vue

  1. The difference between vue.js and vue.runtime.xxx.js:

    1. vue.js is a full version of Vue, including: core functions + template parser.

    2. vue.runtime.xxx.js is the running version of Vue, which only includes: core functions; no template parser.

  2. Because vue.runtime.xxx.js does not have a template parser, the template configuration item cannot be used, and the createElement function received by the render function needs to be used to specify the specific content.

vue.config.js configuration file

  1. Use vue inspect > output.js to view the default configuration of Vue scaffolding.

  2. Scaffolding can be customized using vue.config.js. For details, see: Vue CLI

ref attribute

  1. Used to register reference information for elements or subcomponents (replacement of id)

  2. What the application gets on the html tag is the real DOM element, and what the application gets on the component tag is the component instance object (vc)

  3. How to use:

    1. Mark: <h1 ref="xxx">.....</h1>or<School ref="xxx"></School>

    2. Obtain:this.$refs.xxx

props configuration item

  1. Function: Let the component receive data from the outside

  2. Pass data:<Demo name="xxx"/>

  3. Receive data:

    1. The first way (receive only):props:['name']

    2. Second way (restricted type):props:{name:String}

    3. Third way (restrict type, restrict necessity, specify default value):

      props:{
          name:{
          type: String, //Type
          required:true, //necessity
          default:'Lao Wang' //default value
          }
      }

    Remarks: props are read-only. The bottom layer of Vue will monitor your modification of props. If you modify props, a warning will be issued. If the business needs really need to be modified, please copy the content of props to a copy of data, and then modify it The data in data.

mixin

  1. Function: The configuration shared by multiple components can be extracted into a mix-in object

  2. How to use:

    The first step is to define the mixin:

    {
        data(){....},
        methods:{....}
        ....
    }

    The second step uses mixins:

    Global mixin:Vue.mixin(xxx)​ Local mixin:mixins:['xxx']

plug-in

  1. Function: used to enhance Vue

  2. Essence: An object containing the install method, the first parameter of install is Vue, and the second and subsequent parameters are the data passed by the plug-in user.

  3. Define the plugin:

    object.install = function (Vue, options) {
        // 1. Add a global filter
        View.filter(....)
        // 2. Add global directives
        Directive.view(....)
        // 3. Configure global mixin (combination)
        Vue. mixin(....)
        // 4. Add instance method
        Vue.prototype.$myMethod = function () {...}
        Vue.prototype.$myProperty = xxxx
    }
  4. Use the plugin:Vue.use()

scoped style

  1. Function: Let the style take effect locally to prevent conflicts.

  2. Writing:<style scoped>

Summarize the TodoList case

  1. Component coding process:

    (1). Split static components: components should be split according to function points, and the naming should not conflict with html elements.

    (2). Realize dynamic components: consider the storage location of the data, whether the data is used by a component or some components:

    1). A component is in use: just put it in the component itself.

    2). Some components are in use: put them on their common parent component (state promotion).

    (3). Realize interaction: start from binding events.

  2. props apply to:

    (1). Parent component ==> child component communication

    (2). Child component ==> parent component communication (requiring the parent to give the child a function first)

  3. When using v-model, remember: the value bound by v-model cannot be the value passed by props, because props cannot be modified!

  4. If the value passed by props is an object type, Vue will not report an error when modifying the properties in the object, but this is not recommended.

webStorage

  1. The storage content size generally supports about 5MB (different browsers may vary)

  2. The browser implements the local storage mechanism through the Window.sessionStorage and Window.localStorage properties.

  3. Related APIs:

    1. xxxxxStorage.setItem('key', 'value');This method accepts a key and a value as parameters, and will add the key-value pair to the storage, and if the key exists, update its corresponding value.

    2. xxxxxStorage.getItem('person');

      This method accepts a key name as a parameter and returns the value corresponding to the key name.

    3. xxxxxStorage.removeItem('key');

      This method accepts a key name as a parameter and deletes the key name from the storage.

    4. xxxxxStorage.clear()

      This method clears all data in storage.

  4. Remark:

    1. The content stored in SessionStorage will disappear when the browser window is closed.

    2. The content stored in LocalStorage needs to be manually cleared before it disappears.

    3. xxxxxStorage.getItem(xxx)If the value corresponding to xxx cannot be obtained, the return value of getItem is null.

    4. JSON.parse(null)The result is still null.

Component custom events

  1. A way of communication between components, suitable for: child components ===> parent components

  2. Usage scenario: A is the parent component, B is the child component, and B wants to pass data to A, then it needs to bind a custom event to B in A (event callback is in A).

  3. Bind custom events:

    1. The first way, in the parent component: <Demo @jiyun="test"/>or<Demo v-on:jiyun="test"/>

    2. The second way, in the parent component:

      <Demo ref="demo"/>
      ......
      mounted(){
         this.$refs.xxx.$on('jiyun',this.test)
      }
    3. If you want a custom event to be triggered only once, you can use oncemodifiers, or $oncemethods.

  4. Trigger a custom event:this.$emit('jiyun',数据)

  5. Unbind custom eventsthis.$off('jiyun')

  6. Components can also be bound to native DOM events, requiring the use of nativemodifiers.

  7. Note: When this.$refs.xxx.$on('jiyun',回调)binding a custom event, the callback must either be configured in methods or use an arrow function, otherwise this will cause problems!

Global Event Bus (GlobalEventBus)

  1. A way of communication between components, suitable for any communication between components.

  2. Install the global event bus:

    new View({
        ......
        beforeCreate() {
            Vue.prototype.$bus = this //Install the global event bus, $bus is the vm of the current application
        },
        ......
    }) 
  3. Using the event bus:

    1. Receive data: If component A wants to receive data, then bind a custom event to $bus in component A, and the callback of the event stays in component A itself.

      methods(){
        demo(data){......}
      }
      ......
      mounted() {
        this.$bus.$on('xxxx',this.demo)
      }
    2. provide data:this.$bus.$emit('xxxx',数据)

  4. It is best to use $off in the beforeDestroy hook to unbind the events used by the current component.

Message Subscription and Publishing (pubsub)

  1. A way of communication between components, suitable for any communication between components.

  2. Steps for usage:

    1. Install pubsub:npm i pubsub-js

    2. import:import pubsub from 'pubsub-js'

    3. Receive data: If A component wants to receive data, it subscribes to the message in A component, and the subscribed callback stays in A component itself.

      methods(){
        demo(data){......}
      }
      ......
      mounted() {
        this.pid = pubsub.subscribe('xxx',this.demo) //Subscribe to news
      }
    4. provide data:pubsub.publish('xxx',数据)

    5. It is best PubSub.unsubscribe(pid)to .

nextTick

  1. grammar:this.$nextTick(回调函数)

  2. Function: Execute the specified callback after the next DOM update.

  3. When to use: When the data is changed and some operations are to be performed based on the updated new DOM, it must be executed in the callback function specified by nextTick.

Transition and animation of Vue package

  1. Function: When inserting, updating or removing DOM elements, add a style class name to the element at the appropriate time.

  2. Graphic:

  3. Writing:

    1. Ready to style:

      • Elements come in styles:

        1. v-enter: the starting point of entry

        2. v-enter-active: in the process of entering

        3. v-enter-to: the end point of entry

      • Styles for element leaving:

        1. v-leave: the starting point of leaving

        2. v-leave-active: in the process of leaving

        3. v-leave-to: the end point of leaving

    2. Use <transition>the element to be wrapped and configure the name attribute:

      <transition name="hello">
          <h1 v-show="isShow">Hello! </h1>
      </transition>
    3. Remarks: If there are multiple elements that need to be transitioned, you need to use: <transition-group>, and each element must specify keya value.

Vue scaffolding configuration proxy

method one

Add the following configuration in vue.config.js:

devServer:{
  proxy:"http://localhost:5000"
}

illustrate:

  1. Advantages: The configuration is simple, and it can be sent directly to the front end (8080) when requesting resources.

  2. Disadvantages: Multiple proxies cannot be configured, and it is not possible to flexibly control whether requests go through proxies.

  3. Working method: If the proxy is configured as above, when a resource that does not exist in the front-end is requested, the request will be forwarded to the server (matching front-end resources first)

Method Two

Write vue.config.js to configure specific proxy rules:

module.exports = {
    devServer: {
      proxy: {
      '/api1': {// Match all request paths starting with '/api1'
        target: 'http://localhost:5000', // base path of proxy target
        changeOrigin: true,
        pathRewrite: {'^/api1': ''}
      },
      '/api2': {// Match all request paths starting with '/api2'
        target: 'http://localhost:5001', // base path of proxy target
        changeOrigin: true,
        pathRewrite: {'^/api2': ''}
      }
    }
  }
}
/*
   When changeOrigin is set to true, the host in the request header received by the server is: localhost:5000
   When changeOrigin is set to false, the host in the request header received by the server is: localhost:8080
   changeOrigin default value is true
*/

illustrate:

  1. Advantages: Multiple proxies can be configured, and it is possible to flexibly control whether requests go through proxies.

  2. Disadvantages: The configuration is slightly cumbersome, and a prefix must be added when requesting resources.

slot

  1. Function: Allow the parent component to insert the html structure to the specified position of the child component, and it is also a way of communication between components, which is suitable for parent components ===> child components .

  2. Categories: default slots, named slots, scoped slots

  3. How to use:

    1. Default slot:

      In the parent component:
              <Category>
                 <div>html structure 1</div>
              </Category>
      In the subcomponent:
              <template>
                  <div>
                     <!-- Define slots -->
                     <slot>Slot default content...</slot>
                  </div>
              </template>
    2. Named slots:

      In the parent component:
              <Category>
                  <template slot="center">
                    <div>html structure 1</div>
                  </template>
                  <template v-slot:footer>
                     <div>html structure 2</div>
                  </template>
              </Category>
      In the subcomponent:
              <template>
                  <div>
                     <!-- Define slots -->
                     <slot name="center">Slot default content...</slot>
                     <slot name="footer">Slot default content...</slot>
                  </div>
              </template>
    3. Scoped slots:

      1. Understanding: The data is in the component itself, but the structure generated according to the data needs to be determined by the user of the component. (The games data is in the Category component, but the structure traversed by using the data is determined by the App component)

      2. Specific encoding:

        In the parent component:
                <Category>
                    <template scope="scopeData">
                        <!-- The ul list is generated -->
                        <ul>
                            <li v-for="g in scopeData.games" :key="g">{
                
                {g}}</li>
                        </ul>
                    </template>
                </Category>
                <Category>
                    <template slot-scope="scopeData">
                        <!-- The h4 title is generated -->
                        <h4 v-for="g in scopeData.games" :key="g">{
                
                {g}}</h4>
                    </template>
                </Category>
        In the subcomponent:
                <template>
                    <div>
                        <slot :games="games"></slot>
                    </div>
                </template>
                
                <script>
                    export default {
                        name:'Category',
                        props:['title'],
                        //The data is in the child component itself
                        data() {
                            return {
                                games:['Red Alert','Cross Fire','Audition','Super Mario']
                            }
                        },
                    }
                </script>

Vuex

1. Concept

A Vue plug-in that implements centralized state (data) management in Vue, and performs centralized management (read/write) on the shared state of multiple components in the Vue application. It is also a way of communication between components, and it is suitable for any Communication between components.

2. When to use it?

When multiple components need to share data

3. Build the vuex environment

  1. Create a file:src/store/index.js

    //Introduce the Vue core library
    import View from 'view'
    //Introduce Vuex
    import Vuex from 'vuex'
    //Apply the Vuex plugin
    Vue.use(Vuex)
    //Prepare the actions object - respond to the user's actions in the component
    const actions = {}
    //Prepare the mutations object - modify the data in the state
    const mutations = {}
    //Prepare the state object - save specific data
    const state = {}
    //Create and expose store
    export default new Vuex.Store({
        actions,
        mutations,
        state
    })
  2. Pass in configuration items main.jswhen creating a vm instore

    ......
    //Introduce store
    import store from './store'
    ......
    //create vm
    new View({
        the:'#app',
        render: h => h(App),
        store
    })

4. Basic use

  1. Initialize data, configure actions, configure mutations, manipulate filesstore.js

    //Introduce the Vue core library
    import View from 'view'
    //Introduce Vuex
    import Vuex from 'vuex'
    //reference Vuex
    Vue.use(Vuex)
    const actions = {
        //Response to the action added in the component
        jia(context,value){
            // console.log('jia in actions has been called', miniStore, value)
            context.commit('JIA',value)
        },
    }
    const mutations = {
        //Execute plus
        JIA(state,value){
            // console.log('JIA in mutations is called', state, value)
            state.sum += value
        }
    }
    //Initialization data
    const state = {
       sum:0
    }
    //Create and expose store
    export default new Vuex.Store({
        actions,
        mutations,
        state,
    })
  2. Read the data in vuex in the component:$store.state.sum

  3. Modify the data in vuex in the component: $store.dispatch('action中的方法名',数据)or$store.commit('mutations中的方法名',数据)

    Remarks: If there is no network request or other business logic, actions can also be skipped in the component, that is, do not write dispatch, write directlycommit

5. Use of getters

  1. Concept: When the data in the state needs to be processed before use, getters can be used for processing.

  2. store.jsAppend gettersconfiguration in

    ......
    const getters = {
        bigSum(state){
            return state.sum * 10
        }
    }
    //Create and expose store
    export default new Vuex.Store({
        ......
        getters
    })
  3. Read data in the component:$store.getters.bigSum

6. The use of four map methods

  1. mapState method: used to help us map statethe data into computed properties

    computed: {
        //Generate calculated properties with mapState: sum, school, subject (object writing)
         ...mapState({sum:'sum',school:'school',subject:'subject'}),
             
        //Generate calculated properties with mapState: sum, school, subject (array writing)
        ...mapState(['sum','school','subject']),
    },
  2. mapGetters method: used to help us map gettersthe data into computed properties

    computed: {
        //Generate calculated properties with mapGetters: bigSum (object writing)
        ...mapGetters({bigSum:'bigSum'}),
        //Generate calculated properties with mapGetters: bigSum (array writing)
        ...mapGetters(['bigSum'])
    },
  3. mapActions method: the method used to help us generate and actionsdialogue, namely: the included $store.dispatch(xxx)function

    methods:{
        // Generated by mapActions: incrementOdd, incrementWait (object form)
        ...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
        // Generated by mapActions: incrementOdd, incrementWait (array form)
        ...mapActions(['jiaOdd','jiaWait'])
    }
  4. mapMutations method: the method used to help us generate and mutationsdialogue, namely: $store.commit(xxx)the function contained

    methods:{
        // Generated by mapActions: increment, decrement (object form)
        ...mapMutations({increment:'JIA',decrement:'JIAN'}),
        
        // Generated by mapMutations: JIA, JIAN (object form)
        ...mapMutations(['JIA','JIAN']),
    }

Remarks: When using mapActions and mapMutations, if you need to pass parameters, you need to pass the parameters when binding the event in the template, otherwise the parameters are event objects.

7. Modularity + Namespace

  1. Purpose: Make the code easier to maintain, and make the classification of various data more clear.

  2. Revisestore.js

    const countAbout = {
      namespaced:true,//Open the namespace
      state:{x:1},
      mutations: { ... },
      actions: { ... },
      getters: {
        bigSum(state){
           return state.sum * 10
        }
      }
    }
    const personAbout = {
      namespaced:true,//Open the namespace
      state:{ ... },
      mutations: { ... },
      actions: { ... }
    }
    const store = new Vuex.Store({
      modules: {
        countAbout,
        personAbout
      }
    })
  3. After the namespace is enabled, the state data is read in the component:

    //Method 1: read directly by yourself
    this.$store.state.personAbout.list
    //Method 2: Read with mapState:
    ...mapState('countAbout',['sum','school','subject']),
  4. After the namespace is enabled, getters data is read in the component:

    //Method 1: read directly by yourself
    this.$store.getters['personAbout/firstPersonName']
    //Method 2: Read with mapGetters:
    ...mapGetters('countAbout',['bigSum'])
  5. After the namespace is enabled, dispatch is called in the component

    //Method 1: Dispatch directly by yourself
    this.$store.dispatch('personAbout/addPersonWang',person)
    //Method 2: With mapActions:
    ...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
  6. After the namespace is enabled, commit is called in the component

    //Method 1: commit directly by yourself
    this.$store.commit('personAbout/ADD_PERSON',person)
    //Method 2: With mapMutations:
    ...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),

routing

  1. Understanding: A route is a set of mapping relationships (key-value), and multiple routes need to be managed by a router.

  2. Front-end routing: the key is the path, and the value is the component.

1. Basic use

  1. Install vue-router, command:npm i vue-router

  2. Apply plugin:Vue.use(VueRouter)

  3. Write router configuration items:

    //Introduce VueRouter
    import VueRouter from 'vue-router'
    //Import Luyou component
    import About from '../components/About'
    import Home from '../components/Home'
    //Create a router instance object to manage a group of routing rules
    const router = new VueRouter({
        routes:[
            {
                path:'/about',
                component:About
            },
            {
                path:'/home',
                component:Home
            }
        ]
    })
    //expose router
    export default router
  4. Implement switching (active-class can configure highlighting style)

    <router-link active-class="active" to="/about">About</router-link>
  5. target placements

    <router-view></router-view>

2. A few points for attention

  1. Routing components are usually stored in pagesfolders, and general components are usually stored in componentsfolders.

  2. By switching, the "hidden" routing components are destroyed by default, and then mounted when needed.

  3. Each component has its own $routeproperties, which store its own routing information.

  4. The entire application has only one router, which can $routerbe obtained through the properties of the component.

3. Multi-level routing (multi-level routing)

  1. To configure routing rules, use the children configuration item:

    routes:[
        {
            path:'/about',
            component:About,
        },
        {
            path:'/home',
            component:Home,
            children:[ //Configure sub-level routing through children
                {
                    path:'news', //Do not write here: /news
                    component:News
                },
                {
                    path:'message',//must not write here: /message
                    component:Message
                }
            ]
        }
    ]
  2. Jump (to write the full path):

    <router-link to="/home/news">News</router-link>

4. The query parameter of the route

  1. pass parameters

    <!-- Jump and carry the query parameter, the string writing of to -->
    <router-link :to="/home/message/detail?id=666&title=Hello">Jump</router-link>
                    
    <!-- Jump and carry the query parameter, the object writing method of to -->
    <router-link 
        :to="{
            path:'/home/message/detail',
            query:{
               id:666,
                title:'Hello'
            }
        }"
    >Jump</router-link>
  2. Receive parameters:

    $route.query.id
    $route.query.title

5. Naming Routes

  1. Function: It can simplify the routing jump.

  2. how to use

    1. Give the route a name:

      {
          path:'/demo',
          component:Demo,
          children:[
              {
                  path:'test',
                  component:Test,
                  children:[
                      {
                            name:'hello' //Name the route
                          path:'welcome',
                          component:Hello,
                      }
                  ]
              }
          ]
      }
    2. Simplified jump:

      <!--Before simplification, you need to write the complete path -->
      <router-link to="/demo/test/welcome">跳转</router-link>
      <!--After simplification, jump directly through the name-->
      <router-link :to="{name:'hello'}">跳转</router-link>
      <!-- Simplified writing with passing parameters -->
      <router-link 
          :to="{
              name:'hello',
              query:{
                 id:666,
                  title:'Hello'
              }
          }"
      >Jump</router-link>

6. The params parameter of the route

  1. Configure routing, declare to receive params parameters

    {
        path:'/home',
        component:Home,
        children:[
            {
                path:'news',
                component:News
            },
            {
                component:Message,
                children:[
                    {
                        name:'xiangqing',
                        path:'detail/:id/:title', //use placeholder declaration to receive params parameter
                        component:Detail
                    }
                ]
            }
        ]
    }
  2. pass parameters

    <!-- Jump and carry the params parameter, the string writing method of to -->
    <router-link :to="/home/message/detail/666/Hello">Jump</router-link>
                    
    <!-- Jump and carry params parameters, the object writing method of to -->
    <router-link 
        :to="{
            name:'xiangqing',
            params:{
               id:666,
                title:'Hello'
            }
        }"
    >Jump</router-link>

    Special attention: When the route carries params parameters, if you use the object writing method of to, you cannot use the path configuration item, you must use the name configuration!

  3. Receive parameters:

    $route.params.id
    $route.params.title

7. Routing props configuration

Role: Make it easier for routing components to receive parameters

{
    name:'xiangqing',
    path:'detail/:id',
    component:Detail,
    //The first way of writing: the props value is an object, and all key-value combinations in the object will eventually be passed to the Detail component through props
    // props:{a:900}
    //The second way of writing: the props value is a Boolean value, and the Boolean value is true, then pass all the params parameters received by the route to the Detail component through props
    // props:true
    
    //The third way of writing: the props value is a function, and each set of key-values ​​in the object returned by the function will be passed to the Detail component through props
    props(route){
        return {
            id:route.query.id,
            title:route.query.title
        }
    }
}

8. <router-link>The replace attribute

  1. Role: control the mode of operating browser history when routing jumps

  2. There are two ways to write the history of the browser: pushand respectively replace, pushwhich is to append the history record, and replaceis to replace the current record. When the route jumps, the default ispush

  3. How to turn on replacethe mode:<router-link replace .......>News</router-link>

9. Programmatic Routing Navigation

  1. <router-link>Function: Make routing jumps more flexible without the help of routing jumps

  2. Specific encoding:

    //Two APIs of $router
    this.$router.push({
    	name:'xiangqing',
    		params:{
    			id:xxx,
    			title:xxx
    		}
    })
    
    this.$router.replace({
    	name:'xiangqing',
    		params:{
    			id:xxx,
    			title:xxx
    		}
    })
    this.$router.forward() //forward
    this.$router.back() //Back
    this.$router.go() // can go forward or back
    

10. Cache Routing Components

  1. Function: keep the routing components that are not displayed mounted and not destroyed.

  2. Specific encoding:

    <keep-alive include="News"> 
        <router-view></router-view>
    </keep-alive>
    

11. Two new lifecycle hooks

  1. Function: Two hooks unique to routing components, used to capture the activation status of routing components.

  2. specific name:

    1. activatedFired when the routing component is activated.

    2. deactivatedTriggered when the routing component is deactivated.

12. Route Guard

  1. Role: to control the authority of the route

  2. Category: global guard, exclusive guard, component guard

  3. Global Guard:

    //Global pre-guard: executed at initialization, executed before each routing switch
    router.beforeEach((to,from,next)=>{
    	console.log('beforeEach',to,from)
    	if(to.meta.isAuth){ //Determine whether the current route needs permission control
    		if(localStorage.getItem('school') === 'jiyun'){ //Specific rules for permission control
    			next() // release
    		}else{
    			alert('Temporarily no permission to view')
    			// next({name:'guanyu'})
    		}
    	}else{
    		next() // release
    	}
    })
    
    //Global post guard: execute at initialization, execute after each routing switch
    router.afterEach((to,from)=>{
    	console.log('afterEach',to,from)
    	if(to.meta.title){ 
    		document.title = to.meta.title //Modify the title of the web page
    	}else{
    		document.title = 'vue_test'
    	}
    })
    
  4. Exclusive Guard:

    beforeEnter(to,from,next){
    	console.log('beforeEnter',to,from)
    	if(to.meta.isAuth){ //Determine whether the current route needs permission control
    		if(localStorage.getItem('school') === 'jiyun'){
    			next()
    		}else{
    			alert('Temporarily no permission to view')
    			// next({name:'guanyu'})
    		}
    	}else{
    		next()
    	}
    }
    
  5. Guards inside the component:

    //Enter the guard: through the routing rules, it is called when entering the component
    beforeRouteEnter (to, from, next) {
    },
    //Leave the guard: Called when leaving the component through routing rules
    beforeRouteLeave (to, from, next) {
    }
    

13. Two working modes of the router

  1. For a url, what is the hash value? —— # and the content after it is the hash value.

  2. The hash value will not be included in the HTTP request, that is: the hash value will not be brought to the server.

  3. hash mode:

    1. There is always a # sign in the address, which is not beautiful.

    2. If the address is shared through a third-party mobile app in the future, if the app verification is strict, the address will be marked as illegal.

    3. Compatibility is better.

  4. history mode:

    1. The address is clean and beautiful.

    2. Compatibility is slightly worse than hash mode.

    3. When the application is deployed and launched, it needs the support of the back-end personnel to solve the problem of refreshing the page server 404.

Guess you like

Origin blog.csdn.net/jiangshen_a/article/details/127107578
Recommended