Vue -- 08 Vue component development

Keywords: Vue

Vue -- 08 Vue component development

8.1 concept of components

Component system is another important concept of Vue because it is an abstraction that allows us to build large applications using small, independent and usually reusable components. When you think about it, almost any type of application interface can be abstracted into a component tree:

 

 

  In Vue, a component is essentially a Vue instance with predefined options. Registering components in Vue is simple:

// The definition name is todo-item New components for
Vue.component('todo-item', {
  template: '<li>This is a to-do item</li>'
})

var app = new Vue(...)

Now you can use it to build another component template:

<ol>
  <!-- Create a todo-item Instance of component -->
  <todo-item></todo-item>
</ol>

 ** Component is the encapsulation of detail view. Each component includes:

HTML structure

CSS Style

JavaScript behavior: data / methods behavior

**Improve development efficiency, enhance maintainability, and better solve the three code problems of high coupling, low cohesion and no reuse

**The idea of component in Vue is based on React

**At present, the mainstream front-end frameworks: Angular, React and Vue are component-based development ideas

 

8.2 basic use of components

  In order to be used in the template, these components must be registered so that Vue can recognize the registration types: global registration and local registration

**Global registration

Vue.component('Component name',{
template: 'Define component templates',
data: function(){ //data Option must be a function in a component
return {}
}
//Other options: methods
})

Component name: it can be named by camel case or kebab case

However, only horizontal lines can be used to reference components in DOM

The official strongly recommends that the component name be all lowercase and must contain a hyphen

Template: defines the view template of the component

data: must be a function in a component

<body>

    <div id="app">
        <component-a></component-a>
    </div>

    <script src="./node_modules/vue/dist/vue.js"></script>
    <script>
        /*
        Global component registration:
            After registration, they can be used in the template of any newly created Vue root instance (new Vue)
        Parameter 1: component name
            1.You can use camel case or kebab case naming
            2.DOM Components can only be referenced with horizontal lines in
        */
        Vue.component('component-a', {
            // template Option specifies the template code for this component
            template: `<div><h3>Head assembly--{{ name }}</h3></div>`,
            // data Must be a function
            data: function () {
                return {
                    name: 'hello Vue!'
                }
            }
        })

        var vm = new Vue({
            el: '#app'
        });
    </script>
</body>

**Local registration

Generally, some non general parts are registered as local components, which are generally only applicable to the current project

1. JS Object to define the component:
var ComponentA = { data: function(){}, template: 'Component template A'}
var ComponentA = { data: function(){}, template: 'Component template A'}
2. stay Vue In the instance components Components referenced in options:
new Vue({
  el: '#app',
  data: {},
  components: { // Component options
    'component-a': ComponentA // key: Component name, value: Referenced component object
    'component-b': ComponentB
  }
})
<body>
    <div id="app">
        <component-b></component-b>
    </div>
    <script src="./node_modules/vue/dist/vue.js"></script>
    <script>
        var ComponentB = {
            template: '<div> This is:{{ name }}</div>',
            data: function () {
                return {
                    name: 'Local component'
                }
            }
        }
        var vm = new Vue({
            el: '#app',
            components: {
                'component-b': ComponentB
            }
        });
    </script>
</body>

**Summary:

*Components are reusable Vue instances and do not need to be instantiated manually

*Receive the same options as new Vue, such as data, computed, watch, methods, etc

*The data option of the component must be a function

 

8.3 examples of multiple components

  Component js file:

Header.js
Vue.component('app-header',{
    template:`<h1>Head assembly--{{ content }}</h1>`,
    data() {
        return {
            content: 'header-value',
        };
    },
})
Main.js
Vue.component('app-main', {
    template: `<ul>
                <li v-for="(item,index) in content">{{ item.name }}</li>
              </ul>`,
    data () {
        return {
            content: [
                { id: 1, name: 'customer management' },
                { id: 2, name: 'Supplier management' },
                { id: 3, name: 'information management' }
            ]
        };
    },
})
Footer.js
Vue.component('app-footer',{
    template:`<h3>Bottom assembly--{{ property }}</h3>`,
    data () {
        return {
            property: 'footer-value',
        };
    },
})

