javascript - 使用 angularjs 或 jquery 浏览列表

标签 javascript html angularjs

我正在创建一个列表,每个列表都会有输入,这意味着它可以编辑。但是,我有一个问题。我可以使用箭头键浏览此列表并聚焦目标输入吗?

.content ul {
  padding: 0;
}
.content ul li {
  list-syle: none;
}
<div class="content">
  <ul>
    <li><textarea name="text" id=""></textarea></li>
    <li><textarea name="text" id=""></textarea></li>
    <li><textarea name="text" id=""></textarea></li>
  </ul>
</div>

最佳答案

我刚刚找到了这个解决方案,它对我有用:

var setSelectionByCharacterOffsets = null;
// set cursor
if (window.getSelection && document.createRange) {
    setSelectionByCharacterOffsets = function(containerEl, start, end) {
        var charIndex = 0, range = document.createRange();
        range.setStart(containerEl, 0);
        range.collapse(true);
        var nodeStack = [containerEl], node, foundStart = false, stop = false;

        while (!stop && (node = nodeStack.pop())) {
            if (node.nodeType == 3) {
                var nextCharIndex = charIndex + node.length;
                if (!foundStart && start >= charIndex && start <= nextCharIndex) {
                    range.setStart(node, start - charIndex);
                    foundStart = true;
                }
                if (foundStart && end >= charIndex && end <= nextCharIndex) {
                    range.setEnd(node, end - charIndex);
                    stop = true;
                }
                charIndex = nextCharIndex;
            } else {
                var i = node.childNodes.length;
                while (i--) {
                    nodeStack.push(node.childNodes[i]);
                }
            }
        }

        var sel = window.getSelection();
        sel.removeAllRanges();
        sel.addRange(range);
    }
} else if (document.selection) {
    setSelectionByCharacterOffsets = function(containerEl, start, end) {
        var textRange = document.body.createTextRange();
        textRange.moveToElementText(containerEl);
        textRange.collapse(true);
        textRange.moveEnd("character", end);
        textRange.moveStart("character", start);
        textRange.select();
    };
}

var setCaret = function(element, index) {
    setSelectionByCharacterOffsets(element, index, index);
};

function cursorIndex() {
    return window.getSelection().getRangeAt(0).startOffset;
}

// splits text into array of lines
(function($) {
$.fn.lines = function(){
    words = this.text().split(" "); //split text into each word
    lines = [];
    
    hiddenElement = this.clone(); //copies font settings and width
    hiddenElement.empty();//clear text
    hiddenElement.css("visibility", "hidden");
    
    jQuery('body').append(hiddenElement); // height doesn't exist until inserted into document
    
    hiddenElement.text('i'); //add character to get height
    height = hiddenElement.height();
    hiddenElement.empty();
    
    startIndex = -1; // quick fix for now - offset by one to get the line indexes working
    jQuery.each(words, function() {
      lineText = hiddenElement.text(); // get text before new word appended
      hiddenElement.text(lineText + " " + this);
        if(hiddenElement.height() > height) { // if new line
            lines.push({text: lineText, startIndex: startIndex, endIndex: (lineText.length + startIndex)}); // push lineText not hiddenElement.text() other wise each line will have 1 word too many
            startIndex = startIndex + lineText.length +1;
            hiddenElement.text(this); //first word of the next line
        }
   });
    lines.push({text: hiddenElement.text(), startIndex: startIndex, endIndex: (hiddenElement.text().length + startIndex)}); // push last line
    hiddenElement.remove();
    lines[0].startIndex = 0; //quick fix for now - adjust first line index
    return lines;
}
})(jQuery);

(function($) { // to save a bit of typing
    $.fn.lastLine = function() {
        return this.lines()[this.lines().length-1];
    }
})(jQuery);

function findLineViaCaret(textElement,caretIndex){
    jQuery.each(textElement.lines(), function() {
        if(this.startIndex <= caretIndex && this.endIndex >= caretIndex) {
            r = this;
            return false; // exits loop
        }
   });
    return r;
}

function distanceToCaret(textElement,caretIndex){

    line = findLineViaCaret(textElement,caretIndex);
    if(line.startIndex == 0) { 
     // +1 needed for substring to be correct but only first line?
        relativeIndex = caretIndex - line.startIndex +1;
    } else {
      relativeIndex = caretIndex - line.startIndex;  
    }
    textToCaret = line.text.substring(0, relativeIndex);
    
    hiddenElement = textElement.clone(); //copies font settings and width
    hiddenElement.empty();//clear text
    hiddenElement.css("visibility", "hidden");
    hiddenElement.css("width", "auto"); //so width can be measured
    hiddenElement.css("display", "inline-block"); //so width can be measured

    jQuery('body').append(hiddenElement); // doesn't exist until inserted into document
    
    hiddenElement.text(textToCaret); //add to get width
    width = hiddenElement.width();
    hiddenElement.remove();
    
    return width;
}

