【问题标题】:Vuejs v-on click doesn't work inside componentVuejs v-on click 在组件内不起作用
【发布时间】:2019-03-26 22:24:08
【问题描述】:

我使用 VueJs,并用它创建了以下组件。

var ComponentTest = {
    props: ['list', 'symbole'],
    data: function(){
        return {
            regexSymbole: new RegExp(this.symbole),
        }
    },
    template: `
        <div>
            <ul>
                <li v-for="item in list" 
                    v-html="replaceSymbole(item.name)">
                </li>
            </ul>
        </div>
    `,
    methods: {
        replaceSymbole: function(name){
            return name.replace(this.regexSymbole, '<span v-on:click="test">---</span>');
        },

        test: function(event){
            console.log('Test ...');
            console.log(this.$el);
        },   
    }
};


var app = new Vue({
    el: '#app',
    components: {
        'component-test': ComponentTest,
    },
    data: {
        list: [{"id":1,"name":"@ name1"},{"id":2,"name":"@ name2"},{"id":3,"name":"@ name3"}], 
        symbole: '@'
    },
});

这是我的html代码

<div id="app">
    <component-test :list="list" :symbole="symbole"></component-test>
</div>

当我点击“li”标签内的“span”标签时,没有任何附加内容。

我没有任何警告和任何错误。

当我点击“span”标签时如何调用我的组件方法“test”。

本案例如何实现点击事件。

【问题讨论】:

  • 如果您检查生成的 html,我希望您在 span 元素上看到文字 v-on:click 属性,对吧?
  • 是的,我看到 v-on:click in all span 标签
  • Vue 不会解释您动态创建的 span 标签。您可以使用纯 JavaScript,也可以以编程方式将 Vue 组件渲染到 span 标签中,这会触发点击事件。
  • “你不能使用 v-html 来组合模板部分,因为 Vue 不是基于字符串的模板引擎。相反,组件是 UI 重用和组合的基本单元。” (source)。您也可以查看this answer

标签: vue.js


【解决方案1】:

您不能在提供给v-html 的字符串中使用 vue 指令。它们不会被解释,而是最终成为实际属性。您有多种选择:

  • 更好地准备您的数据,以便您可以使用普通模板。例如,您可以将数据准备为对象:{ linkText: '---', position: 'before', name: 'name1' },然后根据位置进行渲染。我认为这是迄今为止最好的解决方案。

    <template>
      <div>
        <ul>
          <li v-for="(item, index) in preparedList" :key="index">
            <template v-if="item.position === 'before'">
              <span v-on:click="test">{{ item.linkText }}</span>
              {{ item.name }}
            </template>
            <template v-else-if="item.position === 'after'">
              {{ item.name }}
              <span v-on:click="test">{{ item.linkText }}</span>
            </template>
          </li>
        </ul>
      </div>
    </template>
    
    <script>
    export default {
      props: ["list", "symbole"],
    
      computed: {
        preparedList() {
          return this.list.map(item => this.replaceSymbole(item.name));
        }
      },
    
      methods: {
        replaceSymbole: function(question) {
          if (question.indexOf("@") === 0) {
            return {
              linkText: "---",
              position: "before",
              name: question.replace("@", "").trim()
            };
          } else {
            return {
              linkText: "---",
              position: "after",
              name: question.replace("@", "").trim()
            };
          }
        },
    
        test: function(event) {
          console.log("Test ...");
          console.log(this.$el);
        }
      }
    };
    </script>
    
  • 您可以将点击处理程序放在周围的li上,并过滤事件。点击处理程序的第一个参数是被触发的MouseEvent

    <template>
      <div>
        <ul>
          <li v-for="item in list" :key="item.id" v-on:click="clickHandler"
              v-html="replaceSymbole(item.name)">
          </li>
        </ul>
      </div>
    </template>
    
    <script>
    export default {
      props: ["list", "symbole"],
    
      data() {
        return {
          regexSymbole: new RegExp(this.symbole)
        };
      },
    
      computed: {
        preparedList() {
          return this.list.map(item => this.replaceSymbole(item.name));
        }
      },
    
      methods: {
        replaceSymbole: function(name) {
          return name.replace(
            this.regexSymbole,
            '<span class="clickable-area">---</span>'
          );
        },
    
        test: function(event) {
          console.log("Test ...");
          console.log(this.$el);
        },
    
        clickHandler(event) {
          const classes = event.srcElement.className.split(" ");
    
          // Not something you do not want to trigger the event on
          if (classes.indexOf("clickable-area") === -1) {
            return;
          }
    
          // Here we can call test
          this.test(event);
        }
      }
    };
    </script>
    
  • 您的最后一个选择是手动将事件处理程序添加到您的跨度。我确实不!!!推荐这个。您还必须在销毁组件或列表更改时删除这些事件处理程序,否则会造成内存泄漏。

【讨论】:

  • 感谢您的回答,我无法更好地准备数据,因为我的名称字符串可以包含许多符号,是的,我不能在这种情况下使用 v-html,所以我将使用纯 js。
  • @wpuser000 我不明白。第二个选项使用v-html 并具有您期望的行为...
  • 我在
  • {{ replaceSymbol(item.name) }}
  • 之前尝试过这个,但它呈现在 html "--- name" 所以我阅读了文档并找到了这个 v-html,但我没有很好地阅读文档,因为我无法使用这个指令来实现我试图实现的目标,我只想替换所有符号带有点击监听器的跨度。例如:{name:"@ big name @ with many symbols @"} => big name with many symbole "
猜你喜欢
相关资源
最近更新 更多
热门标签