html

<body>
    <div id="app">
        <app-header></app-header>
        <app-main></app-main>
        <app-footer></app-footer>
    </div>

    <script src="./node_modules/vue/dist/vue.js"></script>
    <script src="./components/Header.js"></script>
    <script src="./components/Main.js"></script>
    <script src="./components/Footer.js"></script>
    <script>
        var vm = new Vue({
            el:'#app'
        });
    </script>

</body>

 

8.4 Componentization of bootstrap home page (key)

8.4.1   Home page analysis

Split multiple components on the first page:
a. head navigation area - AppNavbar
b. left menu bar area -- AppLeft
c. main area on the right -- AppHome
    d.DashBoard
    e.HomeList

8.4.2   Head navigation component registration   AppNavbar

AppNavbar.js: declare self calling function; And declare the window attribute, otherwise it cannot be called outside the function

;(function(){

    const template=`<nav class="navbar navbar-inverse navbar-fixed-top">
    <div class="container-fluid">
      <div class="navbar-header">
        <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
          aria-expanded="false" aria-controls="navbar">
          <span class="sr-only">Toggle navigation</span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
        </button>
        <a class="navbar-brand" href="#">{{ title }}</a>
      </div>
      <div id="navbar" class="navbar-collapse collapse">
        <ul class="nav navbar-nav navbar-right">
          <li><a href="#">Dashboard</a></li>
          <li><a href="#">Settings</a></li>
          <li><a href="#">Profile</a></li>
          <li><a href="#">Help</a></li>
        </ul>
        <form class="navbar-form navbar-right">
          <input @blur="searchBlur" type="text" class="form-control" placeholder="Search...">
        </form>
      </div>
    </div>
  </nav>`;

    window.AppNavbar ={
        template,
        data() {
            return {
                title: 'Dream Valley',
            };
        },
        methods:{
            searchBlur(){
                alert('Lose focus!');
            }
        }

    }

})()

index.html page reference   AppNavbar.js and declare the component

<script src="./components/AppNavbar.js"></script>
 <!--Head navigation area-->
    <app-navbar></app-navbar>

8.4.3   Left navigation component registration   AppLeft

;(function(){

    const template=`<div class="col-sm-3 col-md-2 sidebar">
    <ul class="nav nav-sidebar">
      <li class="active"><a href="#">Overview <span class="sr-only">(current)</span></a></li>
      <li><a href="#">Reports</a></li>
      <li><a href="#">Analytics</a></li>
      <li><a href="#">Export</a></li>
    </ul>
    <ul class="nav nav-sidebar">
      <li><a href="">Nav item</a></li>
      <li><a href="">Nav item again</a></li>
      <li><a href="">One more nav</a></li>
      <li><a href="">Another nav item</a></li>
      <li><a href="">More navigation</a></li>
    </ul>
    <ul class="nav nav-sidebar">
      <li><a href="">Nav item again</a></li>
      <li><a href="">One more nav</a></li>
      <li><a href="">Another nav item</a></li>
    </ul>
  </div>`;

    window.AppLeft={
        template
    }

})()
<script src="./components/AppLeft.js"></script>
<!--Left menu bar area-->
        <app-left></app-left>

8.4.4   Right main page

It is divided into three components: AppHome/DashBoard/HomeList

AppHome is the parent component and DashBoard and HomeList are the child components

AppHome.js

;(function(){

    const template=` <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">

    <!--Upper right area-->
    <h1 class="page-header">Dashboard</h1>
    <dash-board></dash-board>

    <!--Lower right area-->
    <h2 class="sub-header">Section title</h2>
    <home-list></home-list>
  </div>`;

    window.AppHome={
        template,
        components:{
            DashBoard,
            HomeList
        }
    }

})()

DashBoard.js

