【问题标题】:How to Create A Suggestion Box (Prompt Box in Javascript) Inside a Html Box With Text如何在带有文本的 Html 框中创建建议框(Javascript 中的提示框)
【发布时间】:2016-07-03 04:11:52
【问题描述】:

我正在尝试创建一个页面,允许用户在单击一个单词后获得一个小建议框(如一个非常小的弹出窗口),他可以在其中单击并选择他想要的同义词。

我不确定这可以用什么语言完成,可能是 javascript,但我没有找到任何示例。

html代码如下:

Original:
I <b class="synonyms" style="color:black;" 
title="love|really like|really love">like</b> apples.

The result should be(after a user chooses synonyms):
I <b>{like|love}</b> apples.

例如,当他从句子“我喜欢苹果”中单击“喜欢”时,应该有一个小建议框,他可以在其中从所有建议的选项中进行选择(喜欢|真的喜欢|真的喜欢)。

在结果中是原创加上他选择的。

这是我 javascript 的一个示例,但是我不确定是否有办法点击特定的单词(一个句子中可能有多个单词),还有没有办法设置建议框的样式并添加通过单击它们可以选择的单词列表。

<!DOCTYPE html>
<html>
<body>

<p>I <b id="demo">like</b> apples.</p>

<button onclick="choose()">Try it</button>


<script>
function choose() {
    var synonym = prompt("Choose synonyms:", "like");
    
    if (synonym != null) {
        document.getElementById("demo").innerHTML =
        "{" + "like" + "|" + synonym + "}";
    }
}
</script>

</body>
</html>

