赋值变量新值以更改元素节点值

assigning variable new value to change element nodeValue

本文关键字:元素 节点 变量 新值 赋值      更新时间:2023-09-26

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

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 规则。

我会建议这样做:

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. 声明所有局部变量(所以没有隐式全局变量 - 你没有声明iaObjtxtNode
  2. 跳过aObj中间,因为它不是必需的
  3. 避免使用textNode中间,因为它不是必需
  4. 直接赋值给节点值
  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) + ' ...';
        }
    }
}

请注意,第二个实现假定 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) + ' ...';
        }
    }
}

如果你只是想避免在任何地方重复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变量。

如果你想在一行中做条件截断,你可以做这样的事情:

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 ? ' ...', '')
    }
}

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

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

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

var i, aObj, txtNode;