;(function(){

    const template=`<div class="row placeholders">
    <div class="col-xs-6 col-sm-3 placeholder">
      <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200"
        height="200" class="img-responsive" alt="Generic placeholder thumbnail">
      <h4>Label</h4>
      <span class="text-muted">Something else</span>
    </div>
    <div class="col-xs-6 col-sm-3 placeholder">
      <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200"
        height="200" class="img-responsive" alt="Generic placeholder thumbnail">
      <h4>Label</h4>
      <span class="text-muted">Something else</span>
    </div>
    <div class="col-xs-6 col-sm-3 placeholder">
      <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200"
        height="200" class="img-responsive" alt="Generic placeholder thumbnail">
      <h4>Label</h4>
      <span class="text-muted">Something else</span>
    </div>
    <div class="col-xs-6 col-sm-3 placeholder">
      <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200"
        height="200" class="img-responsive" alt="Generic placeholder thumbnail">
      <h4>Label</h4>
      <span class="text-muted">Something else</span>
    </div>
  </div>`;

    window.DashBoard={
        template
    }

})()

HomeList.js

;(function(){

    const template=`<div class="table-responsive">
    <table class="table table-striped">
      <thead>
        <tr>
          <th>#</th>
          <th>Header</th>
          <th>Header</th>
          <th>Header</th>
          <th>Header</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>1,001</td>
          <td>Lorem</td>
          <td>ipsum</td>
          <td>dolor</td>
          <td>sit</td>
        </tr>
        <tr>
          <td>1,002</td>
          <td>amet</td>
          <td>consectetur</td>
          <td>adipiscing</td>
          <td>elit</td>
        </tr>
        <tr>
          <td>1,003</td>
          <td>Integer</td>
          <td>nec</td>
          <td>odio</td>
          <td>Praesent</td>
        </tr>
        <tr>
          <td>1,003</td>
          <td>libero</td>
          <td>Sed</td>
          <td>cursus</td>
          <td>ante</td>
        </tr>
        <tr>
          <td>1,004</td>
          <td>dapibus</td>
          <td>diam</td>
          <td>Sed</td>
          <td>nisi</td>
        </tr>
        <tr>
          <td>1,005</td>
          <td>Nulla</td>
          <td>quis</td>
          <td>sem</td>
          <td>at</td>
        </tr>
        <tr>
          <td>1,006</td>
          <td>nibh</td>
          <td>elementum</td>
          <td>imperdiet</td>
          <td>Duis</td>
        </tr>
        <tr>
          <td>1,007</td>
          <td>sagittis</td>
          <td>ipsum</td>
          <td>Praesent</td>
          <td>mauris</td>
        </tr>
        <tr>
          <td>1,008</td>
          <td>Fusce</td>
          <td>nec</td>
          <td>tellus</td>
          <td>sed</td>
        </tr>
        <tr>
          <td>1,009</td>
          <td>augue</td>
          <td>semper</td>
          <td>porta</td>
          <td>Mauris</td>
        </tr>
        <tr>
          <td>1,010</td>
          <td>massa</td>
          <td>Vestibulum</td>
          <td>lacinia</td>
          <td>arcu</td>
        </tr>
        <tr>
          <td>1,011</td>
          <td>eget</td>
          <td>nulla</td>
          <td>Class</td>
          <td>aptent</td>
        </tr>
        <tr>
          <td>1,012</td>
          <td>taciti</td>
          <td>sociosqu</td>
          <td>ad</td>
          <td>litora</td>
        </tr>
        <tr>
          <td>1,013</td>
          <td>torquent</td>
          <td>per</td>
          <td>conubia</td>
          <td>nostra</td>
        </tr>
        <tr>
          <td>1,014</td>
          <td>per</td>
          <td>inceptos</td>
          <td>himenaeos</td>
          <td>Curabitur</td>
        </tr>
        <tr>
          <td>1,015</td>
          <td>sodales</td>
          <td>ligula</td>
          <td>in</td>
          <td>libero</td>
        </tr>
      </tbody>
    </table>
  </div>`;

    window.HomeList={
        template
    }

})()

index.html

