vue中对于一个非表单元素使用this.$emit('input',name)的问题.

一个tab页组建,包括三个文件,在tabs.js中,为何要 this.$emit('input',name)?

请输入代码
<!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:'#app',
            data(){
                return {
                    activeKey:1
                }
            }
        })
    </script>
</body>

</html>

pane.js 文件

//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;
      //改变当前选中的tab,并触发下面的watch
      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
        });
        //如果panel没有name,则默认给索引
        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(){
      //当亲选中的tab改变时候,需要更新panel的显示状态
      this.updateStatus();
    }
  }
})

阅读 5.2k
2 个回答

你的tabs组件中v-model拆解后就是这样的

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

然后用this.$emit('input',name)就是你每次点击时候要将父组件中的activeKey更新。

去官网看看v-model的解释,其实就是:value@input的缩写

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题