如何创建基于原生JavaScript的jQuery css()方法替代封装函数?
你的封装方案整体是可行的,能够实现基础的CSS样式设置功能,但存在不少边缘情况和可以优化的细节,具体如下:
潜在问题与边缘情况
属性名转换缺陷
你实现的驼峰转连字符逻辑无法处理特殊CSS属性,比如float在原生JS中对应的是cssFloat(非IE浏览器)或styleFloat(IE),直接转成float会导致部分浏览器无法识别。另外,像msTransform这类带厂商前缀的属性,虽然转成ms-transform后style对象也能识别,但原生驼峰格式的属性名其实更直接可靠。未支持样式读取功能
jQuery的css()方法既可以设置样式,也能读取元素的计算后样式(比如$('div').css('width')),但你的css2()仅实现了设置逻辑,缺失了读取场景的支持。对象遍历未过滤原型属性
使用for...in遍历属性对象时,会遍历到原型链上的继承属性,可能导致意外的样式设置,需要过滤掉非自身属性。值处理不严谨
- jQuery会自动为数字类型的长度属性添加
px单位(比如width: 100会转为100px),你的代码直接赋值数字会导致样式无效。 - 当传入
null或空字符串时,jQuery会移除对应样式,而你的代码只是赋值空字符串,虽然多数场景有效,但用style.removeProperty()更规范。
- jQuery会自动为数字类型的长度属性添加
未处理厂商前缀
部分CSS属性需要厂商前缀(如transform对应webkitTransform、mozTransform),你的代码无法自动适配这些前缀,会导致样式在旧版浏览器中不生效。变量作用域问题
使用var声明变量存在变量提升问题,容易引发作用域冲突,建议改用let/const。
优化后的示例代码
$.fn.css2 = function(property, value) { // 处理单个样式读取 if (arguments.length === 1 && typeof property === 'string') { if (!this.length) return ''; const computedStyle = getComputedStyle(this[0]); const hyphenatedProp = property.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); return computedStyle.getPropertyValue(hyphenatedProp); } // 处理批量样式设置 if (arguments.length === 1 && typeof property === 'object') { return this.each(function() { const elem = this; Object.keys(property).forEach(prop => { let targetProp = prop; // 处理特殊属性float if (prop === 'float') { targetProp = 'cssFloat'; if (!('cssFloat' in elem.style)) targetProp = 'styleFloat'; } else { targetProp = prop.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); } const propValue = property[prop]; if (propValue === null || propValue === '') { elem.style.removeProperty(targetProp); } else { // 自动为数字类型的非特殊属性添加px单位 if (typeof propValue === 'number' && !['opacity', 'zIndex', 'fontWeight'].includes(prop)) { elem.style.setProperty(targetProp, `${propValue}px`); } else { elem.style.setProperty(targetProp, propValue); } } }); }); } // 处理单个样式设置 let targetProp = property; if (property === 'float') { targetProp = 'cssFloat'; if (!('cssFloat' in this[0].style)) targetProp = 'styleFloat'; } else { targetProp = property.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); } return this.each(function() { const elem = this; if (value === null || value === '') { elem.style.removeProperty(targetProp); } else { if (typeof value === 'number' && !['opacity', 'zIndex', 'fontWeight'].includes(property)) { elem.style.setProperty(targetProp, `${value}px`); } else { elem.style.setProperty(targetProp, value); } } }); };
额外建议
如果是逐步过渡到原生JavaScript,建议在熟悉原生API后,逐步替换这类封装函数,直接使用element.style、getComputedStyle()、style.setProperty()等原生方法,减少对jQuery的依赖,同时也能更灵活地控制样式逻辑。
内容的提问来源于stack exchange,提问作者smolo