<body>

  <div id="app">

    <!--Head navigation area-->
    <app-navbar></app-navbar>

    <!--Core area:Left and right-->
    <div class="container-fluid">
      <div class="row">

        <!--Left menu bar area-->
        <app-left></app-left>

        <!--Master page area on the right: It is divided into upper and lower areas-->
        <app-home></app-home>

      </div>
    </div>

  </div>

  <script src="../node_modules/vue/dist/vue.js"></script>
  <script src="./components/AppNavbar.js"></script>
  <script src="./components/AppLeft.js"></script>
  <script src="./components/Home/DashBoard.js"></script>
  <script src="./components/Home/HomeList.js"></script>
  <script src="./components/Home/AppHome.js"></script>
  <script>
    var vm = new Vue({
      el: '#app',
      components:{
        AppNavbar,
        AppLeft,
        AppHome
      }

    });
  </script>

</body>

  8.4.5 extreme modularization

The root component extracts App.js. Note: the root element in the template template must be, so add < div > < / div > to the outer layer of the extracted content. Be sure not to reduce it, or an error will be reported!

Error message:

App.js declares the previous component AppHome/AppNavbar/AppLeft in app.js

; (function () {

    const template = `
    
        <!--Head navigation area-->
        <app-navbar></app-navbar>

        <!--Core area:Left and right-->
        <div class="container-fluid">
        <div class="row">

            <!--Left menu bar area-->
            <app-left></app-left>

            <!--Master page area on the right: It is divided into upper and lower areas-->
            <app-home></app-home>

        </div>
        </div>
    
    `;

    window.App = {
        template,
        components:{
            AppNavbar,
            AppLeft,
            AppHome
          }
    }

})()

The index.html page refers to App.js and declares the components of App

<body>

  <div id="app">

   <app></app>

  </div>

  <script src="../node_modules/vue/dist/vue.js"></script>
  <script src="./components/AppNavbar.js"></script>
  <script src="./components/AppLeft.js"></script>
  <script src="./components/Home/DashBoard.js"></script>
  <script src="./components/Home/HomeList.js"></script>
  <script src="./components/Home/AppHome.js"></script>

  <script src="./App.js"></script>
  <script>
    var vm = new Vue({
      el: '#app',
      components:{
        App
      }
    });
  </script>

</body>

Note: it is not good to reference App components through < / App > under < div id = "App" > because there will be an extra div in the page code
Better, you don't need to use < / App > to reference App components under < div id = "App" >,
You can reference the component < app > < / APP > through the template option of the Vue root instance, and then replace the rendering results in the template
#app tag.

Currently, there are JS codes in the index.html file, which can be extracted and put into main.js

main.js 
var vm = new Vue({
    el: '#app',
    template:'<app></app>',
    components:{
      App
    }
  });

index.html

<body>

  <div id="app">

  </div>

  <script src="../node_modules/vue/dist/vue.js"></script>
  <script src="./components/AppNavbar.js"></script>
  <script src="./components/AppLeft.js"></script>
  <script src="./components/Home/DashBoard.js"></script>
  <script src="./components/Home/HomeList.js"></script>
  <script src="./components/Home/AppHome.js"></script>

  <script src="./App.js"></script>
  <script src="./main.js"></script>

</body>

 

8.5 precautions for componentization

**The component can be understood as a special Vue instance, which does not need to be instantiated manually, and manages its own template template
**The template of a component must have one and only one root node
**The data option of the component must be a function, and the function body returns an object
**Components are independent of each other. You can configure some of your own option resources, such as data, methods, computed, and so on
**Thought: components manage themselves without affecting others

 

8.6 communication between Vue parent and child components

8.6.1 communication mode between components

1. Pass data from props parent component to child component
2. $emit custom event
3. slot distribution

8.6.2 communication rules between components

1. Do not directly modify the data passed by the parent component in the child component.
2. During data initialization, you should see whether the initialized data is used in multiple components. If it needs to be used in multiple components, it should be initialized in the parent component
Medium; If it is used in only one component, it is initialized in the component to be used.
3. The method (function) for updating data should be defined in which component the data is initialized in.

8.6.3 props transfer data to sub components

  8.6.3.1   Define props in the declared component object (declared in sub components)

  Use the props option in the declaration component object to specify

