Vue2.x learning notes

Keywords: Javascript Vue Vue.js

Scaffold file structure

├── node_modules 
├── public
│   ├── favicon.ico: Tab Icon
│   └── index.html: Main page
├── src
│   ├── assets: Storing static resources
│   │   └── logo.png
│   │── component: Storage components
│   │   └── HelloWorld.vue
│   │── App.vue: Summarize all components
│   │── main.js: Entry file
├── .gitignore: git Configuration ignored by versioning
├── babel.config.js: babel Configuration file for
├── package.json: App package profile 
├── README.md: Application description file
├── package-lock.json: Package version control file

About different versions of Vue

  1. Differences 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 contains: core functions; There is no template parser.
  2. Because vue.runtime.xxx.js does not have a template parser, you cannot use the configuration item template. You need to use the createElement function received by the render function 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. The scaffold can be customized with vue.config.js. For details, see: https://cli.vuejs.org/zh

ref attribute

  1. Used to register reference information (id substitutes) for elements or subcomponents
  2. The application obtains the real DOM element on the html tag, and the application on the component tag is the component instance object (vc)
  3. Usage:
    1. Marking: < H1 ref = "XXX" >... < / H1 > or < school ref = "XXX" > < / School >
    2. Get: this.$refs.xxx

props configuration item

  1. Function: let components receive external data

  2. Transfer data: < demo name = "XXX" / >

  3. Receive data:

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

    2. The second method (restriction type): props:{name:String}

    3. The third method (restriction type, restriction necessity, specifying default value):

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

    Note: props is read-only. Vue bottom layer will monitor your changes to props. If you make changes, you will be warned. If the business requirements really need to be modified, please copy the contents of props into data, and then modify the data in data.

Mixin (mixed)

  1. Function: the configuration shared by multiple components can be extracted into a mixed object

  2. Usage:

    Step 1: define mixing:

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

    Step 2: use blending:

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

plug-in unit

  1. Features: for enhancing Vue

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

  3. Define plug-ins:

    object.install = function (Vue, options) {
        // 1. Add global filter
        Vue.filter(....)
    
        // 2. Add global instruction
        Vue.directive(....)
    
        // 3. Configure global mixing (integration)
        Vue.mixin(....)
    
        // 4. Add instance method
        Vue.prototype.$myMethod = function () {...}
        Vue.prototype.$myProperty = xxxx
    }
    
  4. Using plug-in: Vue.use()

scoped style

  1. Function: make styles take effect locally to prevent conflicts.
  2. Writing method: < style scoped >

Summarize the TodoList case

  1. Component coding process:

    (1). Splitting static components: components should be split according to function points, and their names should not conflict with html elements.

    (2) realize dynamic components: consider the storage location of data, whether a component is in use or some components are in use:

    1). A component is in use: it can be placed on the component itself.

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

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

  2. props applies to:

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

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

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

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

webStorage

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

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

  3. Related API:

    1. xxxxxStorage.setItem('key', 'value');
      This method accepts a key and value as parameters, and will add the key value pair to the storage. If the key name exists, its corresponding value will be updated.

    2. xxxxxStorage.getItem('person');

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

    3. xxxxxStorage.removeItem('key');

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

    4. xxxxxStorage.clear()

      This method will empty all data in the storage.

  4. remarks:

    1. The contents of the SessionStorage store disappear as the browser window closes.
    2. The content stored in LocalStorage needs to be cleared manually before it disappears.
    3. Xxxxxxstorage.getItem (xxx) if the value corresponding to XXX cannot be obtained, the return value of getItem is null.
    4. The result of JSON.parse(null) is still null.

Custom events for components

  1. A method of communication between components, applicable to: child component = = = > parent component

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

  3. Bind custom events:

    1. The first method is in the parent component: < demo @ atguigu = "test" / > or < demo v-on: atguigu = "test" / >

    2. In the second way, in the parent component:

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

  4. Trigger custom event: this.$emit('atguigu ', data)

  5. Unbind custom event this.$off('atguigu ')

  6. You can also bind native DOM events on components, and you need to use the native modifier.

  7. Note: when Binding custom events through this.$refs.xxx.$on('atguigu ', callback), the callback is either configured in methods or used as an arrow function, otherwise there will be a problem with this pointing!

