LuCI前端开发规范:确保代码一致性和质量

LuCI前端开发规范:确保代码一致性和质量

【免费下载链接】luci LuCI - OpenWrt Configuration Interface 【免费下载链接】luci 项目地址: https://gitcode.com/gh_mirrors/lu/luci

1. 引言

1.1 规范背景与目标

LuCI(OpenWrt Configuration Interface)作为OpenWrt路由器操作系统的核心配置界面,其前端代码的质量直接影响用户体验和开发效率。随着LuCI生态的不断扩展,前端代码库日益庞大,团队协作需求增加,制定统一的开发规范变得尤为迫切。本规范旨在通过明确的编码标准、组件设计原则和质量保障措施,解决以下核心痛点:

  • 一致性缺失:不同开发者编写的代码风格迥异,导致维护成本激增
  • 质量参差不齐:缺乏统一的代码质量标准,功能实现稳定性难以保证
  • 协作效率低:代码规范不统一,团队成员间代码理解成本高
  • 扩展性受限:组件设计缺乏规范,难以复用和扩展

通过实施本规范,我们期望达成:90%以上的前端代码符合规范要求新功能开发周期缩短20%线上问题率降低30%

1.2 适用范围

本规范适用于所有基于LuCI框架开发的前端代码,包括但不限于:

  • 核心模块(luci-base、luci-mod-*)
  • 应用插件(luci-app-*)
  • 主题开发(luci-theme-*)
  • 第三方扩展

2. 文件与目录结构

2.1 标准目录布局

LuCI前端项目应遵循以下目录结构,确保代码组织清晰有序:

htdocs/                  # Web根目录
├── luci-static/         # 静态资源
│   ├── resources/       # JavaScript资源
│   │   ├── view/        # 视图组件
│   │   ├── widgets/     # 通用组件
│   │   └── js/          # 工具函数库
│   ├── css/             # 样式文件
│   └── images/          # 图像资源
└── luci/                # 核心框架文件
    ├── js/              # 框架JavaScript
    └── view/            # 框架视图模板

示例:luci-app-smartdns的目录结构遵循了这一规范:

luci-app-smartdns/
└── htdocs/
    └── luci-static/
        └── resources/
            └── view/
                └── smartdns/
                    └── smartdns.js  # 业务逻辑代码

2.2 文件命名规范

文件类型命名规则示例
JavaScript文件小写字母+连字符network-utils.js
视图模板文件小写字母+连字符+.htmwireless-settings.htm
CSS文件小写字母+连字符status-page.css
图像文件小写字母+连字符+扩展名signal-strength.png

禁止使用下划线、 PascalCase 或 CamelCase 命名文件,以保持与LuCI核心代码的一致性。

3. HTML模板规范

3.1 模板语法基础

LuCI使用基于正则表达式的模板处理器,支持特殊标记与HTML混合编写。所有模板文件应以以下代码开头,确保正确的内容类型:

<%
require("luci.http").prepare_content("text/html")
-%>
3.1.1 常用模板标记
标记用途示例
<% ... %>嵌入Lua代码<% if user then %>Welcome<% end %>
<%= ... %>输出变量值Hello <%= username %>
<%+ ... %>包含其他模板<%+header.htm%>
<%: ... %>国际化翻译<%:System Settings%>
<%# ... %>模板注释<%# 这是注释 %>

最佳实践:使用-修饰符去除不必要的空白:

<%- if status == "error" then -%>
<div class="error"><%:Error occurred%></div>
<%- end -%>

3.2 语义化HTML

模板开发应遵循语义化HTML原则,优先使用适当的HTML5元素:

<!-- 推荐 -->
<nav class="menu">...</nav>
<section class="status">...</section>

<!-- 不推荐 -->
<div class="menu">...</div>
<div class="status">...</div>

3.3 模板继承与复用

通过模板包含机制实现代码复用,创建可维护的模板结构:

<!-- base.htm -->
<!DOCTYPE html>
<html>
<head>
    <title><%=title%></title>
    <%+head.htm%>
</head>
<body>
    <%+header.htm%>
    <main><%+main%></main>
    <%+footer.htm%>
</body>
</html>

4. JavaScript编码规范

4.1 变量与函数命名

  • 变量:使用camelCase命名,前缀表示类型(s_字符串, n_数字, b_布尔)
  • 常量:使用UPPER_SNAKE_CASE命名
  • 函数:使用camelCase命名,动词开头
  • 私有成员:以下划线_开头

示例

// 推荐
var s_username = "admin";
var n_timeout = 30;
var b_enabled = true;
var _secretKey = "12345";

function validateInput(value) {
    // ...
}

// 不推荐
var user_name = "admin"; // 使用下划线
var Timeout = 30; // 首字母大写
var ENABLED = true; // 常量但使用了错误作用域

4.2 代码风格

