下列示例中,我们希望观察两种方式从获取属性值到设置属性值的区别。
<body> <input type="text" id="input1" class="input11" /> <button id="btn1">设置为riverwood</button> <button id="btn2">设置为hurstville</button> <script> var inputElem1 = document.querySelector('#input1')
console.log("inputElem1.getAttribute('value'):", inputElem1.getAttribute('value')) console.log('inputElem1.value:', inputElem1.value)
var btn1 = document.querySelector('#btn1') var btn2 = document.querySelector('#btn2')
btn1.onclick = function () { console.log('点击btn1') inputElem1.setAttribute('value', 'riverwood') console.log("inputElem1.getAttribute('value'):", inputElem1.getAttribute('value')) console.log('inputElem1.value:', inputElem1.value) }
btn2.onclick = function () { console.log('点击btn2') inputElem1.value = 'hurstville' console.log("inputElem1.getAttribute('value'):", inputElem1.getAttribute('value')) console.log('inputElem1.value:', inputElem1.value) } </script></body>让我们一步一步拆解。
默认值h2
| HTML 属性(Attribute) | DOM属性(Property) |
|---|---|
| 是HTML标记中的原始值 | 是DOM对象在内存中的当前值 |
使用 getAttribute() 方法获取 | 直接通过 .value 访问 |
| 只在HTML解析时初始化,修改后不会自动更新对应的DOM属性 | 会随着用户输入而实时变化 |
<body> <input type="text" id="input1" class="input11" /> <button id="btn1">设置为riverwood</button> <button id="btn2">设置为hurstville</button> <script> var inputElem1 = document.querySelector('#input1')
console.log("inputElem1.getAttribute('value'):", inputElem1.getAttribute('value')) // inputElem1.getAttribute('value'): null console.log('inputElem1.value:', inputElem1.value) //inputElem1.value: </script></body>没有默认值的情况,因为HTML标记中没有value属性,所以inputElem1.getAttribute('value')返回的是null;而inputElem1.value返回的是空字符串,表示当前输入框的值。
如果input元素value属性有默认值,比如我们设置成value="riverwood"
<body> <input type="text" id="input1" class="input11" value="riverwood" /> <button id="btn1">设置为riverwood</button> <button id="btn2">设置为hurstville</button> <script> var inputElem1 = document.querySelector('#input1')
console.log("inputElem1.getAttribute('value'):", inputElem1.getAttribute('value')) // inputElem1.getAttribute('value'): riverwood console.log('inputElem1.value:', inputElem1.value) //inputElem1.value: riverwood </script></body>有默认值的情况下,一个是从HTML标记中读取的初始值,一个是当前DOM对象的value属性值,返回的都是riverwood。
点击btn1 btn2按钮 再次点击btn1h2
第一阶段:同步期(点击 btn1)h3
当我们点击 btn1 时,执行了 setAttribute('value', 'riverwood')。
// 控制台输出:"inputElem1.getAttribute('value'):" "riverwood""inputElem1.value:" "riverwood"分析: 此时输入框处于“干净(Clean)”状态。浏览器认为用户尚未介入,因此当我们修改 HTML 特性(Attribute)这一“默认值”时,浏览器会自动同步更新 DOM 属性(Property),输入框显示的内容也随之改变。
第二阶段:决裂期(点击 btn2)h3
紧接着,我们要点击 btn2,执行 inputElem1.value = 'hurstville'。
// 控制台输出:"inputElem1.getAttribute('value'):" "riverwood" // 保持不变"inputElem1.value:" "hurstville" // 发生了变化分析: 这一步至关重要!
- Property 变了:我们将 DOM 对象的
value属性直接修改为hurstville,界面内容也随之更新。 - Attribute 没变:可以看到
getAttribute依然是riverwood。这说明修改 Property 不会反向同步 Attribute。 - 脏值标记(Dirty Value Flag):更重要的是,在这一刻,浏览器内部将该输入框标记为“脏(Dirty)”。这意味着浏览器认为:“用户(或脚本)已经显式接管了当前值,它不再依赖默认值了。”
第三阶段:失效期(再次点击 btn1)h3
现在,我们再次点击 btn1,试图通过 setAttribute 把值改回 riverwood。
// 控制台输出:"inputElem1.getAttribute('value'):" "riverwood" // Attribute 确实是 riverwood"inputElem1.value:" "hurstville" // !!! Property 依然是 hurstville分析:
发生了什么?为什么 setAttribute 失效了?
因为此时输入框已经是“脏”的了。一旦 Property 和 Attribute 的同步关系断裂,Attribute(默认值)的修改将不再影响 Property(当前值)。 界面上依然顽固地显示着 hurstville。
有图为证
特殊情况:手动输入会发生什么?h2
除了用 JS 修改 .value,还有一个最常见的场景:用户直接在输入框里打字。
假设页面刷新后,我们不点任何按钮,直接在输入框手动输入 hurstville1,然后点击 btn2(代码中打印当前状态),会得到什么结果?
// 1. 手动输入 "hurstville1"// 此时 Property = "hurstville1", Attribute = null (因为没人设置过)
// 2. 点击 btn2 (执行 input.value = 'hurstville')// 控制台输出:"inputElem1.getAttribute('value'):" null"inputElem1.value:" "hurstville"这里的机理是: 用户的手动输入等同于修改 Property。 当你敲下第一个字符时,浏览器的“脏值标记”就已经置位了。
getAttribute返回null,因为 HTML 标签上从来没有过value="...",用户打字也不会把字写到 HTML 标签上去。value返回hurstville,因为我们的btn2代码把它覆盖了。
总结h2
通过上述实验,我们可以得出一个关键结论:
- Attribute (
setAttribute):本质是设置defaultValue(默认值)。它只在元素初始化,或者元素处于“干净”状态时,才能影响界面显示。 - Property (
.value):代表 当前值。 - 铁律:一旦用户操作过输入框,或者脚本修改过
.value,Attribute 和 Property 的同步链接就会永久断开。此时再用setAttribute是无法改变输入框内容的。
最佳实践:
作为原生 JS 开发者,除非你需要利用 Attribute 进行 CSS 选择器匹配(如 input[value="abc"]),否则在处理表单值时,请始终优先使用 .value。
Comments