const MyComponent = {
    template: '<div></div>',
    props: There are three ways to change the value here,
    components: {
    }
}

  Method 1: specify the transfer attribute name. Note that it is in the form of array

props: ['id','name','salary', 'isPublished', 'commentIds', 'author', 'getEmp']

  Method 2: specify the transfer attribute name and data type. Note that it is in the form of object

props:{
  id:Number,
  name:String,
  salary:Number,
  isPublished:Boolean,
  commentIds:Array,
  author:Object,
  getEmp:Function    
}

  Method 3: specify attribute name, data type, necessity and default value

props: {
name: {
type: String,
required: true,
default: 'mxg'
}
}

  8.6.3.2   Dynamic assignment when referencing a component (parent component)

   When a component is referenced, it is dynamically assigned by v-bind

<my-component v-bind:id="2" :name="meng" :salary="9999" :is-published="true" :comment-ids="[1, 2]"
:author="{name: 'alan'}" :get-emp="getEmp" >
</my-component>

  8.6.3.3   Transfer data attention

1. props is only used to transfer data from parent component to child component
2. All tag attributes will become the attributes of component objects, which can be directly referenced in the template page
3. Questions:
a. if it is necessary to transfer data to non child offspring, it must be transferred layer by layer
b. brother components cannot communicate directly with props, but only with the help of parent components

8.6.4 props cases -- list rendering

Render DashBoard and HomesList data, which is defined by the parent component AppHome

AppHome.js   -- Call subcomponent v-bind to pass parameters

; (function () {

    const template = ` <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">

    <!--Upper right area-->
    <h1 class="page-header">Dashboard</h1>
    <dash-board :hobbies='hobbies'></dash-board>

    <!--Lower right area-->
    <h2 class="sub-header">Section title</h2>
    <home-list :empList='empList'></home-list>
  </div>`;

    window.AppHome = {
        template,
        components: {
            DashBoard,
            HomeList
        },
        data() {
            return {
                hobbies: ['read a book', 'Billiards', 'sleep', 'Lu code'],//dashboard Display data
                empList: [//homelist Display data
                    { id: 1, name: 'Little dream 1', salary: 80001 },
                    { id: 2, name: 'Little dream 2', salary: 80002 },
                    { id: 3, name: 'Little dream 3', salary: 80003 },
                    { id: 4, name: 'Little dream 4', salary: 80004 }
                ]
            };
        },
    }

})()

DashBoard.js

;(function(){

    const template=`
    <div class="row placeholders">
        <div v-for='(item,index) in hobbies' class="col-xs-6 col-sm-3 placeholder">
        <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200"
            height="200" class="img-responsive" alt="Generic placeholder thumbnail">
        <h4>{{item}}</h4>
        <span class="text-muted">Something else</span>
        </div>
    </div>
    `;

    window.DashBoard={
        template,
        props:['hobbies'] //Define the data passed from the parent component
    }

})()

HomeList.js 

**Encapsulate tr in HomeList component in a separate component, named Item

Item.js   -- Define props defines the parameters passed from the parent component

;(function(){

    const template=`
    <tr>
        <td>{{ emp.id }}</td>
        <td>{{ emp.name }}</td>
        <td>{{ emp.salary }}</td>
    </tr>
    `;

    window.Item={
        template,
        props:{//
            emp:Object
        }
    }

})()

HomeList.js  --

;(function(){

    const template=`<div class="table-responsive">
    <table class="table table-striped">
      <thead>
        <tr>
          <th>id</th>
          <th>name</th>
          <th>salary</th>
        </tr>
      </thead>
      <tbody>
        <item v-for='(emp,index) in empList' :emp='emp'></item>
      </tbody>
    </table>
  </div>`;

    window.HomeList={
        template,
        props:{ //Receive the data from the parent component, and then pass the objects in the array to the child component
            empList:Array
        },
        components:{
            Item
        }
    }

})()

8.6.5 props case -- implementation of employee deletion function

According to the principle of component communication, the data defined in which component defines the relevant methods on which component!!!