Global event bus

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

  2. To install the global event bus:

    new Vue({
    	......
    	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, bind a custom event to $bus in component A, and the callback of the event remains in component a itself.

      methods(){
        demo(data){......}
      }
      ......
      mounted() {
        this.$bus.$on('xxxx',this.demo)
      }
      
    2. Data provided: this.$bus.$emit('xxxx ', data)

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

Message subscription and Publication (pubsub)

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

  2. Use steps:

    1. Install pubsub: NPM I pubsub JS

    2. Import: import PubSub from 'PubSub JS'

    3. Receive data: if component a wants to receive data, it subscribes to messages in component A, and the subscribed callback remains in component a itself.

      methods(){
        demo(data){......}
      }
      ......
      mounted() {
        this.pid = pubsub.subscribe('xxx',this.demo) //Subscription message
      }
      
    4. Data provided: pubsub.publish('xxx ', data)

    5. It is better to use PubSub.unsubscribe(pid) to unsubscribe in the beforeDestroy hook.

nextTick

  1. Syntax: this. $nexttick (callback function)
  2. Function: execute the specified callback after the next DOM update.
  3. When to use: when to perform some operations based on the updated new DOM after changing the data, it should be executed in the callback function specified by nextTick.

Vue encapsulated transition and animation

  1. Function: when inserting, updating or removing DOM elements, add style class names to the elements when appropriate.

  2. Writing method:

    1. Ready style:

      • Element entry style:
        1. v-enter: the starting point of entry
        2. v-enter-active: in the process of entering
        3. v-enter-to: end point of entry
      • Style of element departure:
        1. v-leave: the starting point of departure
        2. v-leave-active: leave process 2
        3. v-leave-to: end of departure
  3. Wrap the elements to be excessive with < transition > and configure the name attribute:

      <transition name="hello">
      	<h1 v-show="isShow">How do you do!</h1>
      </transition>
  1. Note: if more than one element needs to be excessive, you need to use:
    < transition group >, and each element must specify a key value.

vue scaffold configuration agent

Method 1

Add the following configuration in vue.config.js:

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

explain:

  1. Advantages: simple configuration. When requesting resources, it can be directly sent to the front end (8080).
  2. Disadvantages: you cannot configure multiple agents, and you cannot flexibly control whether requests go through agents.
  3. Working method: if the agent is configured according to the above, when a resource that does not exist in the front end is requested, the request will be forwarded to the server (priority is given to matching the front end resources)

Method 2

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 ', / / the basic path of the proxy target
        changeOrigin: true,
        pathRewrite: {'^/api1': ''}
      },
      '/api2': {// Match all request paths starting with '/ api2'
        target: 'http://localhost:5001 ', / / the base path of the proxy target
        changeOrigin: true,
        pathRewrite: {'^/api2': ''}
      }
    }
  }
}
/*
   changeOrigin When set to true, the host in the request header received by the server is: localhost:5000
   changeOrigin When set to false, the host in the request header received by the server is: localhost:8080
   changeOrigin The default value is true
*/

explain:

  1. Advantages: multiple agents can be configured, and it can flexibly control whether requests go through agents.
  2. Disadvantages: the configuration is slightly cumbersome and must be prefixed when requesting resources.

slot

  1. Function: enables the parent component to insert html structure into the specified location of the child component. It is also a way of communication between components. It is applicable to parent component = = > child component.

  2. Category: default slot, named slot, scope slot

  3. Usage:

    1. Default slot:
     In parent component:
             <Category>
                <div>html Structure 1</div>
             </Category>
     In subcomponents:
             <template>
                 <div>
                    <!-- Define slot -->
                    <slot>Slot default content...</slot>
                 </div>
             </template>
     ```

  2. Named slot:

```html
     In parent component:
             <Category>
                 <template slot="center">
                   <div>html Structure 1</div>
                 </template>
     
                 <template v-slot:footer>
                    <div>html Structure 2</div>
                 </template>
             </Category>
     In subcomponents:
             <template>
                 <div>
                    <!-- Define slot -->
                    <slot name="center">Slot default content...</slot>
                    <slot name="footer">Slot default content...</slot>
                 </div>
             </template>
  1. Scope slot:

    1. Understanding: the data is in the component itself, but the structure generated by 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 the data is determined by the App component)

    2. Specific code:

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