function getCaretViaWidth(textElement, lineNo, width) {
    line = textElement.lines()[lineNo-1];
     
    lineCharacters = line.text.replace(/^\s+|\s+$/g, '').split("");
    
    hiddenElement = textElement.clone(); //copies font settings and width
    hiddenElement.empty();//clear text
    hiddenElement.css("visibility", "hidden");
    hiddenElement.css("width", "auto"); //so width can be measured
    hiddenElement.css("display", "inline-block"); //so width can be measured
    
    jQuery('body').append(hiddenElement); // doesn't exist until inserted into document
    
    if(width == 0) { //if width is 0 index is at start
        caretIndex = line.startIndex;
    } else {// else loop through each character until width is reached
        hiddenElement.empty();
        jQuery.each(lineCharacters, function() {
            text = hiddenElement.text();
            prevWidth = hiddenElement.width();
            hiddenElement.text(text + this);
            elWidth = hiddenElement.width();
            caretIndex = hiddenElement.text().length + line.startIndex;
            if(hiddenElement.width() > width) {
                // check whether character after width or before width is closest
                if(Math.abs(width - prevWidth) < Math.abs(width - elWidth)) {
                   caretIndex = caretIndex -1; // move index back one if previous is closes
                }
                return false;
            }
        });
    }
    hiddenElement.remove();
    return caretIndex;
}

// arrow key conditions
$(document).on('keydown', 'p[contenteditable="true"]', function(e) {
    //if cursor on first line & up arrow key
    if(e.which == 38 && (cursorIndex() < $(this).lines()[0].text.length)) { 
        e.preventDefault();
        if ($(this).prev().is('p')) {
            prev = $(this).prev('p');
            getDistanceToCaret = distanceToCaret($(this), cursorIndex());
            lineNumber = prev.lines().length;
            caretPosition = getCaretViaWidth(prev, lineNumber, getDistanceToCaret);
            prev.focus();
            setCaret(prev.get(0), caretPosition);
        }
    // if cursor on last line & down arrow
    } else if(e.which == 40 && cursorIndex() >= $(this).lastLine().startIndex && cursorIndex() <= ($(this).lastLine().startIndex + $(this).lastLine().text.length)) {
        e.preventDefault();
        if ($(this).next().is('p')) {
            next = $(this).next('p');
            getDistanceToCaret = distanceToCaret($(this), cursorIndex());
            caretPosition = getCaretViaWidth(next, 1, getDistanceToCaret);
            next.focus();
            setCaret(next.get(0), caretPosition);
        }
        //if start of paragraph and left arrow
    } else if(e.which == 37 && cursorIndex() == 0) {
        e.preventDefault();
        if ($(this).prev().is('p')) {
            prev = $(this).prev('p');
            prev.focus();
            setCaret(prev.get(0), prev.text().length); 
        }
        // if end of paragraph and right arrow
    } else if(e.which == 39 && cursorIndex() == $(this).text().length) {
        e.preventDefault();
        if ($(this).next().is('p')) {
            $(this).next('p').focus();
        }
    };
});
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js"></script>
<p contenteditable = "true" >Lorem ipsum dolor sit amet, consectetur adipiscing elit. pendisse potenti. Sed faucibus nunc sed erat pellentesque ac auctor massa posuere.</p>
<p contenteditable = "true" >Nullam fringilla, urna nec consequat laoreet, massa nibh posuere mauris, id consequat lectus tellus facilisis nisl. Quisque quis lectus tellus. .</p>
<p contenteditable = "true" >Aenean sit amet mattis diam. Cras sed augue et nunc citudin sed erat. Quisque at erat ut felis consequat luctus eget vitae lectus.</p>

关于javascript - 使用 angularjs 或 jquery 浏览列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37790944/

相关文章:

javascript - 找到一个确定的<span>并在容器元素上插入一个id

javascript - 使用水平导航显示内容 (JavaScript)

javascript - 我可以防止 ng-repeat 在 AngularJS 1.2 中对我的内容进行 html 编码/转义吗?还是需要自己写指令?

javascript - AngularJS 不进入 Controller

javascript - 单击提交按钮后加载图像卡住

javascript - 如何在 Timbre.js 中进行弯音

javascript - 使用打开的下拉菜单滚动内容

javascript - Angular.js 路由似乎不起作用

javascript - 使用我的 "DragEnter"和 "Dreagleave"函数在 Firefox 浏览器上进行 Knockout.js 拖放操作时出现问题

javascript - 使用 ui-bootstrap 模式