Because the emplist data needs to be deleted, the deletion method is defined on the AppHome component and passed to the child component

; (function () {

    const template = ` <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">

    <!--Upper right area-->
    <h1 class="page-header">Dashboard</h1>
    <dash-board :hobbies='hobbies'></dash-board>

    <!--Lower right area-->
    <h2 class="sub-header">Section title</h2>
    <home-list :empList='empList' :delItem="delItem"></home-list>
  </div>`;

    window.AppHome = {
        template,
        components: {
            DashBoard,
            HomeList
        },
        data() {
            return {
                hobbies: ['read a book', 'Billiards', 'sleep', 'Lu code'],//dashboard Display data
                empList: [//homelist Display data
                    { id: 1, name: 'Little dream 1', salary: 80001 },
                    { id: 2, name: 'Little dream 2', salary: 80002 },
                    { id: 3, name: 'Little dream 3', salary: 80003 },
                    { id: 4, name: 'Little dream 4', salary: 80004 }
                ]
            };
        },
        methods: {
            // Deletes the data of the specified subscript
            // Because delete emp Yes empList Do the update operation,
            // and empList It is initialized in the current component, so the deleted function should be defined in this component
            delItem(index) {
                this.empList.splice(index, 1);
            }
        }
    }

})()

**The Item component is not a child component of the AppHome component, but a child component, so it needs to be passed layer by layer, first to the HomeList component, and then to the Item component

HomeList component

;(function(){

    const template=`<div class="table-responsive">
    <table class="table table-striped">
      <thead>
        <tr>
          <th>id</th>
          <th>name</th>
          <th>salary</th>
          <th>operation</th>
        </tr>
      </thead>
      <tbody>
        <item v-for='(emp,index) in empList' :key='emp.id' :emp='emp'  :index='index' :delItem='delItem'></item>
      </tbody>
    </table>
  </div>`;

    window.HomeList={
        template,
        props:{ //Receive the data from the parent component, and then pass the objects in the array to the child component
            empList:Array,
            delItem:Function  //Layer by layer transfer
        },
        components:{
            Item
        }
    }

})()

Item component

; (function () {

    const template = `
    <tr>
        <td>{{ emp.id }}</td>
        <td>{{ emp.name }}</td>
        <td>{{ emp.salary }}</td>
        <td><a href='#' @click='deleteItem'>delete</a></td>
    </tr>
    `;

    window.Item = {
        template,
        props: {//
            emp: Object,
            delItem: Function,
            index: Number
        },
        methods: {
            deleteItem() {
                // Remove index as index A record of,
                // Note: no less this
                this.delItem(this.index);
            }
        }
    }

})()

8.6.6 user defined events

Function: use custom events instead of props to pass in function form

a. Binding custom events

Define the event listening function in the parent component and reference the v-on bound event listening on the child component label.

// Binding via v-on
// @Custom event name = event listening function
// Trigger delete in subcomponent dashboard_ The delete hubby function is called using the hubby event
<dashboard @delete_hobby="deleteHobby"></dashboard>

b. Trigger listening event function execution

Function call to trigger listening event of parent component in child component

// Subcomponent trigger event function call
// this.$emit(Custom event name, data)
this.$emit('delete_emp', index)

c. Custom event note

1. Custom events are only used to send messages (data) from child components to parent components

2. Communication between intergenerational components or sibling components is not appropriate

8.6.7 user defined event cases

Delete icon elements in DashBoard

The delete function deleteHobby is defined in the parent component AppHome and passed to the child component through v-on custom events

AppHome.js

