# Ciyon PC前端开发指南 ## 框架概述 Ciyon是一个轻量级、高性能的PC前端开发框架,采用原生JavaScript开发,不依赖第三方库(如Vue、React、jQuery),专注于企业级后台管理系统和SaaS应用的快速开发。 ### 核心特点 - **零依赖**: 纯原生JavaScript,无第三方库依赖 - **组件化**: 提供丰富的表单组件和业务组件 - **高性能**: 优化的DOM操作和事件处理 - **响应式**: 支持多端适配(PC、平板、手机) - **国际化**: 内置多语言支持 - **主题系统**: CSS变量实现主题切换 --- ## 框架架构 ### 核心库文件 ``` web/jscss/ ├── ciy.js # 基础工具库和DOM操作 ├── ciycmp.js # 表单组件库 ├── ciycmp2.js # 扩展组件库 ├── ciytable.js # 表格和列表组件 ├── ciybigscreen.js # 数据大屏组件 ├── ciy_websocket.js # WebSocket通信 ├── style.css # 核心样式 └── theme.js # 暗黑模式 ``` ### 设计模式 #### DOM封装模式 框架使用 `$5()` 函数替代jQuery,提供统一的DOM操作接口: ```javascript // 选择元素 var dom = $5('.class-name'); // 链式调用 dom.css({color: 'red'}).addClass('active').show(); // 事件绑定 dom.on('click', function(e) { console.log('clicked'); }); ``` #### 组件化模式 使用自定义标签和 `ciycmp()` 函数初始化组件: ```html ``` #### 面向对象模式 使用类封装复杂功能: ```javascript var table = new ciyclass.table({ dom: '.table', url: 'api/list', pagecount: 20, fn_done: function(json) { console.log('data loaded'); } }); table.callpage(1); ``` --- ## 组件体系 ### 表单组件 #### 日期时间选择器(ciy-datetime) ```html ``` **属性说明**: - `com`: 组件名称(必填) - `type`: 类型(date/datetime/month) - `value`: 初始值(时间戳或日期字符串) - `mindate`: 最小日期 - `maxdate`: 最大日期 - `placeholder`: 占位文本 #### 日期范围选择器(ciy-daterange) ```html ``` **输出格式**:`开始日期~结束日期` #### 下拉选择框(ciy-select) ```html ``` #### 多选下拉框(ciy-selmulti) ```html ``` **输出格式**:`,id1,id2,id3,` #### 级联选择框(ciy-selcas) ```html ``` 用于省市区级联选择。 #### 开关(ciy-switch) ```html ``` **输出值**:`1`(开启)/ `2`(关闭) #### 单位编辑器(ciy-inputunitedit) ```html ``` 用于三级单位换算,如:1箱=20盒,1盒=24瓶。 #### 地图选择器(ciy-map) ```html ``` 输出经纬度:`lng,lat` #### 文本编辑器(ciy-textarea) ```html ``` 支持Tab键、字数统计、@用户提示。 #### 文件上传(ciy-upload) ```html ``` **属性说明**: - `type`: 允许的文件类型 - `maxcount`: 最大上传数量 - `maxkb`: 文件大小限制(KB) ### 列表组件 #### 表格组件(ciyclass.table) ```html
``` **功能特性**: - 动态列配置 - 列宽调整记忆 - 列排序 - 列隐藏 - 行选择 - 分页 - 搜索 - 顶部选项卡筛选 **顶部选项卡筛选**:使用 `fillsearch` 的 `lidata` 参数添加顶部选项卡,`liall` 设置"全部"选项的文本: ```javascript table = new ciyclass.table({ dom: '.table', url: 'list', pagecount: 20, fn_beforedata: function(json) { ciyfn.fillsearch({ searchdom: '.search', data: json, liall: '全部', lidata: [ {id: 1, name: '未使用'}, {id: 2, name: '已使用'} ], //lidata: '【字典代码】', // 引用字典写法 //lidata: ':全部.1:未使用.2:已使用', //数组简写 liclick: function(dom) { table.search(dom, 'li'); } }); return json; } }); ``` **liid编号**:自定义标识值应从1开始,不要使用0。 **后端处理**:在 `setwhere` 函数中根据 `liid` 参数进行筛选。 #### 卡片列表(ciyclass.cardtable) ```html
``` ### 功能组件 #### 弹窗(ciyfn.alert) ```javascript ciyfn.alert({ title: '提示', content: '操作成功', btn: ['确定', '取消'], cb: function(opn) { if (opn.btn == '确定') { // 确定操作 } } }); ``` #### Toast提示(ciyfn.toast) ```javascript ciyfn.toast('操作成功'); ciyfn.toast('操作失败', 'error'); ``` #### 选项卡(ciyfn.tabcard) ```html
标签1
标签2
内容1
内容2
``` --- ## 开发规范 ### HTML结构规范 #### 标准页面结构 ```html
``` #### 表单结构 ```html
``` ### JavaScript编码规范 #### 页面初始化 ```javascript 'use strict'; var table; ciyfn.pageload(function() { // 初始化组件 ciycmp({ dom: '[com=status]', range: 'status', all: '全部' }); // 初始化表格 table = new ciyclass.table({ dom: '.table', url: 'api/list', pagecount: 20 }); table.callpage(1); }); ``` #### 组件初始化 ```javascript // 标准初始化 ciycmp({ dom: '[com=component]', range: 'dictionary', value: '1', onchange: function(e) { console.log('changed:', e.value); } }); ``` #### 事件处理 ```javascript // 使用$5绑定事件 $5('.btn-save').on('click', function(e) { e.preventDefault(); // 保存逻辑 }); // 使用原生addEventListener document.querySelector('.btn-save').addEventListener('click', function(e) { e.preventDefault(); // 保存逻辑 }); ``` #### API调用 ```javascript ciyfn.callfunc('api/admin.update', { id: 1, name: 'test' }, function(json) { //返回code:1,成功回调 }); ``` #### 表单获取 ```javascript var form = ciyfn.getform('.search'); console.log(form); ``` ### 样式规范 #### CSS变量 ```css :root { /* 主色 */ --man3: #d7eeff; --man4: #80c1f3; --man5: #1E9FFF; --man6: #1e89db; --man7: #8568f7; --mant: #ffffff; /* 成功色 */ --succ5: #03a547; --succ6: #048238; --succt: #ffffff; /* 警示色 */ --warn5: #e39725; --warn6: #b97a1c; --warnt: #ffffff; /* 失败色 */ --dag5: #e34242; --dag6: #bd2525; --dagt: #ffffff; /* 文字色 */ --txt1: #8c9ba4; --txt2: #818e97; --txt3: #738088; --txt4: #646e76; --txt5: #576067; --txt6: #454d52; --txt7: #2c3236; --txt8: #060708; --txt9: #000000; /* 背景色 */ --bg1: #ffffff; --bg2: #fbfbfc; --bg3: #f7f8f8; --bg4: #f0f2f2; --bg5: #e3e6e7; --bg6: #cdd2d4; --bg7: #afb6b9; --bg8: #939da1; --bg9: #7e8a8e; /* 其他css变量 */ --e-scroll: rgba(0, 0, 0, 0.2); --e-tabselect: #fffec5; --e-dialog: 2px 2px 20px -10px #000000; --e-inputbg: #f7f7f7; --e-inputbr: #ffffff; --e-switchtxt: #2c3236; --e-inputshadow: 0 1px 3px 0 #00000042; --e-menusec: 0.5s; } ``` #### 响应式断点 ```css @media (max-width: 767px) { /* 手机 */ } @media (max-width: 991px) { /* 平板 */ } @media (min-width: 576px) { /* 平板及以上 */ } @media (min-width: 992px) { /* PC */ } ``` --- ## 后端交互 ### API调用规范 #### 标准请求格式 ```javascript ciyfn.callfunc('/admin/user.update', { param1: 'value1', param2: 'value2' }, function(json) { // 处理响应 }); ``` #### 标准响应格式 ```json { "code": 1, "msg": "成功", "data": {}, "list": [], "count": 100, "pageno": 1, "once": {} } ``` ### 认证机制 框架使用JWT进行用户认证,Token存储在Cookie或LocalStorage中。 ``` // 获取 var me = ciyfn.getstorage(ciy_vars.tokenfield); ``` ### 权限控制 ``` // 检查权限 if (ciyfn.nopower(me.power, 'p1v')) { ciyfn.alert('未被授权'); } ``` 权限格式:`.p1v.p2v.p3v.`(p=父权限,v=查看) --- ## 最佳实践 ### 组件命名 - 使用 `com` 属性标识组件name - 组件名采用下划线命名法 - 表单字段使用有意义的名称 ```html ``` ### 数据字典 字典数据通过 `range` 属性引用: ```javascript // 字典结构 [{ id: 1, name: '状态1', upid: 0 }] // 使用 ciycmp({ dom: '[com=status]', range: 'userstatus' // 从localstorage缓存读取 }); ``` ### 事件处理 - 使用 `onchange` 处理组件值变化 - 事件回调接收统一的参数对象 ```javascript ciycmp({ dom: '[com=status]', onchange: function(e) { console.log(e.name); // 组件名称 console.log(e.value); // 组件值 console.log(e.dom); // DOM元素 console.log(e.from); // 触发来源 } }); ``` ### 国际化 使用 `ciyfn.lang()` 函数实现多语言: ```javascript console.log(ciyfn.lang('保存')); console.log(ciyfn.lang('删除')); ``` ### 性能优化 - 使用 `ciyfn.throttle()` 防抖 - 使用 `ciyfn.lazyimg()` 懒加载图片 - 列表分页加载 - 图片URL转换:使用 `ciyfn.file_stor()` 将数据库存储路径转换为云存储绝对URL - 图片查看:使用 `ciyfn.showimg(index, imagesString)` 查看多张图片,参数为起始索引和用`~`连接的图片路径字符串 ```javascript // 图片URL转换 var imgurl = ciyfn.file_stor('/2024/03/14/image.jpg'); // 查看多张图片,用~分隔(数据库中的原始存储) ciyfn.showimg(1, '/img/1.jpg~/img/2.jpg~/img/3.jpg'); // 从第2张开始查看 ``` ```javascript // 防抖示例 $5('.search-input').on('input', function() { if (ciyfn.throttle(this)) return; // 搜索逻辑 }); ``` --- ## 开发流程 ### 新建页面 1. 在 `web/xxx/` 下创建同名HTML文件和后端文件 2. 引入必要的JS和CSS文件 3. 使用组件标签构建页面 4. 编写初始化逻辑 5. 实现交互功能 6. 测试和优化 ### 示例代码 #### 列表页面示例 ```html
``` #### 表单页面示例 ```html
``` --- ## 常用API ### 工具函数 ```javascript // 全局函数 tostr(val, defval) // 转字符串 toint(val, def) // 转整数 tofloat(val, def) // 转浮点数 tostamp(time) // 转时间戳 isarray(v) // 判断是否Array类型 isobj(v) // 判断是否Object类型 iselement(v) // 判断是否Element类型 // DOM操作 $5(selector) // 选择元素 dom.css('color') // 获取样式 dom.css()['color'] // 获取计算后样式 dom.css(name, val) // 设置样式 dom.css({color:#xxx}) // 批量设置样式 dom.show() / dom.hide() // 显示/隐藏 dom.on(event, handler) // 绑定事件 dom.val(value) // 获取/设置值 // 数据处理 ciyfn.tojson(str) // JSON解析 ciyfn.jsontostr(obj) // JSON序列化 ciyfn.tostamp(time) // 转时间戳 ciyfn.todatetime(stamp, fmt) // 格式化日期 // 存储 ciyfn.getstorage(key) // 读取存储 ciyfn.setstorage(key, val) // 写入存储 // 消息提示 ciyfn.toast(msg, type) // 提示 ciyfn.alert(opn) // 弹窗 // API调用 ciyfn.callfunc(url, data, callback, opn) // 调用接口 ``` ### 表格API ```javascript // 分页 table.callpage(page); // 加载页面 table.updateline(json); // 更新行 table.delline(json); // 删除行 // 搜索 table.search(dom, act); // 执行搜索 ``` --- ## 八、注意事项 1. **原生开发**: 尽量使用原生开发,已封装$5(jQuery改进版) 1. **严格模式**: 所有JS代码使用 `'use strict'` 3. **引号使用**: 代码中使用单引号 4. **事件处理**: 使用 `$5().on()` 或原生 `addEventListener` 5. **异步处理**: 使用回调函数处理异步结果 6. **数据验证**: 后端必须验证数据 7. **错误处理**: 无需处理API错误,自动弹窗。特殊情况,在opn参数中定义fail函数 8. **性能优化**: 大数据列表使用分页加载 9. **兼容性**: 确保IE11+兼容 10. **安全性**: 防止XSS和CSRF攻击 11. **菜单结构设计**: PC端菜单应具备清晰的层级结构,二次菜单设计必须有一级菜单。 --- ## 常见问题 ### Q: 组件不显示? A: 检查是否正确引入了组件库文件(ciycmp.js、ciycmp2.js)。 ### Q: 表格数据不加载? A: 检查API返回格式是否符合标准,确认 `url` 参数正确。 ## 参考资料 - 组件示例:`web/admin/demo/front/` - API文档:参考各组件的源码注释 - 设计思路:参考框架注释中的设计说明 --- **版本**: 1.0.0 **作者**: Ciyon Team