Vuex

1. Concept

A Vue plug-in that implements centralized state (data) management in Vue. It centrally manages (reads / writes) the shared state of multiple components in Vue applications. It is also a way of communication between components and is suitable for communication between any components.

2. When to use?

When multiple components need to share data

3. Build vuex environment

  1. Create file: src/store/index.js
   //Introducing Vue core library
   import Vue from 'vue'
   //Introduce Vuex
   import Vuex from 'vuex'
   //Applying the Vuex plug-in
   Vue.use(Vuex)
   
   //Prepare the actions object -- respond to the user's actions in the component
   const actions = {}
   //Prepare the changes object -- modify the data in the state
   const mutations = {}
   //Prepare the state object -- save the specific data
   const state = {}
   
   //Create and expose the store
   export default new Vuex.Store({
   	actions,
   	mutations,
   	state
   })
  1. Pass in the store configuration item when creating vm in main.js
   ......
   //Introducing store
   import store from './store'
   ......
   
   //Create vm
   new Vue({
   	el:'#app',
   	render: h => h(App),
   	store
   })

4. Basic use

  1. Initialize data, configure actions, configure changes, and operate the file store.js
   //Introducing Vue core library
   import Vue from 'vue'
   //Introduce Vuex
   import Vuex from 'vuex'
   //Reference Vuex
   Vue.use(Vuex)
   
   const actions = {
       //Action added in response component
   	jia(context,value){
   		// Console.log ('jia in actions is called ', miniStore,value)
   		context.commit('JIA',value)
   	},
   }
   
   const mutations = {
       //Executive plus
   	JIA(state,value){
   		// Console.log ('JIA in changes called ', state,value)
   		state.sum += value
   	}
   }
   
   //Initialization data
   const state = {
      sum:0
   }
   
   //Create and expose the store
   export default new Vuex.Store({
   	actions,
   	mutations,
   	state,
   })
  1. Read data from vuex in component: $store.state.sum

  2. Modify the data in vuex in the component: $store. Dispatch ('method name in action ', data) or $store. Commit ('method name in changes', data)

    Note: if there is no network request or other business logic, actions can also be crossed in the component, that is, commit can be written directly without writing dispatch

5. Use of Getters

  1. Concept: when the data in state needs to be processed before use, you can use getters processing.

  2. Add getters configuration in store.js

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

6. Use of four map methods

  1. mapState method: it is used to help us map the data in state into calculated attributes
   computed: {
       //Generate calculation attributes with mapState: sum, school, subject (object writing method)
        ...mapState({sum:'sum',school:'school',subject:'subject'}),
            
       //Generate calculation attributes with mapState: sum, school, subject (array writing method)
       ...mapState(['sum','school','subject']),
   },
  1. mapGetters method: used to help us map the data in getters into calculated attributes
   computed: {
       //Generate calculation attribute with mapGetters: bigSum (object writing)
       ...mapGetters({bigSum:'bigSum'}),
   
       //Generate calculation attribute with mapGetters: bigSum (array writing method)
       ...mapGetters(['bigSum'])
   },
  1. mapActions method: a method used to help us generate a dialogue with actions, that is, a function containing $store.dispatch(xxx)
   methods:{
       //Generated by mapActions: incrementadd and incrementWait (object form)
       ...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
   
       //Generated by mapActions: incrementadd and incrementWait (array form)
       ...mapActions(['jiaOdd','jiaWait'])
   }
  1. mapMutations method: a method used to help us generate a conversation with mutations, that is, a function containing $store.commit(xxx)
   methods:{
       //Generated by mapActions: increment and increment (in object form)
       ...mapMutations({increment:'JIA',decrement:'JIAN'}),
       
       //Generated by mapMutations: JIA, JIAN (object form)
       ...mapMutations(['JIA','JIAN']),
   }

Note: when mapActions and mapMutations are used, if parameters need to be passed: pass the parameters when binding events in the template, otherwise the parameters are event objects.

