Basic example

<! -- Counter. Vue: Define Counter component --><template>
  <button @click="inc">I got clicked {{count}} times</button>
</template>
<script>
  export default {
    data() { return { count: 0 }},
    methods: {
      inc() { this.count++; }}}</script>
Copy the code
<! -- App.vue --><template>
  <div>
    <counter style="margin-right: 5px;"/>
    <counter />
  </div>
</template>
<script>
  import Counter from './Counter';

  export defaults {
    components: { Counter }
  }
</script>
Copy the code

  • Can be reused, different instances of the same component do not affect each other
  • Enhanced semantics:<div id="counter"> VS <counter >

Multi-component development fundamentals

  • One file per component, with suffix.vueAt the end, usually putsrc\componentsdirectory
  • The component file name is usually the name of the component, using the camel name convention, such asCounter.vue.ItemCounter.vue

Parent component, child component

  • Suppose there are two components A and B inBComponentAComponent, two file contents
  • Component B is called the parent of component A
    • The parent component needs to import child component modules:import AComponent from './A'
    • The parent component needs to be declaredcomponentsProperties,components: { AComponent, CComponent }
  • Component A is called A child of component B
<! -- A.vue --><template>
   <h1>Component A</h1>
</template><! -- B.vue --><template>
  <div>
    <a-component v-for="i in [1, 2]" :key="i" />
  </div>
</template>

<script>
import AComponent from './A'
export default {
  components: { AComponent }
}
</script>
Copy the code

The parent component passes properties to the child component

  • The child component evaluates and renders differently depending on the value passed in
  • In most scenarios, attributes need to be passed to child components for reuse purposes
  • Child components:
    • usepropsArray receives properties passed by the parent component
    • propProperties anddataThe properties generated by the method are identical in usage
      • A template has the same syntax as an instruction, for examplev-for="item in items".{{ name }}
      • in<script>Use to addthis, such asthis.items
  • The parent component:
    • Property values to be passed to child components, such as:items="user.items".:name="user.name"
<! -- Child component: child.vue --><template>
   <div>
       <h3>There are {{count}} items in {{name}}</h3>
       <ul>
           <li v-for="item in items" :key="item.id"> {{ item.text }} </li>
       </ul>
   </div>
</template>
<script>
    export default {
        props: ['name'.'items'].computed: {
            count() {
                return this.items.length
            }
        }
    }
</script><! -- Parent component: parent.vue --><template>
    <div>
        <child :items="user.items" :name="user.name" />
    </div>
</template>
<script>
    import Child from './Child'
    
    export default {
        components: { Child },
        data() {
            return {
                user: { 
                  name: 'zhangsan'.items: [{id: 1.text: 'Study hard'}, 
                    {id: 2.text: "Up every day"}]}}}}</script>
Copy the code

Routing: the Vue – the Router

  • Before routing: Compose applications by combining components
  • The page address is always index.html and the specific path associated with the content cannot be displayed
<template>
  <div>
    <div id="navbar">
       <button @click="select('about')">About me</button>
       <button @click="select('learn')">Travel diary</button>
    </div>
    <div>
      <about v-if="selected === 'about'" />
      <travel v-if="selected === 'travel'" />
    </div>
  </div>
</template>
<script>
  export default {
    data() { return { selected: 'about' }},
    methods: {
      select(value) { this.selected === value; }}}</script>
Copy the code
  • Once you have components: map components to routes, and then tell the Vue Router where to render them
    • Install vue-Router library in project root directory
      • yarn add vue-routeror
      • npm install --Save vue-router
<template>
  <div>
    <div id="navbar">
      <! -- Use router-link to navigate -->
      <! -- Use the to attribute to specify the link to be removed -->
      <router-link to="/about">About me</router-link>
      <router-link to="/travel">Travel diary</router-link>
    </div>
    <div>
      <! -- Route exit -->
      <! -- Routing matching components will be rendered here -->
      <router-view></router-view>
    </div>
  </div>
