The problem of using this.$emit ('input',name) for a non-form element in vue.

A tab page build, including three files, why this.$emit ("input",name) in tabs.js?


<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <style type="text/css" href="style.css"></style>
    <title>vue</title>
</head>

<body>

    <div id="app">
    <tabs v-model="activeKey">
        <pane label="1" name="1" >
             1
        </pane>
        <pane label="2" name="2" >
             2
        </pane>
        <pane label="3" name="3" >
             3
        </pane>
    </tabs>
    </div>
    <script src="../vue.js"></script>
    <script type="text/javascript" src="pane.js"></script>
    <script type="text/javascript" src="tab.js"></script>
    <script>
        var app=new Vue({
            el:"-sharpapp",
            data(){
                return {
                    activeKey:1
                }
            }
        })
    </script>
</body>

</html>

pane.js file

//label
Vue.component("pane",{
  template:
  `
    <div class="pane" v-show="show">
      <slot></slot>
    </div>
  `,
  props:{
    label:{
      type:String,
      default:""
    },
    name:{
      type:String
    }
  },
  data(){
    return {
      show:true
    }
  },
  methods:{
    updateNav(){
      this.$parent.updateNav();
    }
  },
  watch:{
    label(){
      this.updateNav();
    }
  },
  mounted(){
    this.updateNav();
  }
});

tabs.js

Vue.component("tabs",{
  template:`

  <div class="tabs">
    <div class="tabs-bar">
      <div :class="tabCls(item)"
          v-for="(item,index) in navList"
          @click="handleChange(index)">
          {{item.label}}
      </div>
    </div>
    <div class="tab-content">
      <slot></slot>
    </div>
  </div>

  `,
  props:{
    //v-model
    value:{
      type:[String,Number]
    }
  },
  data(){
    return {
      //tabs
      navList:[],
      currentValue:this.value
    }
  },
  methods:{
    tabCls(item){
      return ["tabs-tab",
      {
        "tabs-tab-active" : item.name===this.currentValue
      }
      ]
    },
    //
    handleChange(index){
      var nav=this.navList[index];
      var name=nav.name;
      //tabwatch
      this.currentValue=name;
      //value?
      this.$emit("input",name);
    },
    getTabs(){
      //pane
      console.log(this)
      console.log(this.$children);
      return this.$children.filter(item=>item.$options.name==="pane")
    },
    updateNav(){
      this.navList=[];
      this.getTabs().forEach((pane,index)=>{
        this.navList.push({
          label:pane.label,
          name:pane.name || index
        });
        //panelname
        if(!pane.name){
          pane.name=index;
        }

        //
        if(index===0){
          if(!this.currentValue){
            this.currentValue=pane.name || index;
          }
        }
      });
      this.updateStatus();
    },  
    updateStatus(){
    var tabs=this.getTabs();
    tabs.forEach(tab=>{
      return tab.show=tab.name===this.currentValue;
    })
  }
  },
  watch:{
    value(val){
      this.currentValue=val;
    },
    currentValue(){
      //tabpanel
      this.updateStatus();
    }
  }
})

Oct.19,2021

this is what happens when v-model is disassembled in your tabs component

.
<tabs
  v-bind:value="activeKey"
  v-on:input="activeKey= $event"
></tabs>

then use this.$emit ('input',name) to update the activeKey in the parent component each time you click.


go to the official website to see the explanation of v-model , which is actually the abbreviation

of : value and @ input .
Menu