javascript - 如果元素单击 vue 组件,我如何添加类事件?

标签 javascript css vue.js vuejs2 vue-component

我的 vue 组件是这样的:

Vue.component('list-category', {
  template: "#lc",
  props: ['data', 'category', 'search'],
  data() {
    return {
      open: false,
      categoryId: this.category
    }
  },
  mounted() {
    let isDataOpen = (d) => d.id === this.categoryId || d.children && d.children.some(isDataOpen);
  	this.open = isDataOpen(this.data);
  },
  computed: {
    icon() {
      return {
        'fa-plus': !this.open,
        'fa-minus': this.open,
      }
    },
    isFolder() {
      return this.data.children && this.data.children.length
    },
    isShow() {
      return this.open ? 'show' : 'hide'
    }
  },
  methods: {
    toggle() {
      this.open = !this.open
    },
    filterByCategory(id) {
      this.categoryId = id
    }
  }
})

new Vue({
  el: '#app',
  data() {
    return {
      categories: [{
          id: 1,
          name: 'England',
          children: [{
              id: 3,
              name: 'Chelsea',
              children: [{
                  id: 7,
                  name: 'Hazard'
                },
                {
                  id: 8,
                  name: 'Morata'
                }
              ]
            },
            {
              id: 4,
              name: 'Manchester United',
              children: [{
                  id: 9,
                  name: 'Pogba'
                },
                {
                  id: 10,
                  name: 'Lukaku'
                }
              ]
            }
          ]
        },
        {
          id: 2,
          name: 'Spain',
          children: [{
              id: 5,
              name: 'Real Madrid',
              children: [{
                  id: 11,
                  name: 'Ronaldo'
                },
                {
                  id: 12,
                  name: 'Bale'
                }
              ]
            },
            {
              id: 6,
              name: 'Barcelona',
              children: [{
                  id: 13,
                  name: 'Messi'
                },
                {
                  id: 14,
                  name: 'Suarez'
                }
              ]
            },
          ]
        }
      ],
      category: 7
    }
  }
})
.active {
  background: yellow;
}

.pd-search-filter > .panel-body ul.filter-category {
  padding-left: 0;
  list-style: none;
  margin: 0 -15px 0;
}