7. Modularization + namespace

  1. Purpose: to better maintain the code and make the classification of multiple data more clear.

  2. Modify store.js

   const countAbout = {
     namespaced:true,//Open namespace
     state:{x:1},
     mutations: { ... },
     actions: { ... },
     getters: {
       bigSum(state){
          return state.sum * 10
       }
     }
   }
   
   const personAbout = {
     namespaced:true,//Open namespace
     state:{ ... },
     mutations: { ... },
     actions: { ... }
   }
   
   const store = new Vuex.Store({
     modules: {
       countAbout,
       personAbout
     }
   })
  1. After the namespace is opened, read the state data from the component:
   //Method 1: read directly by yourself
   this.$store.state.personAbout.list
   //Method 2: read with mapState:
   ...mapState('countAbout',['sum','school','subject']),
  1. After the namespace is opened, the getters data is read from the component:
   //Method 1: read directly by yourself
   this.$store.getters['personAbout/firstPersonName']
   //Method 2: read with mapGetters:
   ...mapGetters('countAbout',['bigSum'])
  1. After namespace is opened, dispatch is invoked in the component.
   //Method 1: directly dispatch yourself
   this.$store.dispatch('personAbout/addPersonWang',person)
   //Method 2: with mapActions:
   ...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
  1. After namespace is opened, commit is invoked in the component.
   //Method 1: commit yourself directly
   this.$store.commit('personAbout/ADD_PERSON',person)
   //Method 2: with mapMutations:
   ...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),

route

  1. Understanding: a route is a set of key - value s. Multiple routes need to be managed by a router.
  2. Front end Routing: key is the path and value is the component.

1. Basic use

  1. Install Vue router, command: NPM I Vue router

  2. Application plug-in: Vue.use(VueRouter)

  3. Write router configuration items:

   //Introducing VueRouter
   import VueRouter from 'vue-router'
   //Introducing Luyou components
   import About from '../components/About'
   import Home from '../components/Home'
   
   //Create a router instance object to manage groups of routing rules
   const router = new VueRouter({
   	routes:[
   		{
   			path:'/about',
   			component:About
   		},
   		{
   			path:'/home',
   			component:Home
   		}
   	]
   })
   
   //Exposure router
   export default router
  1. Achieve switching (active class configurable highlight style)
   <router-link active-class="active" to="/about">About</router-link>
  1. Specify display location
   <router-view></router-view>

2. Several points for attention

  1. Routing components are usually stored in the pages folder, and general components are usually stored in the components folder.
  2. By switching, "hidden" routing components are destroyed by default and can be mounted when necessary.
  3. Each component has its own $route attribute, which stores its own routing information.
  4. There is only one router in the whole application, which can be obtained through the $router attribute 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 child routing through children
   			{
   				path:'news', //Be sure not to write: / news here
   				component:News
   			},
   			{
   				path:'message',//Do not write: / message here
   				component:Message
   			}
   		]
   	}
   ]
  1. Jump (to write the full path):
   <router-link to="/home/news">News</router-link>

4. query parameters of route

  1. Transfer parameters
   <!-- Jump and carry query Parameters, to String writing -->
   <router-link :to="/home/message/detail?id=666&title=Hello">Jump</router-link>
   				
   <!-- Jump and carry query Parameters, to Object writing of -->
   <router-link 
   	:to="{
   		path:'/home/message/detail',
   		query:{
   		   id:666,
               title:'Hello'
   		}
   	}"
   >Jump</router-link>
  1. Receiving parameters:
   const id = $route.query.id
   const title = $route.query.title

5. Named route

  1. Function: it can simplify the jump of routing.

  2. How to use

    1. Name the route:
      {
      	path:'/demo',
      	component:Demo,
      	children:[
      		{
      			path:'test',
      			component:Test,
      			children:[
      				{
                            name:'hello' //Name the route
      					path:'welcome',
      					component:Hello,
      				}
      			]
      		}
      	]
      }
  1. Simplified jump:
      <!--Before simplification, you need to write a complete path -->
      <router-link to="/demo/test/welcome">Jump</router-link>
      
      <!--After simplification, jump directly through the name -->
      <router-link :to="{name:'hello'}">Jump</router-link>
      
      <!--Simplified writing fit transfer parameters -->
      <router-link 
      	:to="{
      		name:'hello',
      		query:{
      		   id:666,
                  title:'Hello'
      		}
      	}"
      >Jump</router-link>

