知识库,设置基于 cursor rules 的文档
7 files added
1 files deleted
New file |
| | |
| | | # 文件夹介绍 |
| | | |
| | | ## rules 文件夹 |
| | | |
| | | rules 是指编辑器根据一定条件自动读取的对 AI 的要求 |
| | | |
| | | > 注意:需要进行初始化 |
| | | > 请双击执行项目根目录 `link-rules.cmd` 命令文件,将公共资源目录中的 rules 链接到编辑器中 |
| | | > 然后在编辑器设置中查看是否链接成功(CursorSetting > Rules > ProjectRules) |
| | | |
| | | ### 规则类型:全局使用 `Always` |
| | | |
| | | 所有的聊天(Agent、Ask、Edit)和 ctrl+k 编辑,都会参考此规则 |
| | | |
| | | - [AI系统扮演角色](/src/components/_cursor.ai/rules/all-system-role.mdc) |
| | | - [项目介绍](/src/components/_cursor.ai/rules/all-project-info.mdc) |
| | | - [开发规范](/src/components/_cursor.ai/rules/all-dev-specification.mdc) |
| | | |
| | | ### 规则类型:按路径匹配 `Auto-Attached` |
| | | |
| | | 当路径规则匹配上时,会参考此规则 |
| | | |
| | | - 请求集 |
| | | - [数据控制器](/src/components/_cursor.ai/rules/type-controller.mdc) |
| | | - 界面 |
| | | - 子组件 |
| | | - 公共组件 |
| | | |
| | | ### 规则类型:自主决定 `Agent-Requested` |
| | | |
| | | 根据 Description 的文字描述,由 AI 自主决定是否需要参考此规则 |
| | | 仅 Agent 模式生效,非 Agent 模式需要我们自己 @ 此规则 |
| | | |
| | | - [请求集基类](/src/components/_cursor.ai/rules/fit-base-fetcher.mdc) |
| | | - [数据控制器基类](/src/components/_cursor.ai/rules/fit-base-pilot.mdc) |
| | | - 表单验证规则 |
| | | |
| | | ## prompts 文件夹 |
| | | |
| | | prompts 是我们主动提问,和我们在聊天窗口叫 ai 干活一样 |
| | | 区别是对于经常执行的有具体要求的操作,固定下来方便反复使用 |
| | | |
| | | ## 文档文件夹 |
| | | |
| | | 公共组件库组件对应的文档 |
| | | |
| | | | 文档目录 | 对应的组件目录 | |
| | | | ------------- | ----------------------- | |
| | | | `common.doc` | src/components/common/ | |
| | | | `forms.doc` | src/components/forms/ | |
| | | | `layout.doc` | src/components/layout/ | |
| | | | `plugins.doc` | src/components/plugins/ | |
New file |
| | |
| | | --- |
| | | description: |
| | | globs: |
| | | alwaysApply: true |
| | | --- |
| | | |
| | | # 开发规范 |
| | | |
| | | ## 开发规范宗旨 |
| | | |
| | | **代码首先是给人读的,其次才是给机器运行**,所以让代码容易阅读是你应尽的责任 |
| | | 包括但不限于以下内容: |
| | | - 变量、函数命名需具有实义 |
| | | - 避免使用难懂的语法或设计,用最简单的方式解决问题 |
| | | - 避免单块代码过长,拆分为多个更简短的函数或方法 |
| | | - 避免代码重复,通过封装函数、类或模块进行复用,封装遵守单一职责原则 |
| | | - 写注释应解释 "为什么" 而不仅仅是 "做什么" |
| | | |
| | | ### 命名需要具有实义 |
| | | |
| | | 命名的原则是名称中有具体实体含义的词汇 |
| | | |
| | | 比如没有实义的 |
| | | |
| | | ```js |
| | | const onClick = () => null; // 不好的命名 |
| | | ``` |
| | | |
| | | 因为 `click` 可以发生在任何元素上,从这个名称上无法分辨业务种类,所以我们认为这个函数名没有实义,需要改进一下: |
| | | |
| | | ```js |
| | | const onProductSelected = () => null; // 良好的命名 |
| | | ``` |
| | | |
| | | 改进后,从函数名一看便知,这是商品被选中了以后的需要进行的操作,又因为具备了在同一个页面的唯一性,能帮我们快速获取信息,知道这是哪个业务的哪个环节,大幅提高阅读效率,这就是实义 |
| | | |
| | | ## 常见命名要求 |
| | | |
| | | ### JS 变量和属性的命名 |
| | | |
| | | 使用小驼峰,注意不能以动词开头 |
| | | |
| | | ```js |
| | | // 变量 |
| | | const name = ''; |
| | | const orderList = ''; |
| | | // 属性 |
| | | const user = { |
| | | name: '', |
| | | lastOrder: '', |
| | | }; |
| | | ``` |
| | | |
| | | #### 变量命名的特别约定 |
| | | |
| | | **变量名允许 is 开头** |
| | | 变量名不能用动词开头,但是允许 is 作为特例 |
| | | |
| | | ```js |
| | | // 允许 is 开头的变量名 |
| | | let isOpened = false; |
| | | // 更好的命名 |
| | | let selectorOpened = false; |
| | | ``` |
| | | |
| | | **事件变量用 evt** |
| | | 事件 event 的简写,必须是 evt(不能用单字母 e ) |
| | | |
| | | ```html |
| | | <view @tap="evt => onOrderClick(evt)"></view> |
| | | <CMenu :onClick="evt => onMenuItemClick(evt)" /> |
| | | ``` |
| | | |
| | | **报错信息用 err** |
| | | 报错 error 的简写,必须是 err(不能用单字母 e ) |
| | | |
| | | ```js |
| | | Taro.request({ |
| | | fail: err => {}, |
| | | }); |
| | | ``` |
| | | |
| | | **后端数据 res** |
| | | 后端返回数据,优先采用 resource 的简写 res |
| | | |
| | | ```js |
| | | $fetch.getEquipments().then(res => {}); |
| | | ``` |
| | | |
| | | ### JS 方法的命名 |
| | | |
| | | #### 在数据控制层 |
| | | |
| | | **提供给界面层使用的方法,用 on 开头** |
| | | |
| | | ```js |
| | | // 数据控制层定义 |
| | | onOpenOrderDetail() {} |
| | | ``` |
| | | |
| | | ```html |
| | | // 界面层使用 |
| | | <view class="order-item" @tap="evt => onOpenOrderDetail()"> |
| | | ``` |
| | | |
| | | **数据层自用的方法,用下划线开头** |
| | | |
| | | ```js |
| | | // 数据控制层定义 |
| | | _checkOrderDetailOpened() {} |
| | | |
| | | onOpenOrderDetail() { |
| | | // 数据控制层内部自用 |
| | | this._checkOrderDetailOpened(); |
| | | } |
| | | ``` |
| | | |
| | | #### 在组件内 |
| | | |
| | | **接收父级方法的时候,用 on 开头** |
| | | |
| | | ```js |
| | | export default { |
| | | props: { |
| | | // 选择会员后的回调 |
| | | onUserSelected: Function, |
| | | }, |
| | | } |
| | | ``` |
| | | |
| | | **组件自身模版绑定的时候,用 handle 开头** |
| | | |
| | | ```js |
| | | export default { |
| | | methods: { |
| | | // 组件层定义 |
| | | handleUserSelected() {} |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | ```html |
| | | // 组件层自身模板绑定 |
| | | <view class="user-item" @tap="evt => handleUserSelected()"> |
| | | ``` |
| | | |
| | | **函数相互调用的时候,用下划线开头** |
| | | |
| | | ```js |
| | | export default { |
| | | methods: { |
| | | // 组件层定义 |
| | | _checkUser() {}, |
| | | handleUserSelected() { |
| | | // 组件层内部自用 |
| | | this._checkUser() |
| | | } |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | **给父级ref的引用进行调用的方法,使用 $ 开头** |
| | | |
| | | ```js |
| | | export default { |
| | | methods: { |
| | | // 组件层定义 |
| | | $close() {} |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | 父级 |
| | | |
| | | ```html |
| | | <CUserDetail ref="userDetail"> |
| | | ``` |
| | | |
| | | ```js |
| | | onCloseAll() { |
| | | // 父级 ref 调用 |
| | | this.$refs.userDetail.$close() |
| | | } |
| | | ``` |
| | | |
| | | ### 样式命名 |
| | | |
| | | 样式名的命名,采用横杠连接 |
| | | |
| | | ```css |
| | | .page-name {} |
| | | ``` |
| | | |
| | | #### 界面样式 |
| | | |
| | | 任何一个界面必定包含众多样式,所以: |
| | | |
| | | * 最父级样式名固定,与界面名称一直 |
| | | * 中间层,需要以父级为前缀,接板块说明 |
| | | * 末端则可单名,且尽量不含实义 |
| | | |
| | | ```css |
| | | /** 在界面 userList.vue 中,最父级样式名名称固定 **/ |
| | | .user-list { |
| | | |
| | | /** 中间多层,以父级为前缀 **/ |
| | | .user-list-title { |
| | | |
| | | /** 末端可单名,尽量非实义 **/ |
| | | .left, |
| | | .text, |
| | | .icon, |
| | | .sub, |
| | | .close {} |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | #### 组件样式 |
| | | |
| | | 组件样式名必须已 `c-` 开头,最父级样式名必须与组件名挂钩 |
| | | |
| | | 例如,组件 CMenu.vue 中,最父级样式名必须是: |
| | | |
| | | ```css |
| | | .c-menu {} |
| | | ``` |
| | | |
| | | |
| | | ### 文件命名 |
| | | |
| | | 常用文件命名约定 |
| | | |
| | | #### 界面层文件 |
| | | |
| | | 界面层文件(.vue、.scss),采用小驼峰命名 |
| | | |
| | | ``` |
| | | index.vue |
| | | index.scss |
| | | ``` |
| | | |
| | | #### 数据控制层文件 |
| | | |
| | | 数据控制器文件(.js),以固定前缀 P 开头,再接大驼峰 |
| | | |
| | | ``` |
| | | PIndex.js |
| | | ``` |
| | | |
| | | 数据层代码定义的名称,需要和文件名一致 |
| | | |
| | | ```js |
| | | export class PIndex extends Pilot {} |
| | | ``` |
| | | |
| | | #### 组件文件 |
| | | |
| | | 不论是公共组件还是页面子组件(.vue、.scss),都以固定前缀 C 开头,再接大驼峰 |
| | | |
| | | ``` |
| | | CMenu.vue |
| | | CMenu.scss |
| | | ``` |
| | | |
| | | 组件代码定义的名称,需要和文件名一致 |
| | | |
| | | ```js |
| | | // CMenu.vue 的组件名,必须是 CMenu |
| | | export default { |
| | | name: 'CMenu', |
| | | } |
| | | ``` |
| | | |
| | | #### 请求文件 |
| | | |
| | | 请求层文件(.js),以固定前缀 F 开头,再接大驼峰 |
| | | |
| | | ``` |
| | | FCommon.js |
| | | ``` |
| | | |
| | | 请求集合的代码定义名称,需要和文件名一致 |
| | | |
| | | ```js |
| | | // FCommon.js 的类名称,必须是 FCommon |
| | | class FCommon extends Fetcher {} |
| | | |
| | | // FCommon.js 代表的类的实例名称,则是 $fetchCommon |
| | | export const $fetchCommon = new FCommon(); |
| | | ``` |
| | | |
| | | ## 常见书写要求 |
| | | |
| | | ### 基础书写要求 |
| | | |
| | | 书写规则都由编辑器自动格式化即可,例如 |
| | | - 使用四个空格代替 tab |
| | | - 单行代码宽度最多100个字符 |
| | | - js 代码使用单引号 |
| | | |
| | | 更多规则请参考根目录 `.prettierrc` 文件 |
| | | |
| | | ### JS 中的书写 |
| | | |
| | | #### 变量定义符 |
| | | |
| | | 弃用 `var` ,改用 `const` 与 `let` ,且优先使用 `const` ,除非要改值 |
| | | |
| | | ```js |
| | | const name = 'Tevin'; |
| | | ``` |
| | | |
| | | ```js |
| | | let count = 0; |
| | | count++; |
| | | ``` |
| | | |
| | | 注意,const 定义的对象,其属性是可以改值的 |
| | | |
| | | ```js |
| | | const search = { |
| | | count: 1 |
| | | }; |
| | | search.count++; // 允许运行 |
| | | search = {}; // 报错 |
| | | ``` |
| | | |
| | | 所以: |
| | | * 对于普通数据,如果明确要变更变量值,才使用 `let` |
| | | * 对于引用数据,如果明确需要重新赋值一个引用对象,才使用 `let` |
| | | |
| | | #### 变量判断 |
| | | |
| | | 为了避免弱类型带来的bug追踪困难,变量判断需要使用恒等号,必须判断类型一致 |
| | | |
| | | ```js |
| | | // 需要同时判断值和类型 |
| | | if (order.state === 1) {} |
| | | ``` |
| | | |
| | | #### 模版中的函数调用 |
| | | |
| | | - 模版中调用函数,为了便于阅读,必须显式的书写 evt 变量和箭头函数,即: `evt => fncName()`,**这是规范要求,不是代码冗余** |
| | | - 把 Taro 自身组件视为普通元素,元素绑定事件使用 `@tap` 的方式 |
| | | - 非元素皆是组件,组件使用 `:onClick` 的方式绑定 |
| | | |
| | | 例如: |
| | | ```html |
| | | <!-- 元素绑定事件使用 --> |
| | | <view @tap="() => onOpenOrderDetail()"></view> |
| | | <!-- 组件绑定事件使用 --> |
| | | <CMenu :onItemClick="evt => onMenuItemClick(evt)" /> |
| | | ``` |
| | | |
| | | #### 以 JSDoc 格式写方法注释 |
| | | |
| | | 公共代码中的方法都需要以 JSDoc 的格式写注释 |
| | | |
| | | ```js |
| | | export class Tools { |
| | | /** |
| | | * 显示消息提示框 |
| | | * @param {string} msg - 提示的消息内容 |
| | | * @param {number} [duration=2000] - 提示框显示时长(毫秒) |
| | | * @param {boolean} [mask=false] - 是否显示透明蒙层,防止触摸穿透 |
| | | */ |
| | | static toast(msg, duration = 2000, mask = false) { |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | ### CSS 属性顺序 |
| | | |
| | | 为了避免 css 属性写重复,请按如下顺序书写: |
| | | |
| | | * **文档流属性** |
| | | display, position, float, clear, visibility, table-layout 等 |
| | | |
| | | * **大小属性** |
| | | width, height, margin, padding 等 |
| | | |
| | | * **文字排版属性** |
| | | font, line-height, text-align, text-indent, vertical-align 等 |
| | | |
| | | * **装饰性属性** |
| | | color, background, border, opacity, shadow, cursor 等 |
| | | |
| | | * **生成内容属性** |
| | | content, list-style, quotes 等 |
| | | |
| | | * **二次渲染属性** |
| | | zoom, transform 等 |
| | | |
| | | * **动画属性** |
| | | transition, animation 等 |
New file |
| | |
| | | --- |
| | | description: |
| | | globs: |
| | | alwaysApply: true |
| | | --- |
| | | |
| | | # 项目介绍 |
| | | |
| | | ## 工程介绍 |
| | | |
| | | 这是一套Web前端开发的工程文档,用于指导移动端(H5网页、混合App、小程序等)的开发 |
| | | |
| | | |
| | | ## 技术栈 |
| | | |
| | | - 语法框架:Vue(v2.5.0) |
| | | - 工程框架:Taro(v3.2.13) |
| | | - 显示框架:Taro-UI-Vue(v1.0.0-beta.10) |
| | | - 样式:Sass |
| | | |
| | | 说明:使用时,优先使用公共组件库的组件,其次是 Taro-UI-Vue 的组件,最后才是 Taro 本身的基础元素组件 |
| | | |
| | | ## 工程目录结构 |
| | | |
| | | 工程主要目录及其用途 |
| | | |
| | | - root/(根目录) |
| | | - public/(静态资源目录) |
| | | - src/(开发源码目录) |
| | | - components/(公共资源目录) |
| | | - bases/(公共基类目录) |
| | | - common/(公共工具目录) |
| | | - forms/(公共表单组件目录) |
| | | - layout/(公共排版组件目录) |
| | | - plugins/(公共复杂组件目录) |
| | | - fetchers/(请求层目录) |
| | | - FName.js(请求集) |
| | | - pages/(界面层目录) |
| | | - pageGroup/(界面层分组目录) |
| | | - pageName/(界面层单页目录) |
| | | - cmpt/(界面子组件目录) |
| | | - CName.vue(子组件) |
| | | - cName.scss(子组件样式) |
| | | - page.vue(界面) |
| | | - page.scss(界面样式) |
| | | - pilots/(数据控制层目录) |
| | | - _overall/(全局数据控制目录) |
| | | - pilotGroup/(数据控制层分组目录) |
| | | - mixin/(混合件目录) |
| | | - MName.js(混合件) |
| | | - PName.js(数据控制器) |
| | | |
| | | ### 目录解释 |
| | | |
| | | - **公共资源目录**:移动端所有项目公用,使用 git 子模块跨项目同步 |
| | | - **界面层**:包含界面和子组件,界面子组件是对整个逻辑流程的单个节点的封装(TODO:界面拆分原理) |
| | | - **数据控制层**:包含数据控制器和混合件,混合件是数据控制器代码片段共享的一种设计(非vue混入) |
| | | - **请求层**:请求层中的单个文件是请求集,一个请求集存放某个类型业务的所有请求的集合 |
| | | |
| | | ### 短路径映射 |
| | | |
| | | 工程资源引用时,通常使用更短的引用路径: |
| | | |
| | | * `@components` 代表 `root/src/components` |
| | | * `@fetchers` 代表 `root/src/fetchers` |
| | | * `@pages` 代表 `root/src/pages` |
| | | * `@pilots` 代表 `root/src/pilots` |
| | | |
| | | 例如:'@components/layout/h5Page' 实际引用的是 'root/src/components/layout/h5Page' |
| | | |
| | | |
| | | ## 页面构成 |
| | | |
| | | ### 页面定义 |
| | | |
| | | 当我们说页面的时候,不是普通的 vue 组件,而是由**界面层**和**数据控制层**两部分共同组成的代码实体,逻辑结构如下 |
| | | |
| | | - 页面: |
| | | - 界面层(root/src/pages/pageGroup/pageName/page.vue) |
| | | - 界面子组件(root/src/pages/pageGroup/pageName/cmpt/CName.vue) |
| | | - 数据控制层(root/src/pilots/pilotsGroup/PName.js) |
| | | - 请求层(root/src/fetchers/FName.js) |
| | | |
| | | (当我们说组件、子组件、公共组件的时候,才是指普通 Vue 组件) |
| | | |
| | | ### 界面层和数据控制层的拆分 |
| | | |
| | | 一个业务页面的界面层和数据控制层,实际上是对一个 Vue 组件的拆分,最终运行的时候,还是会合二为一,还原成原本的 Vue 实例 |
| | | 因此,数据控制层其实是对这个 Vue 实例部分功能的一种转写,类似于语法糖 |
| | | |
| | | **数据控制层写法** |
| | | |
| | | 例如: |
| | | |
| | | ```js |
| | | // 数据控制器 |
| | | export class PIndex extends Pilot { |
| | | $data() { |
| | | return { |
| | | a: 1, |
| | | }; |
| | | } |
| | | $computed = { |
| | | a2() {}, |
| | | }; |
| | | $mounted() {} |
| | | onOpenSelector() {} |
| | | } |
| | | ``` |
| | | |
| | | 会转换成 |
| | | |
| | | ```js |
| | | // 标准 Vue |
| | | const Component = Vue.extend({ |
| | | data() { |
| | | return { |
| | | a: 1, |
| | | }; |
| | | }, |
| | | computed: { |
| | | a2() {}, |
| | | }, |
| | | methods: { |
| | | onOpenSelector() {}, |
| | | }, |
| | | mounted() {}, |
| | | }); |
| | | ``` |
New file |
| | |
| | | --- |
| | | description: |
| | | globs: |
| | | alwaysApply: true |
| | | --- |
| | | # 角色 |
| | | |
| | | ## 你是一名拥有10年经验的资深Web前端开发工程师 |
| | | - 对代码质量有严格的要求,代码语义清晰、简洁高效 |
| | | - 拥有丰富的开发实践,擅长编写易于使用和维护的组件,能够设计干净健壮的架构 |
| | | - 懂得遵守最小改动原则,尽量不破坏现有功能 |
| | | - 擅长编用 markdown 写技术文档,层次分明、齐全易懂 |
| | | |
| | | ## 你是一个重视需求分析的开发者 |
| | | - 善于从用户角度理解业务需求 |
| | | - 会主动发现需求中存在缺陷,并与用户讨论完善 |
| | | - 倾向于选择最简单的解决方案,避免过度设计 |
| | | |
| | | ## 你是一个熟悉液化气行业的专业人士 |
| | | - 了解液化气充装、配送、销售等业务流程 |
| | | - 了解会员、订单、气瓶、电子秤等资产管理相关内容 |
New file |
| | |
| | | --- |
| | | description: 数据控制器基类,所有数据控制器都必须继承此类 |
| | | globs: |
| | | alwaysApply: false |
| | | --- |
| | | |
| | | # 请求层基类 Fetcher.js |
| | | |
| | | ## 功能说明 |
| | | |
| | | 类 Fetcher 是一个用于处理 HTTP 请求的基类,包含了URL拼接、响应数据适配、报错提示等多种方法来简化和统一请求的处理 |
| | | 请求层的每个请求集,都必须继承此类 |
| | | |
| | | ## 引用方法 |
| | | |
| | | ```js |
| | | import { |
| | | Fetcher |
| | | } from '@components/bases/Fetcher'; |
| | | ``` |
| | | |
| | | ## 构造函数 |
| | | |
| | | 构造函数接受一个配置对象作为参数,包含如下属性: |
| | | |
| | | - **urlPrefix** 数组,包含两项,第一项为本地 Mock 的 URL 前缀,第二项为服务器接口的前缀 |
| | | |
| | | ```js |
| | | class FCommon extends Fetcher { |
| | | |
| | | constructor() { |
| | | // 构造函数使用示例 |
| | | super({ |
| | | urlPrefix: ['/api/order/', '/mini/order/'], |
| | | }); |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | ## 主要方法 |
| | | |
| | | |
| | | ### `spellURL(devSuffix, serSuffix)` |
| | | |
| | | **功能** |
| | | 根据开发环境和生产环境拼接 URL 地址 |
| | | |
| | | **参数** |
| | | - `devSuffix` (String):开发环境下的 URL 后缀 |
| | | - `serSuffix` (String, 可选):生产环境下的 URL 后缀。如果未提供,则使用 `devSuffix` |
| | | |
| | | **返回值** |
| | | - (String):处理后的完整 URL 地址 |
| | | |
| | | **示例** |
| | | ```javascript |
| | | class FCommon extends Fetcher { |
| | | |
| | | getUserInfo(id) { |
| | | const url = this.spellURL('getUserInfo', 'user/user_info'); |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | **注意事项** |
| | | - 如果启用了 Mock 模式(比如本地开发时),URL 会指向本地的 JSON 文件 |
| | | - 自动处理路径中的 `../` 和多余的 `/`,确保路径正确 |
| | | |
| | | --- |
| | | |
| | | ### `get(url, data, options)` |
| | | |
| | | **功能** |
| | | 发起 GET 请求 |
| | | |
| | | **参数** |
| | | - `url` (String):请求的 URL 地址 |
| | | - `data` (Object):请求参数 |
| | | - `options` (Object,可选):请求配置 |
| | | |
| | | **返回值** |
| | | - (Promise):返回请求结果的 Promise |
| | | |
| | | --- |
| | | |
| | | ### `post(url, data, options)` |
| | | |
| | | **功能** |
| | | 发起 POST 请求,query 方法的简写 |
| | | |
| | | **参数** |
| | | - `url` (String):请求的 URL 地址 |
| | | - `data` (Object):请求参数 |
| | | - `options` (Object,可选):请求配置 |
| | | |
| | | **返回值** |
| | | - (Promise):返回请求结果的 Promise |
| | | |
| | | **示例** |
| | | ```js |
| | | class FCommon extends Fetcher { |
| | | |
| | | getUserInfo() { |
| | | const url = this.spellURL('getUserInfo', 'user/user_info'); |
| | | const send = {}; |
| | | return this.post(url, send); |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ### `query(type, url, data, options)` |
| | | |
| | | **功能** |
| | | 发起基础 AJAX 请求 |
| | | |
| | | **参数** |
| | | - `type` (String):请求类型(如 `'get'`、`'post'`) |
| | | - `url` (String):请求的 URL 地址 |
| | | - `data` (Object,可选):请求参数 |
| | | - `options` (Object,可选):请求配置(参照下文) |
| | | |
| | | **返回值** |
| | | - (Promise):返回请求结果的 Promise |
| | | |
| | | **注意事项** |
| | | - 小程序环境下会自动处理 Cookie,无需手动设置 |
| | | |
| | | --- |
| | | |
| | | ### `stringToCamel(str)` |
| | | |
| | | **功能** |
| | | 将下划线命名的字符串转换为小驼峰命名 |
| | | |
| | | **参数** |
| | | - `str` (String):需要转换的字符串 |
| | | |
| | | **返回值** |
| | | - (String):转换后的小驼峰字符串 |
| | | |
| | | --- |
| | | |
| | | ### `stringToUnderline(str)` |
| | | **功能** |
| | | 将小驼峰命名的字符串转换为下划线命名,如果没有大写字母,则返回原字符串 |
| | | |
| | | **参数** |
| | | - `str` (String):需要转换的字符串 |
| | | |
| | | **返回值** |
| | | - (String):转换后的下划线字符串 |
| | | |
| | | --- |
| | | |
| | | ### `transKeyName(type, json)` |
| | | **功能** |
| | | 将 JSON 对象的键名在驼峰与下划线命名模式之间转换 |
| | | |
| | | **参数** |
| | | - `type` (String):转换的目标类型,有两个值: |
| | | - `'camel'`:下划线转小驼峰 |
| | | - `'underline'`:小驼峰转下划线 |
| | | - `json` (Object):需要转换的 JSON 对象 |
| | | |
| | | **返回值** |
| | | - (Object):转换后的 JSON 对象 |
| | | |
| | | **示例** |
| | | ```js |
| | | class FCommon extends Fetcher { |
| | | |
| | | saveUserInfo() { |
| | | const json = { 'user_name': 'John' }; |
| | | const result = this.transKeyName('camel', json); // 返回 { userName: 'John' } |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | **注意事项** |
| | | - 支持嵌套对象的递归转换 |
| | | |
| | | ## 请求 query 的 options 配置 |
| | | |
| | | ### `hostType` 主机类型 |
| | | |
| | | 在混合 App 中,指定本次请求的主机类型(即域名),有两个值: |
| | | |
| | | - `base`:基础主机(预登陆用) |
| | | - `main`:默认主机,默认值,正常业务主机 |
| | | - 优先由 java 层在 webview 的 URL 上指定 |
| | | - 未指定时,按文件 project.config.json 的 host.buildHost 项值指定 |
| | | |
| | | **示例** |
| | | ```js |
| | | class FCommon extends Fetcher { |
| | | |
| | | loginPrepare() { |
| | | const url = this.spellURL('loginPrepare', 'User/preLogin'); |
| | | const send = {}; |
| | | return this.post(url, send, { hostType: 'base' }); |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | ### `silence` 静音请求 |
| | | 设为 true 时,如果请求失败,不显示提示 |
| | | |
| | | **示例** |
| | | ```js |
| | | class FCommon extends Fetcher { |
| | | |
| | | getUserInfo() { |
| | | const url = this.spellURL('getUserInfo', 'User/info'); |
| | | const send = {}; |
| | | return this.post(url, send, { silence: true }); |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | |
| | | ## 响应处理 |
| | | |
| | | ### 处理流程 |
| | | |
| | | 1. query 方法调用 Taro.request 发送请求 |
| | | 2. 收到响应后,先检测响应数据格式,发现其他类型的响应格式时,会自动转换为:**前端统一响应数据格式** |
| | | 3. 根据响应格式 |
| | | - 如果成功,将响应内容,回传给数据控制层 |
| | | - 如果失败,直接失败提示,回传空内容给数据控制层 |
| | | 4. 将响应内容传给数据控制层之前,会进行如下处理 |
| | | - 将数据中的键名,转换为的驼峰 |
| | | - 将数据中的内容,如果是常规数字的字符串,转为数值 |
| | | |
| | | ### 前端统一响应数据格式 |
| | | |
| | | 格式如下: |
| | | |
| | | ```js |
| | | { |
| | | state: { // 状态 |
| | | code, // 状态码 |
| | | msg // 状态消息 |
| | | }, |
| | | data: { // 实际数据,必须是 Object |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | 例如: |
| | | |
| | | ```json |
| | | { |
| | | "state": { |
| | | "code": 2000, |
| | | "msg": "OK" |
| | | }, |
| | | "data": { |
| | | "id": 1, |
| | | "name": "Tevin" |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | 注意,为了保证接口数据的扩展性,data 只能接 Object 类型,禁止接其他类型 |
| | | |
| | | ### 前端统一响应状态码 |
| | | |
| | | - `2000`:通用请求成功 |
| | | - `2001`:请求成功,但是没有数据,弹窗提示 msg(仅特殊情况使用) |
| | | - `5000`:通用请求失败,弹窗提示 msg |
| | | - `9001`:登录已过期,返回登录页 |
| | | - `9002`:已登录但没有操作权限,弹窗提示 msg |
| | | |
| | | ## 请求调用 |
| | | |
| | | 请求层的每一个请求集,都会实例化自身作为全局单例,使用时,只需引用已经实例化好的全局单例,直接发请求即可 |
| | | |
| | | ```js |
| | | import { Fetcher } from '@components/bases/Fetcher'; |
| | | |
| | | class FCommon extends Fetcher {} |
| | | |
| | | // 全局单例 |
| | | export const $fetchCommon = new FCommon(); |
| | | ``` |
| | | |
| | | ```js |
| | | import { |
| | | $fetchCommon |
| | | } from '@fetchers/FCommon'; |
| | | |
| | | export class PPageName extends Pilot { |
| | | |
| | | // 在数据控制层中,发请求示例 |
| | | onLoadUserInfo() { |
| | | Taro.showLoading(); |
| | | $fetchCommon.getUserInfo(this.userId) |
| | | .then(res => { |
| | | Taro.hideLoading(); |
| | | if (!res) { |
| | | return; |
| | | } |
| | | this.userInfo = res || {}; |
| | | }); |
| | | } |
| | | |
| | | } |
| | | ``` |
| | | |
| | | |
New file |
| | |
| | | --- |
| | | description: |
| | | globs: |
| | | alwaysApply: false |
| | | --- |
| | | |
| | | # 数据控制层基类 Pilot.js |
| | | |
| | | ## 功能说明 |
| | | |
| | | Pilot 是数据控制层的基类 |
| | | - 将 Vue 对象的数据绑定、方法绑定、生命周期等功能拆分出来,进行独立申明(拆分后界面层管显示,数据控制层管数据流转) |
| | | - 增加跨页通讯、键名转换等相关的能力 |
| | | - 每个数据控制器都需要继承此类 |
| | | - 子类实例化后,再将申明的内容合并回去 |
| | | |
| | | ## 引用方法 |
| | | |
| | | ```js |
| | | import { |
| | | Pilot |
| | | } from '@components/bases/Pilot'; |
| | | ``` |
| | | |
| | | ## 主要方法 |
| | | |
| | | |
| | | ### `createOptions(dataAdd)` |
| | | **功能** |
| | | 创建页面合并对象,将实例的属性和方法映射到页面合并对象中 |
| | | |
| | | **参数** |
| | | - `dataAdd` (Object):需要添加到页面中的额外数据 |
| | | |
| | | **返回值** |
| | | - (Object):页面合并对象 |
| | | |
| | | |
| | | **注意事项** |
| | | - 如果 `dataAdd` 中包含 `assets` 属性,会自动调用 transAssets 转换其中的图片地址值 |
| | | - `$` 开头的属性会被直接映射到合并对象中,同时去掉 `$` 前缀 |
| | | - 非 `$` 开头的属性会被映射到合并对象的 `methods` 属性中 |
| | | |
| | | --- |
| | | |
| | | ### `transAssets(assets)` |
| | | **功能** |
| | | 转换静态图片引用的路径,根据运行环境(H5 或小程序)生成图片实际发布的路径 |
| | | |
| | | **参数** |
| | | - `assets` (Object):包含图片路径的对象 |
| | | |
| | | **返回值** |
| | | - (Object):转换后的图片路径对象 |
| | | |
| | | #### 静态图片地址转换说明 |
| | | |
| | | 在目前项目体系设计下,由于不同项目(公众号、小程序、混合app)图片加载机制的不同,设置了一个统一的图片地址转换入口 |
| | | 经过静态方法 transAssets 转换,可以获得图片实际发布的地址 |
| | | |
| | | **示例1** |
| | | |
| | | ```javascript |
| | | const assets = { logo: 'assets/images/logo.png' }; |
| | | const result = Pilot.transAssets(assets); // 输出转换后的图片实际发布地址 |
| | | ``` |
| | | |
| | | **示例2** |
| | | |
| | | ```HTML |
| | | <template> |
| | | <image :src="assets.homeNav1" mode="aspectFit" /> |
| | | </template> |
| | | ``` |
| | | |
| | | ```js |
| | | export default { |
| | | name: 'index', |
| | | ...new PIndex().createOptions({ |
| | | // 首页菜单图片,会全部经过 transAssets 进行路径转换,转换为图片实际发布的地址 |
| | | assets: { |
| | | homeNav1: 'assets/img/home-nav-01.png', |
| | | homeNav2: 'assets/img/home-nav-02.png', |
| | | homeNav3: 'assets/img/home-nav-03.png', |
| | | }, |
| | | }), |
| | | }; |
| | | ``` |
| | | |
| | | **注意事项** |
| | | 移动端的图片不要使用 css 背景,而是使用 image 图片元素,再填充由 transAssets 生成的实际发布地址 |
| | | |
| | | ## 页面合并流程 |
| | | |
| | | `createOptions` 是类 Pilot 的核心方法,此方法将独立申明的信息转换为合并对象,以方便原 Vue 对象进行合并 |
| | | |
| | | ### 第一步:生成合并对象 |
| | | |
| | | * 扫描当前类,以 `$` 开头的属性或方法,去掉 `$` 符后,直接作为 Vue 的属性或方法准备合并 |
| | | * 扫描当前类,非以 `$` 开头的方法,作为 Vue 对象申明中 methods 的子级方法准备合并 |
| | | * 生成合并对象,用以进行合并 |
| | | |
| | | ```js |
| | | // 数据控制器中,用 $ 开头的视为 Vue 属性或方法 |
| | | export class PIndex extends Pilot { |
| | | $data() { |
| | | return { |
| | | a: 1, |
| | | }; |
| | | } |
| | | $computed = { |
| | | a2() {}, |
| | | }; |
| | | $mounted() {} |
| | | } |
| | | |
| | | // 合并后的实际效果 |
| | | const Component = Vue.extend({ |
| | | data() { |
| | | return { |
| | | a: 1, |
| | | }; |
| | | }, |
| | | computed: { |
| | | a2() {}, |
| | | }, |
| | | mounted() {}, |
| | | }); |
| | | ``` |
| | | |
| | | ```js |
| | | // 数据控制器中,非 $ 开头的,转到 methods 中 |
| | | export class PIndex extends Pilot { |
| | | onOpenSelector() {} |
| | | } |
| | | |
| | | // 合并后的实际效果 |
| | | const Component = Vue.extend({ |
| | | methods: { |
| | | onOpenSelector() {}, |
| | | }, |
| | | }); |
| | | ``` |
| | | |
| | | 注意:不能在数据控制器中定义 $name、$components、$methods 这三项,因为实际合并时会覆盖 |
| | | |
| | | ### 第二步:实际合并 |
| | | |
| | | 数据控制层和界面层实际的合并,其实是写在界面层上 |
| | | 由界面层实例化数据控制层,并使用其基类的 createOptions 方法生成选项,再合并进原 Vue 对象 |
| | | |
| | | ```js |
| | | // 引入界面层对应数据控制器 |
| | | import { |
| | | PPageName |
| | | } from '@pilots/pilotGroup/PPageName'; |
| | | |
| | | export default { |
| | | name: 'PageName', |
| | | components: {}, |
| | | // 示例化数据控制器,由实例生成 Vue 选项,再展开合并到界面 Vue 对象上 |
| | | ...new PPageName().createOptions(), |
| | | }; |
| | | ``` |
| | | ## 页面能力扩展 |
| | | |
| | | ### 跨页面通讯 |
| | | |
| | | Taro 的跨页面通讯能力,仅小程序可用,非小城不能跨页通讯非常不方便 |
| | | 因此,使用 createOptions 创建合并对象时,给页面的 Vue 实例,增加了跨页面通讯的方法,兼容所有平台 |
| | | |
| | | **跨页发送:$poster** |
| | | |
| | | 此方法挂载到 vue 实例的 this 上 |
| | | |
| | | ```js |
| | | this.$poster(direction, action, data); |
| | | ``` |
| | | |
| | | 参数: |
| | | - `direction` (String,必填):发送去向,有两值: |
| | | - `'nextPage'`:发生给下一页(如果正在创建,会等待创建成功后再传递) |
| | | - `'prevPage'`:发送给上一页 |
| | | - `action` (String,必填):动作名称 |
| | | - `data` (any,可选):携带数据 |
| | | |
| | | 例如: |
| | | |
| | | ```js |
| | | export class PList extends Pilot { |
| | | onSaveSetting() { |
| | | // 设置保存后,通知上页 |
| | | this.$poster('prevPage', 'settingChanged'); |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | **跨页接收:$onMessage** |
| | | |
| | | 此方法的用法,类似生命周期的钩子 |
| | | |
| | | ```js |
| | | $onMessage(action, data) {} |
| | | ``` |
| | | |
| | | 例如: |
| | | |
| | | ```js |
| | | export class PIndex extends Pilot { |
| | | |
| | | $onMessage(action, data) { |
| | | // 接收消息,设置已变更 |
| | | if (action === 'settingChanged') { |
| | | // do something |
| | | } |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | ### 跨端通讯 |
| | | |
| | | 当我们进混合 APP 开发时,我们需要与 java 层进行通讯,使用 createOptions 创建合并对象时,增加了跨通讯的能力 |
| | | |
| | | (TODO:更多跨端通讯明细待续) |
| | | |
New file |
| | |
| | | --- |
| | | description: |
| | | globs: src/pilots/**/P*.js |
| | | alwaysApply: false |
| | | --- |
| | | |
| | | # 数据控制器 |