</template>
<script>
  import About from './components/about'
  import Travel from './components/travel'
  import VueRouter from './vue-router'
  
  const routes = [
    { path: '/about'.component: About },
    { path: '/travel'.component: Travel }
  ]
  
  const router = new VueRouter({ routes })
  
</script>
Copy the code

HTML 5 History pattern

  • Vue-router uses hash mode by default. It uses the HASH of URL to simulate a complete URL

    • Hash: indicates a position in the web page
      • <div id="print">... </div>
      • <a href="#print">
      • When an anchor point is clicked, no request is sent to the server
    • When the URL changes, the page does not reload
  • You can use history mode instead of hash mode

    const router = new VueRouter({
      mode: 'history'.routes: [...]. })Copy the code
    • Urls in history mode are more like normal urls

Status management: Vuex

  • Vuex is a state management mode developed specifically for vue.js applications
  • Centralized storage is used to manage the state of all application components

Status management mode

  • Let’s start with a simple counting application

    <! -- view --> <template> <div>{{ count }}</div> </template> <script> export default { // state data() { return { count: 0}; }, // actions methods: { inc() { this.count++; } } } </script>Copy the code
  • Vue applications generally include

    • State: data that drives the application
    • View: map state to the view declaratively
    • Actions: Changes in state in response to user input on the view
  • For simple applications (single component applications and simple multi-component applications), data flow is easy to manage

  • However, when the application encountersMultiple components share the same state
    • Multiple views depend on the same state
      • Parameters are passed through multiple layers to reach the underlying component
      • There is nothing you can do about the state between sibling components
    • Actions from different views need to change the same state
      • Events can be used to change and synchronize state, but maintenance is poor
  • So, think about itState shared by different components is extracted and managed as a global singleton
    • The component tree is a huge view
    • Any node in the component tree can read the state and trigger the behavior
  • Applicable situations
    • Large single-page applications
    • For simple applications, consider the Store model

Store model

  • Put all shared states in the state object
  • All shared state operations are placed in the Store object
var store = {
  debug: true.state: {
    message: 'Hello! '
  },
  setMessageAction (newValue) {
    if (this.debug) console.log('setMessageAction triggered with', newValue)
    this.state.message = newValue
  },
  clearMessageAction () {
    if (this.debug) console.log('clearMessageAction triggered')
    this.state.message = ' '}}Copy the code
  • Components can use shared state or have their own private state

  • Components cannot directly modify the state of the share. Instead, they execute actions to notify the store of the change

Vuex core concept: State

  • Single state tree: Each application contains only one store instance

    • Remain responsive: The DOM of all components is updated as soon as the state in the Store changes
  • Get the Vuex state in the Vue component

    • Using computed properties

      • Problem: Each component is directly dependent on global state
      const Counter = { template: `<div>{{ count}}</div>`, computed: { count() { return store.state.count; }}}Copy the code
    • Inject state into child components from the root component

      • Register the store from the root component:const app = new Vue({ store })
      • Child component throughthis.$storeFor a visit
      • Problem: When a component requires more than one state, these computed properties can be repetitive and redundant
      const Counter = { template: `<div>{{ count}}</div>`, computed: { count() { return this.$store.state.count; }}}Copy the code
    • Use the mapState function

      import { mapState } from 'vuex'
      
      const Counter = {
        template: `<div>{{ count}}</div>`.computed: mapState({
          count: state= > state.count
        })
      }
      Copy the code
      • If the name of the evaluated property is the same as the name of the state property
      const Counter = {
        template: `<div>{{ count}}</div>`.computed: mapState([
          // Map this.count to store.state.count
          'count'])}Copy the code
      • The mapState function returns an object, so how can it be mixed with local computed properties
        • Use extension operators
      const Counter = {
        template: `<div>{{ count}}</div>`.computed: {
          ...mapState([
            // Map this.count to store.state.count
            'count'
          ]),
          localComputed(){... }}}Copy the code

Vuex core concept: Getter

  • Derive some state from the store state

    computed: {
      doneTodosCount() {
         return this.$store.state.todos.filter(todo= >todo.done).length; }}Copy the code