4.2.1 缩进与换行
  • 使用4个空格缩进,不使用制表符
  • 每行代码不超过80个字符
  • 函数定义的左大括号不换行

示例

// 推荐
function formatBytes(bytes) {
    if (bytes < 1024)
        return bytes + " B";
    else if (bytes < 1048576)
        return (bytes / 1024).toFixed(1) + " KB";
    else
        return (bytes / 1048576).toFixed(1) + " MB";
}

// 不推荐
function formatBytes(bytes) { 
    if(bytes<1024)return bytes+" B";
    else if(bytes<1048576)return (bytes/1024).toFixed(1)+" KB";
    else return (bytes/1048576).toFixed(1)+" MB";
}
4.2.2 空格使用
  • 操作符前后添加空格:a = b + c而非a=b+c
  • 逗号后添加空格:func(a, b, c)而非func(a,b,c)
  • 括号内侧不加空格:if (x > 0)而非if ( x > 0 )

4.3 模块化开发

LuCI前端支持模块化开发,通过require机制加载依赖:

// 模块定义
define("luci/view/network", [
    "luci.util",
    "luci.fs"
], function(util, fs) {
    return {
        getInterfaceList: function() {
            // ...
        }
    };
});

// 模块使用
require("luci/view/network").getInterfaceList();

5. 组件与UI开发

5.1 CBI模型开发

CBI(Configuration Backend Interface)是LuCI特有的配置界面开发框架,通过Lua代码定义配置表单。所有CBI模型必须返回luci.cbi.Map对象:

-- 基础CBI模型结构
m = Map("network", translate("Network Settings"), 
        translate("Configure network interfaces and protocols"))

s = m:section(NamedSection, "wan", "interface", translate("WAN Interface"))
s.addremove = false
s.anonymous = true

o = s:option(Value, "proto", translate("Protocol"))
o:value("dhcp", translate("DHCP Client"))
o:value("static", translate("Static Address"))
o.default = "dhcp"

return m
5.1.1 常用CBI组件

LuCI提供丰富的CBI组件,满足不同配置需求:

组件类型用途示例
Value单行文本输入主机名、IP地址
ListValue下拉列表选择协议类型、加密方式
Flag布尔值选择启用/禁用选项
MultiValue多选列表服务访问控制
DynamicList动态可扩展列表DNS服务器
DummyValue只读显示状态信息

示例:使用ListValue创建协议选择器:

o = s:option(ListValue, "proto", translate("Protocol"))
o:value("dhcp", translate("DHCP Client"))
o:value("static", translate("Static Address"))
o:value("pppoe", translate("PPPoE"))
o:depends("ifname", "eth0")  -- 条件显示
o.default = "dhcp"

5.2 表单验证

所有用户输入必须经过验证,CBI模型通过validate方法实现:

// smartdns.js中的验证示例
o.validate = function (section_id, value) {
    if (value.length < 4 || value.length > 32) {
        return translate("Length must be between 4 and 32 characters");
    }
    if (!/^[a-zA-Z0-9_\-]+$/.test(value)) {
        return translate("Only letters, numbers, underscores and hyphens are allowed");
    }
    return true;  // 验证通过
};
5.2.1 通用验证函数

推荐封装常用验证逻辑为可复用函数:

// 验证IP地址
function validateIpAddress(section_id, value) {
    var ipRegex = /^(\d{1,3}\.){3}\d{1,3}$/;
    if (!ipRegex.test(value)) {
        return translate("Invalid IP address format");
    }
    var parts = value.split('.');
    for (var i = 0; i < 4; i++) {
        if (parseInt(parts[i]) > 255) {
            return translate("IP address octet must be between 0 and 255");
        }
    }
    return true;
}

// 使用验证函数
o.validate = validateIpAddress;

5.3 主题开发规范

LuCI主题开发应遵循模块化原则,主题目录结构如下:

luci-theme-mytheme/
├── htdocs/                # 静态资源
│   └── luci-static/
│       └── mytheme/       # 主题资源
│           ├── css/       # 样式表
│           ├── js/        # 主题脚本
│           └── images/    # 图像资源
├── luasrc/
│   └── view/
│       └── themes/
│           └── mytheme/   # 主题模板
│               ├── header.htm
│               └── footer.htm
├── root/etc/uci-defaults/ # 主题配置
└── Makefile               # 构建文件

主题开发应确保:

  • 响应式设计,适配不同屏幕尺寸
  • 优化加载性能,CSS/JS资源压缩
  • 遵循LuCI主题切换机制,通过UCI配置生效

6. 质量保障

6.1 代码审查清单

代码提交前应进行自检,确保符合以下标准:

  •  遵循文件和目录命名规范
  •  代码格式符合规范(缩进、空格、换行)
  •  所有用户输入都有验证
  •  包含必要的注释和文档
  •  使用<%: ... %>进行国际化
  •  无硬编码字符串(使用翻译函数)
  •  无控制台错误和警告
  •  在至少两种浏览器中测试通过