; (function () {

    const template = ` <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">

    <!--Upper right area-->
    <h1 class="page-header">Dashboard</h1>
    <dash-board :hobbies='hobbies' @del-Hobby="deleteHobby"></dash-board>

    <!--Lower right area-->
    <h2 class="sub-header">Section title</h2>
    <home-list :empList='empList' :delItem="delItem"></home-list>
  </div>`;

    window.AppHome = {
        template,
        components: {
            DashBoard,
            HomeList
        },
        data() {
            return {
                hobbies: ['read a book', 'Billiards', 'sleep', 'Lu code'],//dashboard Display data
                empList: [//homelist Display data
                    { id: 1, name: 'Little dream 1', salary: 80001 },
                    { id: 2, name: 'Little dream 2', salary: 80002 },
                    { id: 3, name: 'Little dream 3', salary: 80003 },
                    { id: 4, name: 'Little dream 4', salary: 80004 }
                ]
            };
        },
        methods: {
            // Deletes the data of the specified subscript
            // Because delete emp Yes empList Do the update operation,
            // and empList It is initialized in the current component, so the deleted function should be defined in this component
            delItem(index) {
                this.empList.splice(index, 1);
            },
            deleteHobby(index) {
                this.hobbies.splice(index, 1);
            }
        }
    }

})()

DashBoard.js

;(function(){
    const template=`
    <div class="row placeholders">
        <div v-for='(item,index) in hobbies' class="col-xs-6 col-sm-3 placeholder">
        <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200"
            height="200" class="img-responsive" alt="Generic placeholder thumbnail">
        <h4>{{item}}</h4>
        <span class="text-muted"><a @click='delHobby(index)' href="#"> delete</a></span>
        </div>
    </div>
    `;
    window.DashBoard={
        template,
        props:['hobbies'] ,//Define the data passed from the parent component
        methods:{
            delHobby(index){
                // Trigger in parent component del-Hobby Event to delete
                this.$emit('del-Hobby', index);
            }
        }
    }
})()

8.6.8 slot

Function: it is mainly used for the parent component to transfer tag + data to the child component (while the above prop and custom events only transfer data)
Scene: generally, the display effect needs to be switched dynamically at a certain location

a. Sub component definition slot

Define the slot in the sub component. When the parent component passes label data to the specified slot, the slot will be rendered, otherwise the slot will not be rendered

<div>
    <!-- name The property value specifies a unique slot name through which the parent component specifies label data-->
    <slot name="aaa">Uncertain label structure 1</slot>
    <div>Label structure determined by component</div>
    <slot name="bbb">Uncertain label structure 2</slot>
</div>

b. Parent component passes label data

<child>
    <!--slot The attribute value corresponds to the number of slots in the subcomponent name Attribute value-->
    <div slot="aaa">towards name=aaa Insert this label data at the slot of the</div>
    <div slot="bbb">towards name=bbb Insert this label data at the slot of the</div>
</child>

c. Slot considerations

1. It can only be used to transfer label + data from parent component to child component

2. The data processing in the transferred slot label needs to be defined in the parent component

8.6.9 slot cases

  Display the title of the Dashboard through the slot

  Define the title label of the Dashboard as slot < slot name = "Dashboard" > < / slot >

; (function () {

    const template = ` <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">

    <!--Upper right area-->
    <!--<h1 class="page-header">Dashboard</h1>-->
    <!--Define slot-->
    <slot name="dashboard"></slot>
    <dash-board :hobbies='hobbies' @del-Hobby="deleteHobby"></dash-board>

    <!--Lower right area-->
    <h2 class="sub-header">Section title</h2>
    <home-list :empList='empList' :delItem="delItem"></home-list>
  </div>`;

    window.AppHome = {
        template,
        components: {
            DashBoard,
            HomeList
        },
        data() {
            return {
                hobbies: ['read a book', 'Billiards', 'sleep', 'Lu code'],//dashboard Display data
                empList: [//homelist Display data
                    { id: 1, name: 'Little dream 1', salary: 80001 },
                    { id: 2, name: 'Little dream 2', salary: 80002 },
                    { id: 3, name: 'Little dream 3', salary: 80003 },
                    { id: 4, name: 'Little dream 4', salary: 80004 }
                ]
            };
        },
        methods: {
            // Deletes the data of the specified subscript
            // Because delete emp Yes empList Do the update operation,
            // and empList It is initialized in the current component, so the deleted function should be defined in this component
            delItem(index) {
                this.empList.splice(index, 1);
            },
            deleteHobby(index) {
                this.hobbies.splice(index, 1);
            }
        }
    }

})()