【问题讨论】:

    标签: javascript jquery html css ajax


    【解决方案1】:

    Here's a Fiddle

    我使用了 jQuery,并稍微改变了语法。每个选项都应该是 spanselectable。然后它需要一个options 属性。选项按照您建议的方式显示。

    我的脚本与其他脚本的不同之处在于它没有列出已选择且可通过键盘使用的选项(尝试使用 Tab、Enter 和箭头键)。

    $(function () {
      $('.selectable').each(function () {
        var $this = $(this)
        var list  = $this.attr('options').split('|')
        var text  = $this.text()
        $this
          .data('original', text)
          .html('<div><span>' + text + '</span><ul><li tabindex="0">' + list.join('</li><li tabindex="0">') + '</li></ul></div>')
      }).on('mousedown', function (e) {
        e.preventDefault()
        var $this   = $(this)
        var $target = $(e.target)
        var $focus  = $this.find(':focus')
        if ($focus.length) $focus.blur()
        else $this.find('li:not(.active)').eq(0).focus()
        if ($target.is('li')) changeSelection($this, $target)
      }).on('keydown', function (e) {
        var which = e.which
        if (which === 13) changeSelection($(this))
        else if (which === 40) $(this).find(':focus').next().focus()
        else if (which === 38) $(this).find(':focus').prev().focus()
      })
      function changeSelection ($this, $target) {
        $target = $target || $this.find(':focus')
        $target.blur()
        $this
          .one('transitionend', function () {
            $target.addClass('active').siblings().removeClass('active').last().focus().blur()
          })
          .addClass('filled')
          .find('span').text($this.data('original') + ' | ' + $target.text())
      }
    })
    body {
      font-family: sans-serif;
    }
    
    .selectable {
      cursor: default;
    }
    
    .selectable:focus {
      outline: none;
    }
    
    .selectable div {
      position: relative;
      display: inline-block;
    }
    
    .selectable::before,
    .selectable::after,
    .selectable span {
      color: #F00;
    }
    
    .selectable.filled::before {
      content: '{';
      margin-right: .2em;
    }
    
    .selectable.filled::after {
      content: '}';
      margin-left: .2em;
    }
    
    .selectable ul {
      position: absolute;
      top: calc(100% + .2em);
      left: calc(-.4em - 1px);
      list-style: none;
      margin: 0;
      padding: 1px 0 0;
      overflow: hidden;
      background-color: #DDD;
      z-index: 1;
    }
    
    .selectable ul:not(:focus-within) {
      pointer-events: none;
      user-select: none;
      opacity: 0;
      transform: translateY(-5px);
      transition: opacity .25s ease, transform .4s ease;
    }
    
    .selectable ul:focus-within {
      transition: opacity .25s ease, transform .4s ease -.15s;
    }
    
    .selectable li {
      white-space: nowrap;
      padding: .4em;
      margin: 0 1px 1px;
      background-color: #FFF;
    }
    
    .selectable li:hover {
      background-color: #F7F7F7;
    }
    
    .selectable li.active {
      display: none;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <p>I <span class="selectable" options="love|really like|really love">like</span> apples.</p>
    <p>There's nothing <span class="selectable" options="in this world|in the universe">on earth</span> I eat more than apples.</p>

    希望对你有帮助

    【讨论】:

    • 在小提琴上它有效,在我的网站上它没有。我当然复制了 css、html 并在
    【解决方案2】:

    ...但是我不确定是否有 点击特定单词的方式(一个单词中可能有多个单词 句子),还有没有办法设置建议框的样式并添加 通过单击它们可以选择的单词列表。

    将您的问题分解为多个步骤。这将使您更容易理解问题域并设计解决方案。根据我对您的问题的了解,大致的步骤及其实施可能类似于下面描述的那些。

    注意 1:答案基于纯 JavaScript。请记住,像 jQuery 等所有框架都是 JavaScript 只是在更高层次上抽象出来的。首先学习基本的 JavaScript 很重要。

    注意 2:我在整个答案中以嵌入式链接的形式提供了关键概念的参考(供您获取更多信息和学习)。

    1) 单词的标记和 Javascript 设置: 某些单词有同义词。同义词在标题属性中的标记本身中可用。你到达的标记很好:

    标记

    <p>
        I <i class="synonyms" title="love|really like|really love">like</i> apples. 
        I <i class="synonyms" title="love|relish|savor|enjoy|patronize|adore">like</i> oranges. 
    </p>
    

    我们需要能够识别所有带有同义词的词,以便我们可以使用 Javascript 来操作这些词。这些在标记中标识为 i 元素,其类名为 synonyms

    Javascript

    var words = [].slice.call(document.querySelectorAll('i.synonyms'));
    

    querySelectorAll 返回一个节点列表,因此将其转换为数组的最简单方法是调用slice on array prototype。我们需要一个数组,以便我们以后可以对其进行迭代。

    2) 菜单的标记和 Javascript 设置: 需要弹出一个建议框。因此,只需添加一个包含同义词的元素。你已经知道会有一个同义词列表,所以从语义上讲,有一个列表元素是有意义的。并给它一个id。我们稍后会动态填充它。

    标记

    <ul id="synonymMenu"></ul>
    

    Javascript

    var menu = document.getElementById('synonymMenu');
    

    3) 建议框菜单应弹出:每当点击这样的词。因此,我们需要在所有将监听点击事件的单词上添加事件监听器。在上面的第一步中,我们已经在变量words 中找到了单词。我们只是迭代和add the event listener 来执行函数manageMenu。我们稍后会定义该函数。在此过程中,我们还将现有单词缓存在数据属性中,以便以后使用setAttribute

    words.forEach(function(wrd) {
        wrd.setAttribute('data-word', wrd.textContent);
        wrd.addEventListener('click', manageMenu);
    });
    

    4) 用选定的同义词替换单词:每当在建议框菜单中单击同义词时。所以我们还必须在同义词列表中添加一个点击事件监听器。在上面的步骤 2 中,我们已经将菜单存储在变量 menu 中。只需添加侦听器即可执行函数applySynonym。我们稍后会定义该函数。

    menu.addEventListener('click', applySynonym);
    

    5) 我们还必须关闭悬空的建议框:我们可以通过单击主体上的任意位置来实现。只需在正文上添加另一个单击事件处理程序。使用hide 参数执行函数toggleMenu。稍后会定义这个函数。

    document.body.addEventListener('click', function() {
        toggleMenu('hide');
    });
    

    6) 从 title 属性创建同义词列表并显示:它在建议框菜单中,当点击单词时。我们将在步骤 3 中声明的 manageMenu 函数中定义。解释在代码 cmets 中。

    function manageMenu(e) {
        // define variables
        var synonyms, optn, link, position;  
    
        // clear existing list and then show the menu
        clearMenu(); toggleMenu('show'); 
    
        // cache the click event target to a variable to be used later
        currentWord = e.target;
    
        // get the position of word relative to viewport
        position = currentWord.getBoundingClientRect();
    
        // use that position to shift the popup menu near to the word
        menu.style.top = position.top + 24 + 'px';
        menu.style.left = position.left + 2 + 'px';
    
        // extract title attribute, split by | and store in array
        synonyms = currentWord.getAttribute('title').split('|');
    
        // iterate array creating an li and anchor for each synonym
        // createElement creates a new element
        // appendChild adds an element to another
        synonyms.forEach(function(syn) {
            optn = document.createElement('li');
            link = document.createElement('a');
            link.setAttribute('href', '#'); link.textContent = syn;
            // add anchor to li, and the li to the menu
            optn.appendChild(link); menu.appendChild(optn);
        });
        // stop propagation of click, so that it doesn't go to body
        e.stopPropagation(); 
    }
    

    上面代码中对你的关键引用是关于using the event object and its targetgetting the position of word relative to viewportcreateElementappendChildstopPropagation

    7) 同义词应附加到原始单词:并在单击同义词后显示在其位置。我们将在第 4 步中引用的 applySynonym 函数中定义它。

    function applySynonym(e) {
        var txt = '';
    
        // Because we added event listener to the parent ul element, 
        // we have to check if the clicked element is the anchor or not
        if (e.target.tagName != 'A') { return false; }
    
        // We retrieve the orginal text from the data attribute, 
        // which we cached in step 6 above. And append current anchor's text
        txt += '{' + currentWord.getAttribute('data-word') + '|';
        txt += e.target.textContent + '}';
        // replace the text of the word
        currentWord.textContent = txt;
        toggleMenu('hide'); // hide the suggestion box menu
        // stop propagation of click, so that it doesn't go to body
        // prevent default so that clicking anchor doesn't jump to top
        e.stopPropagation(); e.preventDefault();
    }
    

    上面代码中对你的关键引用是关于preventDefault

    8) 我们定义了其余的辅助函数

    function toggleMenu(mode) {
        if (mode == 'show') { menu.style.display = 'block'; }
        if (mode == 'hide') { menu.style.display = 'none'; }
    }
    
    function clearMenu() {
        // we loop the child nodes of menu ul element, 
        // remove the last child (last li) of that ul element, 
        // until it does not has-child-nodes.
        while (menu.hasChildNodes()) { 
            menu.removeChild(menu.lastChild); 
        }
    }
    

    上面代码中的关键参考是关于hasChildNodesremoveChildlastChild

    9) 通过 CSS 定义演示文稿,尤其是让菜单绝对定位,在首次加载时将其隐藏并美化演示文稿:

    ul#synonymMenu {
        position: absolute; display: none;
        ...
        border: 1px solid #bbb; background-color: #efefef;
    }
    

    10) 测试。

    演示小提琴:https://jsfiddle.net/abhitalks/zske2aoh/

    演示片段:

    (function() {
    	var menu = document.getElementById('synonymMenu'), 
    		words = [].slice.call(document.querySelectorAll('i.synonyms')), 
    		currentWord = null
    	;
    	
    	words.forEach(function(wrd) {
    		wrd.setAttribute('data-word', wrd.textContent);
    		wrd.addEventListener('click', manageMenu);
    	});
    	menu.addEventListener('click', applySynonym);
    	document.body.addEventListener('click', function() {
    		toggleMenu('hide');
    	});
    
    	function manageMenu(e) {
    		var synonyms, optn, link, position; 
    		clearMenu(); toggleMenu('show'); 
    		currentWord = e.target;
    		position = currentWord.getBoundingClientRect();
    		menu.style.top = position.top + 24 + 'px';
    		menu.style.left = position.left + 2 + 'px';
    		synonyms = currentWord.getAttribute('title').split('|');
    		synonyms.forEach(function(syn) {
    			optn = document.createElement('li');
    			link = document.createElement('a');
    			link.setAttribute('href', '#'); link.textContent = syn;
    			optn.appendChild(link); menu.appendChild(optn);
    		});
    		e.stopPropagation();
    	}
    	
    	function applySynonym(e) {
    		var txt = '';
    		if (e.target.tagName != 'A') { return false; }
    		txt += '{' + currentWord.getAttribute('data-word') + '|';
    		txt += e.target.textContent + '}';
    		currentWord.textContent = txt;
    		toggleMenu('hide');
    		e.stopPropagation(); e.preventDefault();
    	}
    	
    	function toggleMenu(mode) {
    		if (mode == 'show') { menu.style.display = 'block'; }
    		if (mode == 'hide') { menu.style.display = 'none'; }
    	}
    	
    	function clearMenu() {
    		while (menu.hasChildNodes()) { 
    			menu.removeChild(menu.lastChild); 
    		}
    	}
    	
    })();
    * { font-family: sans-serif; }
    html, body { height: 100%; }
    i.synonyms { cursor: pointer; color: #333; }
    ul#synonymMenu {
    	position: absolute; display: none;
    	width: auto; max-height: 120px; 
    	overflow: hidden; overflow-y: auto;
    	list-style: none; padding: 0; margin: 0; 
    	border: 1px solid #bbb; background-color: #efefef;
    	box-shadow: 0px 0px 6px 1px rgba(128,128,128,0.3);
    }
    ul#synonymMenu > li { display: block; }
    ul#synonymMenu a { 
    	display: block; padding: 4px 20px 4px 6px; 
    	color: #333; font-size: 0.9em; text-decoration: none;
    }
    ul#synonymMenu a:hover {
    	background-color: #99b;
    }
    <p>
    I <i class="synonyms" title="love|really like|really love">like</i> apples. 
    I <i class="synonyms" title="love|relish|savor|enjoy|patronize|adore">like</i> oranges. 
    </p>
    <ul id="synonymMenu"></ul>

    编辑:

    根据 Op 的 cmets,代码已更新,以适应通过复选框选择多个同义词。增加的复杂性在于添加复选框而不是普通的锚点,更改事件侦听器以获得相同的更新样式,以及在重复点击时保留预先存在的选择的逻辑。

    更新的小提琴:https://jsfiddle.net/abhitalks/ffpL4f7k/

    更新片段:

    (function() {
    	var menu = document.getElementById('synonymMenu'), 
    		menuWrap = document.getElementById('menuWrapper'),
    		okButton = document.getElementById('synOk'), 
    		words = [].slice.call(document.querySelectorAll('i.synonyms')), 
    		currentWord = null
    	;
    	
    	words.forEach(function(wrd) {
    		wrd.setAttribute('data-word', wrd.textContent);
    		wrd.addEventListener('click', manageMenu);
    	});
    	okButton.addEventListener('click', applySynonym);
    	document.body.addEventListener('click', function(e) { 
    		if (isDescendant(menuWrapper, e.target)) {
    			return;
    		}
    		toggleMenu('hide');
    	});
    
    	function manageMenu(e) {
    		var synonyms, opt, lbl, chk, txt, position, existing; 
    		clearMenu(); toggleMenu('show'); 
    		currentWord = e.target;
    		position = currentWord.getBoundingClientRect();
    		menuWrap.style.top = position.top + 20 + 'px';
    		menuWrap.style.left = position.left + 2 + 'px';
    		existing = currentWord.textContent;
    		synonyms = currentWord.getAttribute('title').split('|');
    		synonyms.forEach(function(syn) {
    			opt = document.createElement('li'); 
    			lbl = document.createElement('label');
    			chk = document.createElement('input'); 
    			chk.setAttribute('type', 'checkbox'); 
    			txt = document.createTextNode(syn);
    			lbl.appendChild(chk); 
    			lbl.appendChild(txt); 
    			opt.appendChild(lbl); 
    			menu.appendChild(opt);
    		});
    		preSelect(existing);
    		e.stopPropagation();
    	}
    	
    	function preSelect(existing) {
    		var labels = [].slice.call(menu.querySelectorAll('label'));
    		labels.forEach(function(lbl) {
    			if (existing.indexOf(lbl.textContent) > -1) {
    				lbl.firstChild.checked = true;
    			}
    		});
    	}
    	
    	function applySynonym(e) {
    		var txt = '', labels, checked, selected;
    		labels = [].slice.call(menu.querySelectorAll('label'));
    		checked = labels.filter(function(lbl){
    			return lbl.firstChild.checked;
    		});
    		selected = checked.map(function(lbl){
    			return lbl.textContent;
    		}).join('|');
    		
    		txt += '{' + currentWord.getAttribute('data-word') + '|';
    		txt += selected + '}';
    		currentWord.textContent = txt;
    		toggleMenu('hide');
    		e.stopPropagation(); 
    	}
    	
    	function toggleMenu(mode) {
    		if (mode == 'show') { menuWrap.style.display = 'block'; }
    		if (mode == 'hide') { menuWrap.style.display = 'none'; }
    	}
    	
    	function clearMenu() {
    		while (menu.hasChildNodes()) { 
    			menu.removeChild(menu.lastChild); 
    		}
    	}
    	
    	function isDescendant(parent, child) {
    		 var node = child.parentNode;
    		 while (node != null) {
    			 if (node == parent) {
    				 return true;
    			 }
    			 node = node.parentNode;
    		 }
    		 return false;
    	}
    
    })();
    * { font-family: sans-serif; box-sizing: border-box; }
    html, body { height: 100%; }
    div.wrap { 
    	border: 1px solid #ddd; max-height: 480px; 
    	padding: 4px 22px 4px 4px; font-size: 0.9em;
    	overflow: hidden; overflow-y: auto;
    }
    i.synonyms { cursor: pointer; color: #333; }
    div#menuWrapper {
    	position: absolute; display: none; width: 128px; 
    	padding: 4px; margin: 0; 
    	border: 1px solid #bbb; background-color: #efefef;
    	box-shadow: 0px 0px 6px 1px rgba(128,128,128,0.3);
    }
    ul#synonymMenu {
    	max-height: 120px; 
    	overflow: hidden; overflow-y: auto;
    	list-style: none; padding: 0; margin: 0; 
    }
    ul#synonymMenu > li { display: block; }
    ul#synonymMenu label { 
    	display: block; color: #333; font-size: 0.9em; 
    	padding: 2px 18px 2px 4px; 
    }
    ul#synonymMenu label:hover { background-color: #99b; }
    button#synOk { padding: 2px; width: 100%; }
    <div class="wrap">
    	<p>
    	I <i class="synonyms" title="love|relish|savor">like</i> apples. I <i class="synonyms" title="love|relish|savor|enjoy|patronize|adore">like</i> oranges. I <i class="synonyms" title="love|relish|savor">like</i> apples. I <i class="synonyms" title="love|relish|savor|enjoy|patronize|adore">like</i> oranges. I <i class="synonyms" title="love|relish|savor">like</i> apples. I <i class="synonyms" title="love|relish|savor|enjoy|patronize|adore">like</i> oranges. I <i class="synonyms" title="love|relish|savor">like</i> apples. I <i class="synonyms" title="love|relish|savor|enjoy|patronize|adore">like</i> oranges. I <i class="synonyms" title="love|relish|savor">like</i> apples. I <i class="synonyms" title="love|relish|savor|enjoy|patronize|adore">like</i> oranges. I <i class="synonyms" title="love|relish|savor">like</i> apples. I <i class="synonyms" title="love|relish|savor|enjoy|patronize|adore">like</i> oranges. I <i class="synonyms" title="love|relish|savor">like</i> apples. I <i class="synonyms" title="love|relish|savor|enjoy|patronize|adore">like</i> oranges. I <i class="synonyms" title="love|relish|savor">like</i> apples. I <i class="synonyms" title="love|relish|savor|enjoy|patronize|adore">like</i> oranges. I <i class="synonyms" title="love|relish|savor">like</i> apples. I <i class="synonyms" title="love|relish|savor|enjoy|patronize|adore">like</i> oranges. 
    	</p>
    	<p>
    	I <i class="synonyms" title="love|relish|savor">like</i> apples. I <i class="synonyms" title="love|relish|savor|enjoy|patronize|adore">like</i> oranges. I <i class="synonyms" title="love|relish|savor">like</i> apples. I <i class="synonyms" title="love|relish|savor|enjoy|patronize|adore">like</i> oranges. I <i class="synonyms" title="love|relish|savor">like</i> apples. I <i class="synonyms" title="love|relish|savor|enjoy|patronize|adore">like</i> oranges. I <i class="synonyms" title="love|relish|savor">like</i> apples. I <i class="synonyms" title="love|relish|savor|enjoy|patronize|adore">like</i> oranges. I <i class="synonyms" title="love|relish|savor">like</i> apples. I <i class="synonyms" title="love|relish|savor|enjoy|patronize|adore">like</i> oranges. I <i class="synonyms" title="love|relish|savor">like</i> apples. I <i class="synonyms" title="love|relish|savor|enjoy|patronize|adore">like</i> oranges. I <i class="synonyms" title="love|relish|savor">like</i> apples. I <i class="synonyms" title="love|relish|savor|enjoy|patronize|adore">like</i> oranges. I <i class="synonyms" title="love|relish|savor">like</i> apples. I <i class="synonyms" title="love|relish|savor|enjoy|patronize|adore">like</i> oranges. I <i class="synonyms" title="love|relish|savor">like</i> apples. I <i class="synonyms" title="love|relish|savor|enjoy|patronize|adore">like</i> oranges. 
    	</p>
    	<p>
    	I <i class="synonyms" title="love|relish|savor">like</i> apples. I <i class="synonyms" title="love|relish|savor|enjoy|patronize|adore">like</i> oranges. I <i class="synonyms" title="love|relish|savor">like</i> apples. I <i class="synonyms" title="love|relish|savor|enjoy|patronize|adore">like</i> oranges. I <i class="synonyms" title="love|relish|savor">like</i> apples. I <i class="synonyms" title="love|relish|savor|enjoy|patronize|adore">like</i> oranges. I <i class="synonyms" title="love|relish|savor">like</i> apples. I <i class="synonyms" title="love|relish|savor|enjoy|patronize|adore">like</i> oranges. I <i class="synonyms" title="love|relish|savor">like</i> apples. I <i class="synonyms" title="love|relish|savor|enjoy|patronize|adore">like</i> oranges. I <i class="synonyms" title="love|relish|savor">like</i> apples. I <i class="synonyms" title="love|relish|savor|enjoy|patronize|adore">like</i> oranges. I <i class="synonyms" title="love|relish|savor">like</i> apples. I <i class="synonyms" title="love|relish|savor|enjoy|patronize|adore">like</i> oranges. I <i class="synonyms" title="love|relish|savor">like</i> apples. I <i class="synonyms" title="love|relish|savor|enjoy|patronize|adore">like</i> oranges. I <i class="synonyms" title="love|relish|savor">like</i> apples. I <i class="synonyms" title="love|relish|savor|enjoy|patronize|adore">like</i> oranges. 
    	</p>
    </div>
    <div id="menuWrapper">
    	<ul id="synonymMenu"></ul>
    	<hr/>
    	<button id="synOk">Ok</button>
    </div>

    【讨论】:

    • @Brana:我似乎无法理解你在这里想说什么。我看不到您所说的更新版本,因此无法弄清楚您要放入表格中的内容。
    • 等一下@Brana,给我几分钟。
    • @Brana:这里 - jsfiddle.net/abhitalks/ffpL4f7k。它现在变得有点太复杂了。建议你慢慢来,慢慢理解。发生的事情太多了。
    • 然而,你完成了 99.99%,这是一项了不起的工作,相当复杂,但你轻松地处理了它。非常感谢。
    • 谢谢@brana。感觉很好,你能发现它很有用。是的,由于时间有限,我无法处理滚动和定位等较小的细节。但很高兴知道你可以解决这个问题。
    【解决方案3】:

    我相信我构建了以下适合您需求的 jQuery 组件。
    如果您愿意,这里是jsbin

    //jquery component
    $.fn.synonyms = function(options){
      options = $.extend({}, {separator: '|'}, options);
      this.each(function(elKey, el){
        var $el = $(el),
            originalText = $el.text(),
            originalTextSpan = $('<span>'+originalText+'</span>');
        $el.html(originalTextSpan);
        var suggestionBox = '<div>';
        $.each($el.attr('data-synonyms').split(options.separator),
               function(key, suggestion){
          suggestionBox+='<span>'+suggestion+'</span> - ';
        }
              );
        suggestionBox = suggestionBox.slice(0, -2);
        suggestionBox += '</div>';
        suggestionBox = $(suggestionBox);
        suggestionBox.css({
          display: 'none'
        });
      
        $el.click(function(){
          suggestionBox.toggle();
        });
      
        suggestionBox.on('click','span',function(){
          var selectedText = $(this).text();
          originalTextSpan.text('{'+originalText+'|'+selectedText+'}');
          onSelected(selectedText);
        });
      
        $el.append(suggestionBox);
      });
      
      
      function onSelected(selectedText){
        if(options.onSelected){
          options.onSelected(selectedText);
        }
      }
    };
    
    
    // How to use the component
    $(function(){
      $('[data-synonyms]').synonyms({
        onSelected: function(selectedText){
          alert('you selected:'+selectedText);
        }
      });
    });
    div[data-synonyms]{
      display: inline;
      position: relative;
      cursor: pointer;
      text-decoration: underline;
    }
    div[data-synonyms] > div{
      white-space: nowrap;
      position: absolute;
      top: 1.2em;
      left: 0;
      background: #fff;
      border: 1px solid #bbb;
      padding: 2px;
    }
    div[data-synonyms] > div > span{
      text-decoration: underline;
      cursor: pointer;
    }
    <!DOCTYPE html>
    <html>
    <head>
    <script src="https://code.jquery.com/jquery-2.1.4.js"></script>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width">
      <title>JS Bin</title>
    </head>
    <body>
      I <div data-synonyms="love|really like|really love">like</div> apples. Carrots are the <div data-synonyms="worst|orangest">best</div> though.
    </body>
    </html>

    【讨论】:

    • 您可以让 originalText 成为同义词的第一个选项,因此您不必在新选择旁边显示括号和 originalText(我认为更好/更漂亮的 UI)。顺便说一句,很棒的小部件/组件!
    • @Philip 谢谢!我使用了 {xxx|yyy} 格式,因为这似乎是他想要的。但是,是的,我认为应该替换文本。也许原始文本在被替换后应该成为选项之一,以便可以恢复。
    • @Philip,看起来很棒。我刚刚更新了我的答案,因为当页面上有多个同义词时它效果不佳。它现在可以更好地处理多个同义词实例。
    【解决方案4】:

    我使用引导程序的下拉菜单创建了另一个解决方案:

    http://www.bootply.com/rWfTgSwf1z

    我们的想法是对所有要使用同义词的单词使用下拉菜单。当前代码为每个单词手动添加下拉列表,并在选择时替换原始单词。

    data-synonyms属性中定义了单词的同义词时,您可以拥有如下句子:

    <div>
      I
      <span data-synonyms="love|really like|really love">like</span>
      apples and
      <span data-synonyms="mangoes|bananas|other fruits">oranges</span>.
    </div>
    

    然后,在 javascript 中,我们创建下拉菜单并替换现有元素:

    $('[data-synonyms]').each(function () {
    
      // get the current element
      var $this = $(this);
    
      // create a dropdown wrapper
      var $dropdownDiv = $('<div>').addClass('dropdown word-dropdown');
    
      // create the dropdown trigger
      var $a = $('<a>').attr('data-toggle', 'dropdown').text($this.text()).appendTo($dropdownDiv);
    
      // create the dropdown list
      var $ul = $('<ul>').addClass('dropdown-menu').appendTo($dropdownDiv);
    
      // get the synonyms and append the existing word
      var synonyms = $this.attr('data-synonyms').split('|');
      synonyms.splice(0, 0, $this.text());
    
      // create an entry in the dropdown for each synonym
      $.each(synonyms, function (idx, syn) {
        var $li = $('<li>').addClass('synonyms').appendTo($ul).append($('<a>').text(syn.trim()));
    
        // add a handler which replaces the existing word with the synonym
        $li.on('click', function () {
            $a.text(syn.trim());
        });
      });
    
      // replace the current element with the dropdown element
      $this.replaceWith($dropdownDiv);
    
      // activate the dropdown
      $a.dropdown();
    
    });
    

    【讨论】:

      【解决方案5】:

      $(document).ready(function() {
        $("b").on("click", function() {
          var $b = $(this),
            alternatives = this.title.split('|').join('</option><option>');
          $b.after('<select class="selector"><option>&nbsp;</option><option>' + alternatives + '</option><select>');
        });
        $("body").on("change", "select.selector", function() {
          var $sl = $(this),
            txt = $sl.val();
          $sl.prev('b').text(txt);
          $sl.remove();
        });
      });
      b {
        color: red;
        cursor: pointer;
      }
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
      
      <div class="text">
        <p>I <b title="like|love|adore">like</b> apples, <b title="especially|particularily">particularily</b> if they are <b title="fresh|ripe">ripe</b>.</p>
      
      </div>

      【讨论】:

      • 这很好,但是有一些问题:点击一个单词两次会出现几个下拉菜单,只有第一个有效。
      • @MarkWright 在什么浏览器/平台上?选择项会在选择项目时自毁,因此每个单词不应该有多个选择,除非您在选择之前再次单击一个单词;即使这样,如果您进行选择,它也会被删除,然后下一个就可以正常工作了。
      • 啊,现在是第二部和第三部作品。至于多项选择 - 那是因为我在选择之前点击了两次。但是谢谢你,现在它可以工作了:)
      猜你喜欢
      • 2018-05-16
      • 2011-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多