6. params parameters of route

  1. Configure the route and declare to receive params parameters
   {
   	path:'/home',
   	component:Home,
   	children:[
   		{
   			path:'news',
   			component:News
   		},
   		{
   			component:Message,
   			children:[
   				{
   					name:'xiangqing',
   					path:'detail/:id/:title', //Receive params parameters using placeholder declarations
   					component:Detail
   				}
   			]
   		}
   	]
   }
  1. Transfer parameters
   <!-- Jump and carry params Parameters, to String writing -->
   <router-link :to="/home/message/detail/666/Hello">Jump</router-link>
   				
   <!-- Jump and carry params Parameters, to Object writing of -->
   <router-link 
   	:to="{
   		name:'xiangqing',
   		params:{
   		   id:666,
               title:'Hello'
   		}
   	}"
   >Jump</router-link>

Special note: when the route carries params parameters, if the object writing method of to is used, the path configuration item cannot be used, but the name configuration must be used!

  1. Receiving parameters:
 const id = $route.params.id
 const tilte = $route.params.title

7. props configuration of routing

Function: make it easier for routing components to receive parameters

{
	name:'xiangqing',
	path:'detail/:id',
	component:Detail,

	//The first way to write it: 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 method: if props value is Boolean and Boolean value is true, all params parameters received by the route will be passed to Detail component through props
	// props:true
	
	//The third way to write: props value is a function, and each group of key values in the object returned by this function will be passed to the Detail component through props
	props(route){
		return {
			id:route.query.id,
			title:route.query.title
		}
	}
}

8. replace attribute of < router link >

  1. Function: control the mode of operating browser history during route jump
  2. There are two ways to write browser history: push and replace. Push is to add history and replace is to replace the current record. The default value for route jump is push
  3. How to start the replace mode: < router link replace... > News < / router link >

9. Program route navigation

  1. Function: route jump is realized without the help of < router link >, making route jump more flexible

  2. Specific code:

   //Two API s 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 off
   this.$router.go() //You can move forward or backward

10. Cache routing component

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

  2. Specific code:

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

11. Two new life cycle hooks

  1. Function: the two hooks unique to the routing component are used to capture the activation status of the routing component.
  2. Specific name:
    1. Triggered when the activated routing component is activated.
    2. Triggered when the deactivated routing component is deactivated.

12. Route guard

  1. Function: to control the routing permission

  2. Classification: Global guard, exclusive guard and in component guard

  3. Global guard:

  //Global front guard: executed during initialization and before each route switching
  router.beforeEach((to,from,next)=>{
  	console.log('beforeEach',to,from)
  	if(to.meta.isAuth){ //Judge whether the current route needs permission control
  		if(localStorage.getItem('school') === 'atguigu'){ //Specific rules for permission control
  			next() //Release
  		}else{
  			alert('No permission to view')
  			// next({name:'guanyu'})
  		}
  	}else{
  		next() //Release
  	}
  })
  
  //Global post guard: executed during initialization and after each route switch
  router.afterEach((to,from)=>{
  	console.log('afterEach',to,from)
  	if(to.meta.title){ 
  		document.title = to.meta.title //Modify the title of the page
  	}else{
  		document.title = 'vue_test'
  	}
  })
  1. Exclusive guard:
   beforeEnter(to,from,next){
   	console.log('beforeEnter',to,from)
   	if(to.meta.isAuth){ //Judge whether the current route needs permission control
   		if(localStorage.getItem('school') === 'atguigu'){
   			next()
   		}else{
   			alert('No permission to view')
   			// next({name:'guanyu'})
   		}
   	}else{
   		next()
   	}
   }
  1. Guard inside the assembly:
   //Entry guard: called when entering the component through routing rules
   beforeRouteEnter (to, from, next) {
   },
   //Leave guard: it is called when leaving the component through routing rules
   beforeRouteLeave (to, from, next) {
   }

13. Two working modes of router

  1. What is a hash value for a url? --# And what follows 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. The address always carries a # number, 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. Good compatibility.
  4. history mode:
    1. The address is clean and beautiful.
    2. Compatibility is slightly worse than hash mode.
    3. When the application is deployed online, it needs the support of back-end personnel to solve the problem of refreshing the page server 404.

Posted by livepjam on Wed, 13 Oct 2021 16:29:00 -0700