6.2 性能优化

LuCI前端性能直接影响低端路由器设备的响应速度,应特别注意:

6.2.1 JavaScript优化
  • 延迟加载:非关键JavaScript使用异步加载
  • 减少DOM操作:批量处理DOM更新
  • 事件委托:使用事件委托减少事件监听器
// 不佳的做法
document.querySelectorAll('.list-item').forEach(item => {
    item.addEventListener('click', handleClick);
});

// 优化做法(事件委托)
document.querySelector('.list-container').addEventListener('click', function(e) {
    if (e.target.classList.contains('list-item')) {
        handleClick.call(e.target);
    }
});
6.2.2 资源优化
  • 压缩CSS/JS:减小文件体积
  • 图像优化:使用适当格式和尺寸
  • 减少HTTP请求:合并资源文件

6.3 错误处理与调试

6.3.1 错误处理

所有可能出错的操作必须包含错误处理:

try {
    var data = JSON.parse(response);
} catch (e) {
    console.error("JSON parse failed:", e);
    luci.util.message(translate("Failed to parse response"));
}
6.3.2 调试技巧

LuCI提供luci.debug工具简化调试过程:

// 输出调试信息
if (luci.debug) {
    console.log("Network status:", status);
}

// 使用LuCI消息提示
luci.util.message(translate("Configuration saved successfully"));
luci.util.error(translate("Invalid configuration"));

7. 总结与最佳实践

7.1 核心原则回顾

  1. 一致性:遵循统一的代码风格和组织结构
  2. 可维护性:代码清晰易懂,文档完善
  3. 可靠性:严格的输入验证,健壮的错误处理
  4. 性能优先:考虑低端设备的资源限制
  5. 用户体验:直观的界面设计,友好的交互反馈

7.2 推荐学习资源

7.3 规范执行与演进

本规范不是一成不变的,随着LuCI框架的发展和社区实践的积累,将定期更新。所有开发者都有责任遵守规范,并为规范的改进提供建议。

执行机制

  • 代码提交前进行规范自检
  • 代码审查过程中检查规范符合性
  • 定期进行规范培训和宣讲
  • 每季度修订一次规范文档

通过共同遵守和持续改进本规范,我们将构建一个更高质量、更易维护的LuCI前端代码库,为OpenWrt社区提供更好的用户体验。

附录:常用代码片段

A.1 表单验证函数

// IP地址验证
function validateIp(section_id, value) {
    var parts = value.split('.');
    if (parts.length !== 4)
        return translate("Invalid IP address");
    for (var i = 0; i < 4; i++) {
        var p = parseInt(parts[i]);
        if (isNaN(p) || p < 0 || p > 255)
            return translate("Invalid IP address");
    }
    return true;
}

// 端口号验证
function validatePort(section_id, value) {
    var port = parseInt(value);
    if (isNaN(port) || port < 1 || port > 65535)
        return translate("Port must be between 1 and 65535");
    return true;
}

A.2 CBI模型示例

-- 完整的CBI配置示例
m = Map("firewall", 
        translate("Firewall Settings"),
        translate("Configure firewall rules and access control"))

-- 区域设置部分
s = m:section(NamedSection, "lan", "zone", translate("LAN Zone"))
s.addremove = false

o = s:option(MultiValue, "network", translate("Covered Networks"))
o:value("lan", translate("Local Area Network"))
o:value("wan", translate("Wide Area Network"))
o.default = "lan"

o = s:option(ListValue, "input", translate("Input Policy"))
o:value("ACCEPT", translate("Accept"))
o:value("REJECT", translate("Reject"))
o:value("DROP", translate("Drop"))
o.default = "ACCEPT"

return m

A.3 模板示例

<%
require("luci.http").prepare_content("text/html")
-%>
<!DOCTYPE html>
<html>
<head>
    <title><%:System Information%></title>
    <%+luci-static/resources/view/header.htm%>
</head>
<body>
    <div class="container">
        <h1><%:System Status%></h1>
        
        <div class="status-card">
            <h2><%:CPU Usage%></h2>
            <div class="cpu-usage">
                <%=math.floor(collectd.cpu.usage * 100)%>%
            </div>
        </div>
        
        <div class="status-card">
            <h2><%:Memory Usage%></h2>
            <div class="mem-usage">
                <%=math.floor(collectd.memory.used / collectd.memory.total * 100)%>%
            </div>
        </div>
    </div>
    <%+luci-static/resources/view/footer.htm%>
</body>
</html>

【免费下载链接】luci LuCI - OpenWrt Configuration Interface 【免费下载链接】luci 项目地址: https://gitcode.com/gh_mirrors/lu/luci

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值