Pass label data to the slot defined in the subcomponent. Where the title is bound with the title data

; (function () {

    const template = `
    <div>
        <!--Head navigation area-->
        <app-navbar></app-navbar>

        <!--Core area:Left and right-->
        <div class="container-fluid">
        <div class="row">

            <!--Left menu bar area-->
            <app-left></app-left>

            <!--Master page area on the right: It is divided into upper and lower areas-->
            <app-home>
                <h1 slot="dashboard" class="page-header">{{title}}</h1>
            </app-home>

        </div>
        </div>
    </div>
    `;

    window.App = {
        template,
        components: {
            AppNavbar,
            AppLeft,
            AppHome
        },
        data() {
            return {
                title: 'Dashboard',
            };
        },
    }

})()

 

8.7 communication between non parent and child components

Vue.js can realize the communication between non parent and child components through PubSubJS library, and use the message publishing and subscription mode of PubSubJS for data
Pass.

Understanding: subscription information = = = = bind event listening, publish message = = = = trigger event.
Note: however, the subscribe event must be executed before publish ing the event.

Subscription message (binding event listening)

First subscribe to the message in the created hook function

//event The message name is received, data Is the data passed when receiving the publication
PubSub.subscribe('Message name (equivalent to event name)', function(event, data) {
    //Event callback processing
})

Publish message (trigger event)

PubSub.publish('Message name (equivalent to event name)', data)

case

1. Install PubSub JS

npm install pubsub-js

2.index.html import PubSub JS Library

<script src="./node_modules/vue/dist/vue.js"></script>
<script src="./node_modules/pubsub-js/src/pubsub.js"></script>

3.AppLeft.js subscription message

Initialize the quantity, subscribe to messages in the created hook, listen, and count the total number of deleted hobbies after they are deleted

; (function () {

  const template = `<div class="col-sm-3 col-md-2 sidebar">
    <ul class="nav nav-sidebar">
      <li class="active"><a href="#">Overview 
      <span v-show="delNum">({{ delNum }})</span></a>
      </li>
      <li><a href="#">Reports</a></li>
      <li><a href="#">Analytics</a></li>
      <li><a href="#">Export</a></li>
    </ul>
    <ul class="nav nav-sidebar">
      <li><a href="">Nav item</a></li>
      <li><a href="">Nav item again</a></li>
      <li><a href="">One more nav</a></li>
      <li><a href="">Another nav item</a></li>
      <li><a href="">More navigation</a></li>
    </ul>
    <ul class="nav nav-sidebar">
      <li><a href="">Nav item again</a></li>
      <li><a href="">One more nav</a></li>
      <li><a href="">Another nav item</a></li>
    </ul>
  </div>`;

  window.AppLeft = {
    template,
    data() {
      return {
        delNum: 0,
      };
    },
    created() {
      PubSub.subscribe('changeNum', (event, num) => { // Arrow function
        // Delete succeeded
        this.delNum = this.delNum + num
      })
    }
  }

})()

4.AppHome.js release message

deleteHobby(index) {
                this.hobbies.splice(index, 1);
                // Delete succeeded, publish message, navigation statistics
                PubSub.publish('changeNum', 1)
            }

Advantages: PubSubJS can realize communication between father and son or between non father and son

 

8.8 single document component

8.8.1 problems existing in the current project

**Global definitions enforce that the names in each component must not be repeated.
**String templates lack syntax highlighting, and ugly \ 'is needed when there are multiple lines of HTML.
**No CSS support means that CSS is obviously missing when HTML and JavaScript are componentized.
**There is no build step restriction. You can only use HTML and ES5 JavaScript, but not preprocessors, such as Pug
(formerly Jade) and Babel.

 

Single file components with a file extension of. vue provide a solution to all the above problems, and can also be used
Build tools such as webpack or Browserify.

 

8.8.2   Single file component template format

<template>
// Module of component
</template>
<script>
// Component JS
</script>
<style>
// Style of component
</style>

 

Posted by tonbah on Tue, 02 Nov 2021 22:13:48 -0700