Learning Vue from scratch (3)

Keywords: Javascript Vue Attribute

Let's learn about components from an example. vuejs2.0 Actual Warfare: Imitate Douban app Project, Create Custom Component tabbar

This example uses other components. For beginners, it will be confusing to know how to use so many components at once. So I rewrote this example, relying only on Vue.

Then it's better for FQ to install a chrome extension vue-devtools so that you can see the components better.

 

Component is one of the most powerful functions of Vue.js. Components can extend HTML elements and encapsulate reusable code.

At a higher level, components are custom elements for which the compiler of Vue.js adds special functionality. In some cases, components can also be in the form of native HTML elements, extending with is features.  

The relationship between parent and child components can be summarized as props down, events up. The parent component passes data down to the child component through props, and the child component sends messages to the parent component through events.

 

SLOT understandings: the slot with the name of the child component will replace the slot with the same name of the parent component, and the slot with anonymous child component will replace other slot-name content of the parent component.

             <m-tabbar-item id='tab1'>                
                <img src="../assets/images/ic_tab_home_normal.png" alt="" slot="icon-normal"> 
                <img src="../assets/images/ic_tab_home_active.png" alt="" slot="icon-active"> 
                home page
              </m-tabbar-item>

Subcomponent templates:

            <a class="m-tabbar-item" :class="{'is-active':isActive}" @click="$parent.$emit('input',id)">
                <span class="m-tabbar-item-icon" v-show="!isActive"><slot name="icon-normal"></slot></span>
                <span class="m-tabbar-item-icon" v-show="isActive"><slot name="icon-active"></slot></span>
                <span class="m-tabbar-item-text"><slot></slot></span>
            </a>

The resulting HTML:

<a class="m-tabbar-item">
<span class="m-tabbar-item-icon">
<img src="../assets/images/ic_tab_home_normal.png" alt=""></span>
<span class="m-tabbar-item-icon" style="display: none;">
<img src="../assets/images/ic_tab_home_active.png" alt=""></span>
<span class="m-tabbar-item-text">
//home page
</span>
</a>
<img src=". / assets/images/ic_tab_home_normal.png" alt=""slot="icon-normal"> will replace <slot name="icon-normal"> </slot>
<img src=". / assets/images/ic_tab_home_active.png" alt=""slot="icon-active"/> will replace <slot name="icon-active"></slot> and remove the slot name.
The home page will replace the anonymous <slot></slot>.


The code for the entire page is as follows:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <meta content="width=device-width,initial-scale=1,user-scalable=no" name="viewport" />
    <script src="Scripts/vue.js" type="text/javascript"></script>
    <style type="text/css">
        .m-tabbar
        {
            display: flex;
            flex-direction: row;
            position: fixed;
            bottom: 0;
            left: 0;
            right: 0;
            width: 100%;
            overflow: hidden;
            height: 50px;
            background: #fff;
            border-top: 1px solid #e4e4e4;
        }
        .m-tabbar-item
        {
            flex: 1;
            text-align: center;
        }
        .m-tabbar-item-icon
        {
            display: block;
            padding-top: 2px;
        }
        .m-tabbar-item-icon img
        {
            width: 28px;
            height: 28px;
        }
        .m-tabbar-item-text
        {
            display: block;
            font-size: 10px;
            color: #949494;
        }
        .is-active
        {
            color: #42bd56;
        }
    </style>
