0

以下代码可以正常工作,但我想让它变得更好:

function prodNameTrim(selector){
        var el = document.getElementsByClassName(selector);
        var len = el.length;
        for(i = 0; i<len; i++){
            aObj = el[i].getElementsByTagName('a');
            txtNode = aObj[0].childNodes[0].nodeValue;
            if(txtNode.length > 26){
                txtNode = txtNode.substring(0, 27) + ' ...';
            }
            aObj[0].childNodes[0].nodeValue = txtNode;
        }
    }

我不喜欢的是,我首先在这样的条件之前建立 txtNode:

txtNode = aObj[0].childNodes[0].nodeValue;

在我通过条件处理变量以用省略号截断字符串后,我执行以下操作来替换 DOM 中的文本:

aObj[0].childNodes[0].nodeValue = txtNode;

我必须相信有更好的方法可以做到这一点,但我不确定那是什么,我觉得我好像违反了 DRY 规则。

4

4 回答 4

2

如果您只是想避免在aObj[0].childNodes[0]任何地方重复该部分,您可以使用txtNode变量来引用节点本身,而不是它的值:

function prodNameTrim(selector){
    var el = document.getElementsByClassName(selector);
    var len = el.length;
    var txtNode;  // declare txtNode with var
    for(var i = 0; i<len; i++){
        txtNode = el[i].getElementsByTagName('a')[0].childNodes[0];
        if(txtNode.nodeValue.length > 26){
            txtNode.nodeValue = txtNode.nodeValue.substring(0, 27) + ' ...';
        }
    }
}

你会注意到你最终仍然会txtNode.nodeValue到处重复,但这比aObj[0].childNodes[0]每次都包含要好。并且if不需要将子字符串版本写回节点的语句之后的行,因为该更新现在直接在if.

另请注意,您应该声明所有变量,var否则它们将成为全局变量。(而且我上面显示的方式实际上根本不需要aObj变量。)

于 2013-10-15T20:52:52.773 回答
2

我建议这样做:

function prodNameTrim(selector){
    var el = document.getElementsByClassName(selector),
        len = el.length, node;
    for(var i = 0; i < len; i++) {
        node = el[i].getElementsByTagName('a')[0].firstChild;
        if(node.nodeValue.length > 26){
            node.nodeValue = node.nodeValue.substring(0, 27) + ' ...';
        }
    }
}

变化:

  1. 声明所有局部变量(所以没有隐式全局变量 - 你没有声明i,aObjtxtNode
  2. 跳过aObj中间,因为它不需要
  3. 避免使用 textNode 中间,因为它不需要
  4. 直接赋值给 nodeValue
  5. 仅在if语句内部对 nodeValue 进行分配,因为这是它唯一更改的地方
  6. 使用.firstChild代替.childNodes[0]

我想知道这是否可行(可能需要 IE9 或更高版本,并且希望查看 HTML 以确定并运行一些浏览器测试),但总体思路是使用querySelectorAll()并将这两个搜索组合到一个更复杂的 CSS 选择器中:

function prodNameTrim(rootClass) {
    var items = document.querySelectorAll("." + rootClass + " a:first-of-type"), node;
    for (var i = 0; i < items.length; i++) {
        node = items[i].firstChild;
        if (node.nodeValue.length > 26) {
            node.nodeValue = node.nodeValue.substring(0, 27) + ' ...';
        }
    }
}

请注意,第二个实现假定 to 的参数prodNameTrim()是一个类名(就像它在 OP 的版本中一样)。


或者,如果每个选择器父级中只有一个链接标签,那么您可以简单地使用它,它应该适用于所有现代浏览器:

function prodNameTrim(rootClass) {
    var items = document.querySelectorAll("." + rootClass + " a"), node;
    for (var i = 0; i < items.length; i++) {
        node = items[i].firstChild;
        if (node.nodeValue.length > 26) {
            node.nodeValue = node.nodeValue.substring(0, 27) + ' ...';
        }
    }
}
于 2013-10-15T21:00:44.420 回答
1

如果您想在一行中进行条件截断,您可以执行以下操作:

function prodNameTrim(selector){
    var el = document.getElementsByClassName(selector),
        len = el.length, node;
    for(var i = 0; i < len; i++) {
        node = el[i].getElementsByTagName('a')[0].firstChild;
        node.nodeValue.substring(0, 27) + (node.nodeValue.length > 26 ? ' ...', '')
    }
}
于 2013-10-15T21:10:18.847 回答
0

你这样做是正确的——除了你引入了一个不必要的全局变量。第一个任务应该是:

var txtNode = aObj[0].childNodes[0].nodeValue;

使用var声明!您还可以在for循环之前在函数顶部声明变量。正如 nnnnnn 所指出的,您还在为iand创建意外的全局变量aObjfor所以你可以通过在循环之前插入这个来解决所有三个问题:

var i, aObj, txtNode;
于 2013-10-15T20:52:42.240 回答