.pd-search-filter > .panel-body ul.filter-category > li a {
  display: block;
  padding: 10px 15px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pd-search-filter > .panel-body ul.filter-category > li a:last-child {
  padding-left: 45px;
}

.pd-search-filter > .panel-body ul.filter-category > li a:focus, .pd-search-filter > .panel-body ul.filter-category > li a:hover {
  background-color: #eeeeee;
  text-decoration: none;
}

.pd-search-filter > .panel-body ul.filter-category > li a + ul {
  padding-left: 0;
  list-style: none;
}

.pd-search-filter > .panel-body ul.filter-category > li a + ul > li > a {
  padding-left: 30px;
}

.show {
  display: block !important;
}

.hide {
  display: none !important;
}
<script src="https://unpkg.com/vue"></script>
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">

<div id="app">
  <div class="panel panel-default pd-search-filter">
    <div class="panel-heading">
      <h3 class="panel-title"><i class="fa fa-circle-o"></i> By Category</h3>
    </div>
    <div class="panel-body">
      <ul class="filter-category" v-for="list in categories">
        <list-category :data="list" :category="category"></list-category>
      </ul>
    </div>
  </div>
</div>

<template id="lc">
    <li>
        <!--parent-->
        <a v-if="isFolder" href="javascript:" @click="toggle">
            <span class="fa fa-fw" :class="icon"></span> {{data.name}}
        </a>
        <!--if not folding, we do not need an binding event-->
        <a v-else href="javascript:" :title="data.name" :class="{active: data.id === categoryId}" @click="filterByCategory(data.id)"><span class="fa fa-fw fa-circle-o"></span> {{data.name}}</a>
        <!--children-->
        <ul v-if="isFolder" :class="isShow">
            <list-category v-for="(data, index) in data.children" :key="index" :data="data" :search="search" :category="categoryId"></list-category>
        </ul>
    </li>
</template>

看来您需要查看演示和完整代码

是这样的:http://jsfiddle.net/vxLhbo5m/861/

从演示中看到类别危险活跃。如果我点击 morata 类别,它是不活动的。而我已经编写了代码

我该如何解决这个问题?

============================================= ============================

最佳答案

您必须将类别计算器移动到观察者(而不是 mount())并发出/监听从子级到父级的一些事件以更新类别和折叠 未选择的子树。

Updated JSFiddle here .

变化:

  • 模板:

    • 家长:

      • 来自:

        <div id="app">
            ...
                <list-category :data="list" :category="category"></list-category>
        
      • 添加对 category 事件的监听并更新父级的 category 属性:

        <div id="app">
            ...
                <list-category :data="list" :category="category" @category="category = $event"></list-category>
        
    • child :

      • 来自:

        <template id="lc">
            ...
                <list-category v-for="(data, index) in data.children" :key="index" :data="data" :search="search" :category="categoryId"></list-category>
        
      • 监听 category 事件并将其发送给父级:

        <template id="lc">
            ...
                <list-category v-for="(data, index) in data.children" :key="index" :data="data" :search="search" :category="categoryId" @category="$emit('category', $event)"></list-category>
        
  • JavaScript(全部在 child 中):

    • 更改 filterByCategory 以发出事件而不是改变属性:

      • 来自:

        filterByCategory(id) {
          this.categoryId = id
        }
        
      • 收件人:

        filterByCategory(id) {
          this.$emit('category', id);
        }
        
    • 删除 mounted 钩子(Hook)并添加 watcher:

      • 移除挂载:

        mounted() {
          let isDataOpen = (d) => d.id === this.categoryId || d.children && d.children.some(isDataOpen);
          this.open = isDataOpen(this.data);
        },
        
      • category 在父级中发生变化时添加 watcher 以获取:

        watch: {
          category: {
            handler() {
              this.categoryId = this.category
              let isDataOpen = (d) => d.id === this.categoryId || d.children && d.children.some(isDataOpen);
              this.open = isDataOpen(this.data);
            },
            immediate: true
          }
        }
        

演示:

Vue.component('list-category', {
  template: "#lc",
  props: ['data', 'category', 'search'],
  data() {
    return {
      open: false,
      categoryId: this.category
    }
  },
  computed: {
    icon() {
      return {
        'fa-plus': !this.open,
        'fa-minus': this.open,
      }
    },
    isFolder() {
      return this.data.children && this.data.children.length
    },
    isShow() {
      return this.open ? 'show' : 'hide'
    }
  },
  methods: {
    toggle() {
      this.open = !this.open
    },
    filterByCategory(id) {
      this.$emit('category', id);
    }
  },
  watch: {
    category: {
    	handler() {
        this.categoryId = this.category
	      let isDataOpen = (d) => d.id === this.categoryId || d.children && d.children.some(isDataOpen);
	      this.open = isDataOpen(this.data);
      },
      immediate: true
    }
  }
})

new Vue({
  el: '#app',
  data() {
    return {
      categories: [{
          id: 1,
          name: 'England',
          children: [{
              id: 3,
              name: 'Chelsea',
              children: [{
                  id: 7,
                  name: 'Hazard'
                },
                {
                  id: 8,
                  name: 'Morata'
                }
              ]
            },
            {
              id: 4,
              name: 'Manchester United',
              children: [{
                  id: 9,
                  name: 'Pogba'
                },
                {
                  id: 10,
                  name: 'Lukaku'
                }
              ]
            }
          ]
        },
        {
          id: 2,
          name: 'Spain',
          children: [{
              id: 5,
              name: 'Real Madrid',
              children: [{
                  id: 11,
                  name: 'Ronaldo'
                },
                {
                  id: 12,
                  name: 'Bale'
                }
              ]
            },
            {
              id: 6,
              name: 'Barcelona',
              children: [{
                  id: 13,
                  name: 'Messi'
                },
                {
                  id: 14,
                  name: 'Suarez'
                }
              ]
            },
          ]
        }
      ],
      category: 7
    }
  }
})
.active {
  background: yellow;
}

.pd-search-filter > .panel-body ul.filter-category {
  padding-left: 0;
  list-style: none;
  margin: 0 -15px 0;
}

.pd-search-filter > .panel-body ul.filter-category > li a {
  display: block;
  padding: 10px 15px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pd-search-filter > .panel-body ul.filter-category > li a:last-child {
  padding-left: 45px;
}

.pd-search-filter > .panel-body ul.filter-category > li a:focus, .pd-search-filter > .panel-body ul.filter-category > li a:hover {
  background-color: #eeeeee;
  text-decoration: none;
}

.pd-search-filter > .panel-body ul.filter-category > li a + ul {
  padding-left: 0;
  list-style: none;
}

.pd-search-filter > .panel-body ul.filter-category > li a + ul > li > a {
  padding-left: 30px;
}

.show {
  display: block !important;
}

.hide {
  display: none !important;
}
<script src="https://unpkg.com/vue"></script>
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">

<div id="app">
  <div class="panel panel-default pd-search-filter">
    <div class="panel-heading">
      <h3 class="panel-title"><i class="fa fa-circle-o"></i> By Category</h3>
    </div>
    <div class="panel-body">
      <ul class="filter-category" v-for="list in categories">
        <list-category :data="list" :category="category" @category="category = $event"></list-category>
      </ul>
    </div>
  </div>
</div>

<template id="lc">
    <li>
        <!--parent-->
        <a v-if="isFolder" href="javascript:" @click="toggle">
            <span class="fa fa-fw" :class="icon"></span> {{data.name}}
        </a>
        <!--if not folding, we do not need an binding event-->
        <a v-else href="javascript:" :title="data.name" :class="{active: data.id === categoryId}" @click="filterByCategory(data.id)"><span class="fa fa-fw fa-circle-o"></span> {{data.name}}</a>
        <!--children-->
        <ul v-if="isFolder" :class="isShow">
            <list-category v-for="(data, index) in data.children" :key="index" :data="data" :search="search" :category="categoryId" @category="$emit('category', $event)"></list-category>
        </ul>
    </li>
</template>

关于javascript - 如果元素单击 vue 组件,我如何添加类事件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49473224/

相关文章:

css - IE 不在 CSS 背景中显示重复的单词

javascript - 未定义 Photoswipe UI 默认值

javascript - TinyMCE 和 Vuejs 作为组件

vue.js - 如何在 vue.js 版本 3 中上传文件

javascript - jQuery 能否获取与元素关联的所有 CSS 样式?

javascript - 如何使用 JavaScript 将 Unicode 转换为在网页中显示的字符?

javascript - http.createServer如何使用fs.createReadStream从needle.post接收数据

css - Bootstrap 4 - SASS 扩展按钮在 anchor 标签上不起作用?

javascript - 尝试在 header 中包含 js 脚本但没有成功

firebase - .orderByChild() 不适用于 Firebase (vue.js)