【问题标题】:Set event Listener on every Word in a long text为长文本中的每个单词设置事件监听器
【发布时间】:2018-05-14 11:03:16
【问题描述】:

我想让文本可点击,我的意思是其中的每个单词。 现在我知道你可以用<span> 标签来包装每个单词。这适用于 句子和段落,但我希望能够使用长文本(文章到书籍),我猜这种机制不适用于此。

所以在某种程度上我想添加特定的事件监听器,当我点击它而不是事先点击它时,因为用<span> 将整本书中的每个单词包装起来只会导致很多开销。

所以我想知道是否有类似包之类的东西可以为我做到这一点?

我能想到的另一种方法是将文本和事件监听器放入这样的对象中:

[{"word: 'Hello'", event:EventListenerFunction},{"word":'World!', event: EventListerenerFunction},...].

这样我可以在服务器上而不是在客户端上计算整个事情,并且会创建更多需要的信息。对于我想对文本做的其他事情,它也有优势。

现在这种方法的问题是显示。在 vue.js 中显示文本很容易,如下所示:{{ textObject.text }}(如果对象的结构当然是正确的。否则你需要事先过滤单词)。但是如何在不丢失对象中的信息的情况下显示单词并使事件侦听器工作?

我的第三个理论想法是给父 html-tag 一个事件监听器,它以某种方式获取点击的单词作为参数。这将适用于围绕单词方法的包装span。但是没有它呢?

您还有其他想法吗?

【问题讨论】:

  • I guess that this mechanism wont work for this 为什么不呢?这正是我会做的。
  • 或许你可以看看here
  • 您是一次显示整本书吗?没有分页?
  • 我计划像在 Facebook 上那样向下滚动时加载内容。

标签: javascript html node.js vue.js


【解决方案1】:

有跨度:

var page = 'Lorem ipsum dolor sit amet, cu eum eros vitae persequeris, laudem possit nam ex. Labore eloquentiam per an. Sit ex omnesque interpretaris, habeo tantas eos ad, ea eos ludus inciderint. Facete tritani pro ei, vim evertitur liberavisse ex. Ridens indoctum duo cu, est utamur aliquando expetendis ne. Cum nusquam definiebas ex, id esse neglegentur cum, eu libris bonorum volumus vis. Ius et quis omnis graeco, no his nullam perpetua dissentiet. No vix possim scripserit consequuntur, te mnesarchum philosophia sed. Ne mea putent iudicabit, in eam ipsum viris dicunt. Eum amet accommodare ex, sint malis adversarium at qui.'

new Vue({
  el: '#app',
  data: {
    page: ''
  },
  computed: {
    pageContent () {
      return this.page.replace(/\b(\w+?)\b/g, '<span>$1</span>')
    }
  },
  methods: {
    doSomething (e) {
      if (e.target.nodeName === 'SPAN')
        console.log(e.target.textContent)
    }
  },
  created () {
    // load external data
    this.page = page
  }
})
<div id="app">
  <p @click="doSomething" v-html="pageContent"></p>
</div>

<script src="https://unpkg.com/vue@2.5.9/dist/vue.min.js"></script>

没有跨度:

var book = 'Lorem ipsum dolor sit amet, cu eum eros vitae persequeris, laudem possit nam ex. Labore eloquentiam per an. Sit ex omnesque interpretaris, habeo tantas eos ad, ea eos ludus inciderint. Facete tritani pro ei, vim evertitur liberavisse ex. Ridens indoctum duo cu, est utamur aliquando expetendis ne. Cum nusquam definiebas ex, id esse neglegentur cum, eu libris bonorum volumus vis. Ius et quis omnis graeco, no his nullam perpetua dissentiet. No vix possim scripserit consequuntur, te mnesarchum philosophia sed. Ne mea putent iudicabit, in eam ipsum viris dicunt. Eum amet accommodare ex, sint malis adversarium at qui.'

new Vue({
  el: '#app',
  data: {
    book: ''
  },
  methods: {
    doSomething (e) {
      var content = e.target.textContent
      var pos = window.getSelection().anchorOffset
      content = content
        .substring(0, content.indexOf(' ', pos))
        .trim()
      content = content
        .substr(content.lastIndexOf(' ') + 1)
        .replace(/[.,:;!?()+-]/g, '')
        
      console.log(content)
    }
  },
  created () {
    // load external data
    this.book = book
  }
})
<div id="app">
  <p @click="doSomething" v-html="book"></p>
</div>

<script src="https://unpkg.com/vue@2.5.9/dist/vue.min.js"></script>

【讨论】:

  • 我想我现在会使用它。谢谢。
  • @telion 完成。我找到了一个解决方案,不需要用 span 元素包装每个单词。已添加示例。
  • @Waldemarlce 不错。很好的答案!非常感谢。
  • 为了完成:有像 这样的内联标签的边缘情况。我看起来分析了您的答案,并且对为什么它不起作用感到有点困惑,因为 e.target.textcontent 实际上应该在标签中获取所有文本,即使其中还有其他标签。然而,它会导致奇怪的行为。
  • 改进了第二个示例 - 您现在可以使用带有标记标签的文本。
【解决方案2】:

您可以使用window.getSelection() 获取您在文本中的位置,然后找到它周围的单词字符。

一个极端情况:如果您有打断单词的格式标记(例如我的示例中的粗体),您将获得您单击的单词的一部分,而不是整个单词。

var page = `Lorem ipsum dolor sit amet, cu eum eros vitae persequeris, laudem possit nam ex.
Labore eloquentiam per an.
Sit ex omnesque interpretaris, habeo tantas eos ad, ea eos ludus inciderint.
<i>Facete tritani pro ei</i>, vim evertitur liberavisse ex.
Ridens indoctum duo cu, est utamur aliquando expetendis ne. <b>Cum nusquam defin</b>iebas ex, id esse neglegentur cum, eu libris bonorum volumus vis. Ius et quis omnis graeco, no his nullam perpetua dissentiet. No vix possim scripserit consequuntur, te mnesarchum philosophia sed. Ne mea putent iudicabit, in eam ipsum viris dicunt. Eum amet accommodare ex, sint malis adversarium at qui.`

new Vue({
  el: '#app',
  data: {
    page
  },
  methods: {
    doSomething (e) {
      const sel = window.getSelection();
      const text = sel.anchorNode.textContent;
      const lmatch = text.substr(0, sel.anchorOffset).match(/[\s\S]*\s/);
      const offset = lmatch ? lmatch[0].length : 0;
      const match = text.substr(offset).match(/\w+/);
      
      console.log(match && match[0]);
    }
  }
})
<div id="app">
  <p @click="doSomething" v-html="page"></p>
</div>

<script src="https://unpkg.com/vue@2.5.9/dist/vue.min.js"></script>

【讨论】:

  • 很好的答案。我现在不知道是谁先发布了解决方案,但非常感谢您的回答。我真的很感激。
  • 为了完整起见:还有第二个极端情况,即 utf-8。如果有一个字符不是 \w 的一部分,则该单词将只显示所有字符,直到未定义的字符。
  • 公平点。 UTF-8 在 JavaScript 正则表达式中很难看。 stackoverflow.com/questions/6381752/…
猜你喜欢
  • 1970-01-01
  • 2011-11-03
  • 1970-01-01
  • 1970-01-01
  • 2015-09-22
  • 1970-01-01
  • 2016-11-01
  • 1970-01-01
  • 2020-08-03
相关资源
最近更新 更多