</head>
<body>
    <div id="app">
        <div>
            <m-tabbar v-model="select">
             <m-tabbar-item id='tab1'>
                
                <img src="../assets/images/ic_tab_home_normal.png" alt="" slot="icon-normal"> 
                <img src="../assets/images/ic_tab_home_active.png" alt="" slot="icon-active"> 
                //home page
              </m-tabbar-item>
              <m-tabbar-item id='tab2'>
                <img src="../assets/images/ic_tab_subject_normal.png" alt="" slot="icon-normal"> 
                <img src="../assets/images/ic_tab_subject_active.png" alt="" slot="icon-active"> 
                //douban
            </m-tabbar-item>
              <m-tabbar-item id='tab3'>
                <img src="../assets/images/ic_tab_status_normal.png" alt="" slot="icon-normal"> 
                <img src="../assets/images/ic_tab_status_active.png" alt="" slot="icon-active"> 
                //Radio broadcast
              </m-tabbar-item>
              <m-tabbar-item id='tab4'>
                <img src="../assets/images/ic_tab_group_normal.png" alt="" slot="icon-normal"> 
                <img src="../assets/images/ic_tab_group_active.png" alt="" slot="icon-active"> 
                //group
              </m-tabbar-item>
               <m-tabbar-item id='tab5'>
                <img src="../assets/images/ic_tab_profile_normal.png" alt="" slot="icon-normal"> 
                <img src="../assets/images/ic_tab_profile_active.png" alt="" slot="icon-active"> 
                //My
              </m-tabbar-item>
          </m-tabbar>
        </div>
    </div>
    <script type="text/javascript">
        Vue.component("m-tabbar", {
            props: ['value'],
            template:'<div class="m-tabbar"><slot></slot></div>'
        });

        Vue.component("m-tabbar-item", {
            props: ['id'],
            computed: {
               isActive(){
                   if(this.$parent.value===this.id){
                       return true;
                   }
                   else
                        return false;
               }
            },
            template:'<a class="m-tabbar-item" :class="{\'is-active\':isActive}" @click="$parent.$emit(\'input\',id)">'
                +'<span class="m-tabbar-item-icon" v-show="!isActive"><slot name="icon-normal"></slot></span>'
                +'<span class="m-tabbar-item-icon" v-show="isActive"><slot name="icon-active"></slot></span>'
                + '<span class="m-tabbar-item-text"><slot></slot></span>'
                +'</a>'
        });
        var app = new Vue({
            el: '#app',
            data: { 
                select:"tab1"
            }
        });
    </script>
</body>
</html>
The bi-directional binding v-model="select" of the m-tabbar component indicates that the attribute value exposed by the m-tabbar is associated with the select field in the data. The first tab is selected by default on the page, and its Id is tab1.
There is a judgment in the m-tabbar-item component that this.$parent.value===this.id, and the value of the parent component is equal to the Id of the child component, then the child component is selected.
@ Click = "$parent. $emit ( input  id)" method, see here https://cn.vuejs.org/v2/guide/components.html# Input Components Using Forms of Custom Events
<m-tabbar v-model="select">is equivalent to <m-tabbar v-bind:value="select" v-on:input="select=arguments[0]">
So to make the component's v-model work, it must:
Accept a value attribute
Trigger the input event when there is a new value

So the @click="$parent. $emit (\ input id)" method is to trigger the input event of the parent component to pass the Id of the child component to the value attribute of the parent component at the event of the child component click.

 

The question arises: Why does the parent component have an input event? It's just a div. Can I change the name of this event to something else?

Change to the following code and change the event name to abcdef, which is passable
<m-tabbar v-bind:value="selectId" v-on:abcdef="tabSelect">
    <script type="text/javascript">
        Vue.component("m-tabbar", {
            props: ['value'],
            template:'<div class="m-tabbar"><slot></slot></div>',
            mounted: function () {
                console.log("m-tabbar mounted");
            }
        });

        Vue.component("m-tabbar-item", {
            props: ['id'],
            mounted: function () {
                console.log("m-tabbar-item mounted");
            },
            computed: {
               isActive(){
                   if(this.$parent.value===this.id){
                       return true;
                   }
                   else
                        return false;
               }
            },
            template:'<a class="m-tabbar-item" :class="{\'is-active\':isActive}" @click="$parent.$emit(\'abcdef\',id)">'
                +'<span class="m-tabbar-item-icon" v-show="!isActive"><slot name="icon-normal"></slot></span>'
                +'<span class="m-tabbar-item-icon" v-show="isActive"><slot name="icon-active"></slot></span>'
                + '<span class="m-tabbar-item-text"><slot></slot></span>'
                +'</a>'
        });
        var app = new Vue({
            el: '#app',
            data: { 
                selectId:"tab1"
            },
            methods:{
                tabSelect:function(Id){
                    console.log("tabSelect");
                    this.selectId= Id;
                }
            }
        });
    </script>

Is it any name? No, I've tried two of them, but they don't work. When the event name contains the words Select or Index, the parent component will not be able to listen for the event. Are these two reserved words known to anyone?



Posted by NCllns on Tue, 16 Apr 2019 23:24:33 -0700