如何在带有文本的Html框内创建一个建议框(Javascript中的提示框)

时间:2016-03-17 01:12:48

标签: javascript jquery html css ajax

enter image description here我试图创建一个页面,允许用户点击一个单词后得到一个小的建议框(如一个相当小的弹出窗口),他可以点击并选择他想要的同义词。

我不确定用什么语言可以做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>

5 个答案:

答案 0 :(得分:9)

  

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

将您的问题分解为几个步骤。这将使您更容易理解问题域并设计解决方案。从我的问题出发,广泛的步骤及其实施可能与下面描述的步骤相同。

注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)建议框菜单应该弹出:只要点击这样的单词。因此,我们需要在所有会听取click事件的单词上添加和事件监听器。我们已经在上面第一步中的变量words中有了单词。我们只需迭代并add the event listener执行函数manageMenu。我们稍后会定义该函数。在我们处理它的同时,我们还会在数据属性中缓存现有单词,以便以后能够使用setAttribute来使用它。

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

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

menu.addEventListener('click', applySynonym);

5)我们必须关闭悬空建议箱:我们可以通过点击身体的任何地方来做到这一点。只需在body上添加另一个click事件处理程序。使用toggleMenu参数执行函数hide。稍后会定义这个函数。

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

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

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的评论,代码已经更新,以通过复选框容纳多个同义词选择。增加的复杂性在于添加复选框而不是普通锚点,为相同的更新样式更改事件侦听器,以及在重复点击时保留预先存在的选择的逻辑。

更新小提琴: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>

答案 1 :(得分:5)

我建立了以下适合您需求的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>

答案 2 :(得分:4)

rand.Next
$(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;
}

答案 3 :(得分:1)

我使用bootstrap的下拉列表创建了另一个解决方案:

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();

});

答案 4 :(得分:1)

这里有a Fiddle,其中有两个选项。

我使用过jQuery,并稍微改变了语法。每个选项都应为struct oneCell{ var date = NSDate() var money = Int() } var spend = [oneCell]() ,其中包含span类。然后它需要selectable属性。选项以您建议的方式呈现。

我的脚本与其他脚本的不同之处在于它没有列出已经选择的选项。

HTML:

options

CSS:

<p>I <span class="selectable" options="love|really like|really love">like</span> apples.</p>

JavaScript:

.selectable{
  position: relative;
}

.selectable span{
  color: #F00;
  cursor: pointer;
}

.selectable ul{
  position: absolute;
  top: 100%;
  left: 0;
  list-style: none;
  padding: 0;
  margin: 0;
  pointer-events: none;
  opacity: 0;
}

.selectable.active ul{
  pointer-events: initial;
  opacity: 1;
}

.selectable li{
  cursor: pointer;
  white-space: nowrap;
  background-color: #FFF;
}

.selectable li:hover{
  background-color: #F7F7F7;
}

.selectable li.active{
  display: none;
}

希望这有帮助