From dda26e1f5111bb9f875271bb4524714483dfe31b Mon Sep 17 00:00:00 2001 From: Tevin <tingquanren@163.com> Date: Tue, 18 Mar 2025 12:14:11 +0800 Subject: [PATCH] 知识库文档调整,删除旧文档 --- /dev/null | 7 --- _cursor.ai/rules/type-component.mdc | 57 ++++++++++++++++++++++++++++ _cursor.ai/文档说明.md | 3 - _cursor.ai/common.doc/Tools.doc.md | 0 4 files changed, 58 insertions(+), 9 deletions(-) diff --git "a/_cursor.ai/101-\345\267\245\347\250\213\344\273\213\347\273\215.md" "b/_cursor.ai/101-\345\267\245\347\250\213\344\273\213\347\273\215.md" deleted file mode 100644 index f1987f3..0000000 --- "a/_cursor.ai/101-\345\267\245\347\250\213\344\273\213\347\273\215.md" +++ /dev/null @@ -1,299 +0,0 @@ -# 工程介绍 - -- [工程介绍](#工程介绍) - - [工程介绍](#工程介绍-1) - - [技术栈](#技术栈) - - [工程目录结构](#工程目录结构) - - [短路径映射](#短路径映射) - - [页面构成](#页面构成) - - [界面层和数据控制层的拆分](#界面层和数据控制层的拆分) - - [新页面模板](#新页面模板) - - [界面层空白模板](#界面层空白模板) - - [H5 空白界面模板](#h5-空白界面模板) - - [小程序空白界面模板](#小程序空白界面模板) - - [空白样式文件模板](#空白样式文件模板) - - [数据控制层空白模板](#数据控制层空白模板) - - [数据控制器空白模板](#数据控制器空白模板) - - [请求集空白模板](#请求集空白模板) - -## 工程介绍 - -这是一套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(数据控制器) - -### 短路径映射 - -工程资源引用时,通常使用更短的引用路径: - -* `@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 实例部分功能的一种转写,类似于语法糖 - -**数据控制层写法** - -例如: - -```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() {}, -}); -``` - -更多细节,请参照《数据控制层基类Pilot》 - -## 新页面模板 - -新建页面时,页面初始内容,可参考如下空白模板 - -### 界面层空白模板 - -#### H5 空白界面模板 - -H5 界面需要 CPage、CContent、CNavBar 这三个基础页面组件 - -```html -/** -* pageName - 页面名称 -* @author 作者 -*/ - -<template> - <CPage> - <CNavBar title="页面名称" /> - <CContent class="page-name"> - <!-- 页面内容 --> - </CContent> - </CPage> -</template> - -<script> - import Taro from '@tarojs/taro'; - import {} from 'taro-ui-vue'; - import { - PPageName - } from '@pilots/pilotGroup/PPageName'; - import { - CPage, - CContent, - CNavBar - } from '@components/layout/h5Page'; - import './pageName.scss'; - - export default { - name: 'PageName', - components: {}, - ...new PPageName().createOptions(), - }; -</script> -``` - -#### 小程序空白界面模板 - -```html -/** -* pageName - 页面名称 -* @author 作者 -*/ - -<template> - <view class="page-name"> - <!-- 页面内容 --> - </view> -</template> - -<script> - import Taro from '@tarojs/taro'; - import {} from 'taro-ui-vue'; - import { - PPageName - } from '@pilots/pilotGroup/PPageName'; - import './pageName.scss'; - - export default { - name: 'PageName', - components: {}, - ...new PPageName().createOptions(), - }; -</script> -``` - -#### 空白样式文件模板 - -```css -/** - * pageName - 页面名称 - * @author 作者 - */ - -@import "../../../components/common/sassMixin"; - -.page-name {} -``` - -### 数据控制层空白模板 - -#### 数据控制器空白模板 - -```js -/** - * PPageName - 页面名称 - * @author 作者 - */ - -import Taro from '@tarojs/taro'; -import { - Pilot -} from '@components/bases/Pilot'; -import { - $fetchCommon -} from '@fetchers/FCommon'; - -export class PPageName extends Pilot { - - $data() { - return {}; - } - - $mounted() { - this.onLoadDataResource(); - } - - // 加载用户详情 - onLoadDataResource() { - Taro.showLoading(); - $fetchCommon.getPageDetail() - .then(res => { - Taro.hideLoading(); - if (!res) { - return; - } - // do something - }); - } - -} -``` - -说明:请求异常由请求层的基类自动处理,数据控制层跳过错误的逻辑,只处理请求成功的后续业务 - -#### 请求集空白模板 - -```js -/** - * FCommon - 公用请求集 - * @author 作者 - */ - -import { - Fetcher -} from '@components/bases/Fetcher'; - -class FCommon extends Fetcher { - - constructor() { - super({ - // url前缀(本地路径, 服务器路径) - urlPrefix: ['/api/common/', '/serverPath/'], - }); - } - - // 读取页面详情 - getPageDetail() { - const url = this.spellURL('getPageDetail', 'page/Detail'); - const send = {}; - return this.post(url, send); - } - -} - -export const $fetchCommon = new FCommon(); -``` diff --git "a/_cursor.ai/102-\345\274\200\345\217\221\350\247\204\350\214\203.md" "b/_cursor.ai/102-\345\274\200\345\217\221\350\247\204\350\214\203.md" deleted file mode 100644 index c73d973..0000000 --- "a/_cursor.ai/102-\345\274\200\345\217\221\350\247\204\350\214\203.md" +++ /dev/null @@ -1,370 +0,0 @@ -# 开发规范 - -- [开发规范](#开发规范) - - [规范宗旨](#规范宗旨) - - [命名问题](#命名问题) - - [命名需要具有实义](#命名需要具有实义) - - [文件命名](#文件命名) - - [界面层文件](#界面层文件) - - [数据控制层文件](#数据控制层文件) - - [组件文件](#组件文件) - - [请求文件](#请求文件) - - [样式命名](#样式命名) - - [界面样式](#界面样式) - - [组件样式](#组件样式) - - [JS 变量和属性的命名](#js-变量和属性的命名) - - [变量命名的特别约定](#变量命名的特别约定) - - [JS 方法的命名](#js-方法的命名) - - [在数据控制层](#在数据控制层) - - [在组件内](#在组件内) - - [书写问题](#书写问题) - - [JS 中的书写](#js-中的书写) - - [变量定义符](#变量定义符) - - [模版中的函数调用](#模版中的函数调用) - - [CSS 属性顺序](#css-属性顺序) - -## 规范宗旨 - -**代码首先是给人读的,其次才是给机器运行**,所以让代码容易阅读是应尽的责任 - -除了尽可能不写难懂的代码外,我们还需要尽量遵守统一的规范,来帮助我们更高效率的相互阅读代码 - -## 命名问题 - -### 命名需要具有实义 - -命名的核心原则是名称含有具体的实体含义 - -比如没有实义的 - -```js -const onClick = () => null; // 不好的命名 -``` - -因为 `click` 可以发生在任何元素上,从这个名称上无法分辨业务种类,所以我们认为这个函数名没有实义,需要改进一下: - -```js -const onProductSelected = () => null; // 良好的命名 -``` - -改进后,从函数名一看便知,这是商品被选中了以后的需要进行的操作,又因为具备了在同一个页面的唯一性,能帮我们快速获取信息,知道这是哪个业务的哪个环节,大幅提高阅读效率,这就是实义 - -### 文件命名 - -常用文件命名约定 - -#### 界面层文件 - -界面层文件(.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(); -``` - -### 样式命名 - -样式名的命名,采用横杠连接 - -```css -.page-name {} -``` - -#### 界面样式 - -任何一个界面必定包含众多样式,所以: - -* 最父级样式名固定,与界面名称一直 -* 中间层,需要以父级为前缀,接板块说明 -* 末端则可单名,且尽量不含实义 - -```css -/** 在界面 userList.vue 中,最父级样式名名称固定 **/ -.user-list { - - /** 中间多层,以父级为前缀 **/ - .user-list-title { - - /** 末端可单名,尽量非实义 **/ - .left, - .text, - .icon, - .sub, - .close {} - } -} -``` - -#### 组件样式 - -组件样式名必须已 `c-` 开头,最父级样式名必须与组件名挂钩 - -例如,组件 CMenu.vue 中,最父级样式名必须是: - -```css -.c-menu {} -``` - -### JS 变量和属性的命名 - -使用小驼峰,注意不能以动词开头 - -```js -// 变量 -const name = ''; -const orderList = ''; -// 属性 -const user = { - name: '', - lastOrder: '', -}; -``` - -#### 变量命名的特别约定 - -**变量名允许 is 开头** -变量名不能用动词开头,但是允许 is 作为特例 - -```js -// 允许 is 开头的变量名 -let isOpened = 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() -} -``` - -## 书写问题 - -书写规则都由编辑器自动格式化即可,这里主要说明非格式化的几点约定 - -### 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` - -#### 模版中的函数调用 - -模版中调用函数,必须显式的书写 evt 变量和箭头函数,即: `evt => fncName()` -我们把 Taro 自身组件视为普通元素,元素绑定事件使用 `@tap` 的方式,非元素皆是组件,组件使用 `:onClick` 的方式绑定 - -例如: -```html -<view @tap="() => onOpenOrderDetail()"></view> -<CMenu :onItemClick="evt => onMenuItemClick(evt)" /> -``` - -### 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 等 diff --git "a/_cursor.ai/201-\350\257\267\346\261\202\345\261\202\345\237\272\347\261\273Fetcher.md" "b/_cursor.ai/201-\350\257\267\346\261\202\345\261\202\345\237\272\347\261\273Fetcher.md" deleted file mode 100644 index 5166145..0000000 --- "a/_cursor.ai/201-\350\257\267\346\261\202\345\261\202\345\237\272\347\261\273Fetcher.md" +++ /dev/null @@ -1,324 +0,0 @@ -# 请求层基类 Fetcher.js - -- [请求层基类 Fetcher.js](#请求层基类-fetcherjs) - - [功能说明](#功能说明) - - [引用方法](#引用方法) - - [构造函数](#构造函数) - - [主要方法](#主要方法) - - [`spellURL(devSuffix, serSuffix)`](#spellurldevsuffix-sersuffix) - - [`get(url, data, options)`](#geturl-data-options) - - [`post(url, data, options)`](#posturl-data-options) - - [`query(type, url, data, options)`](#querytype-url-data-options) - - [`stringToCamel(str)`](#stringtocamelstr) - - [`stringToUnderline(str)`](#stringtounderlinestr) - - [`transKeyName(type, json)`](#transkeynametype-json) - - [请求的 options 配置](#请求的-options-配置) - - [`hostType` 主机类型](#hosttype-主机类型) - - [`silence` 静音请求](#silence-静音请求) - - [响应处理](#响应处理) - - [处理流程](#处理流程) - - [前端统一响应数据格式](#前端统一响应数据格式) - - [前端统一响应状态码](#前端统一响应状态码) - - [请求调用](#请求调用) - -## 功能说明 - -类 Fetcher 是一个用于处理 HTTP 请求的基类,包含了URL拼接、响应数据适配、报错提示等多种方法来简化和统一请求的处理 -请求层的每个请求集,都必须继承此类 - -## 引用方法 - -```js -import { - Fetcher -} from '@components/bases/Fetcher'; -``` - -## 构造函数 - -构造函数接受一个配置对象 options 作为参数,包含如下属性: -* **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' } - } -} -``` - -**注意事项** -- 支持嵌套对象的递归转换 - -## 请求的 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 || {}; - }); - } - -} -``` diff --git "a/_cursor.ai/202-\346\225\260\346\215\256\346\216\247\345\210\266\345\261\202\345\237\272\347\261\273Pilot.md" "b/_cursor.ai/202-\346\225\260\346\215\256\346\216\247\345\210\266\345\261\202\345\237\272\347\261\273Pilot.md" deleted file mode 100644 index 63bfadb..0000000 --- "a/_cursor.ai/202-\346\225\260\346\215\256\346\216\247\345\210\266\345\261\202\345\237\272\347\261\273Pilot.md" +++ /dev/null @@ -1,233 +0,0 @@ -# 数据控制层基类 Pilot.js - -- [数据控制层基类 Pilot.js](#数据控制层基类-pilotjs) - - [功能说明](#功能说明) - - [引用方法](#引用方法) - - [主要方法](#主要方法) - - [`createOptions(dataAdd)`](#createoptionsdataadd) - - [`transAssets(assets)`](#transassetsassets) - - [静态图片地址转换说明](#静态图片地址转换说明) - - [页面合并流程](#页面合并流程) - - [第一步:生成合并对象](#第一步生成合并对象) - - [第二步:实际合并](#第二步实际合并) - - [页面能力扩展](#页面能力扩展) - - [跨页面通讯](#跨页面通讯) - - [跨端通讯](#跨端通讯) - -## 功能说明 - -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:更多跨端通讯明细待续) - diff --git "a/_cursor.ai/301-\345\205\254\345\205\261\350\241\250\345\215\225\347\273\204\344\273\266.md" "b/_cursor.ai/301-\345\205\254\345\205\261\350\241\250\345\215\225\347\273\204\344\273\266.md" deleted file mode 100644 index b040b7e..0000000 --- "a/_cursor.ai/301-\345\205\254\345\205\261\350\241\250\345\215\225\347\273\204\344\273\266.md" +++ /dev/null @@ -1,46 +0,0 @@ -# 公共表单组件 - -- [公共表单组件](#公共表单组件) - - [组件列表](#组件列表) - - [表单容器组件](#表单容器组件) - - [基础输入组件](#基础输入组件) - - [选择组件](#选择组件) - - [开关组件](#开关组件) - - [数值组件](#数值组件) - - [表单项验证规则](#表单项验证规则) - - [完整表单示例](#完整表单示例) - -移动端表单组件库 - -## 组件列表 - -### 表单容器组件 -- [CForm 表单组件](./forms/CForm.md) -- [CFormItem 表单项组件](./forms/CFormItem.md) -- [CFormSubmit 表单提交按钮组件](./forms/CFormSubmit.md) -- [CFormAgreement 表单协议组件](./forms/CFormAgreement.md) - -### 基础输入组件 -- [CInput 文本输入框组件](./forms/CInput.md) -- [CInputPhoneCode 手机验证码输入框组件](./forms/CInputPhoneCode.md) -- [CInputScanCode 扫码输入框组件](./forms/CInputScanCode.md) -- [CInputExpressCode 快递单号输入框组件](./forms/CInputExpressCode.md) -- [CTextArea 多行文本输入组件](./forms/CTextArea.md) - -### 选择组件 -- [CSelect 下拉选择组件](./forms/CSelect.md) -- [CJumpSelect 跳转选择组件](./forms/CJumpSelect.md) -- [CCheckBox 复选框组件](./forms/CCheckBox.md) -- [CDatePicker 日期选择组件](./forms/CDatePicker.md) - -### 开关组件 -- [CSwitch 开关组件](./forms/CSwitch.md) -- [CSwitchRadio 开关式单选组件](./forms/CSwitchRadio.md) - -### 数值组件 -- [CNumberStep 数字步进器组件](./forms/CNumberStep.md) -- [CNumberValve 数值滑块组件](./forms/CNumberValve.md) - -## 表单项验证规则 - -## 完整表单示例 \ No newline at end of file diff --git "a/_cursor.ai/210-\345\205\254\345\205\261\345\267\245\345\205\267\347\256\261Tools.md" b/_cursor.ai/common.doc/Tools.doc.md similarity index 100% rename from "_cursor.ai/210-\345\205\254\345\205\261\345\267\245\345\205\267\347\256\261Tools.md" rename to _cursor.ai/common.doc/Tools.doc.md diff --git "a/_cursor.ai/prompts/\346\233\264\346\226\260\345\205\254\345\205\261\347\273\204\344\273\266\347\232\204\346\226\207\346\241\243.prompts.md" "b/_cursor.ai/prompts/\346\233\264\346\226\260\345\205\254\345\205\261\347\273\204\344\273\266\347\232\204\346\226\207\346\241\243.prompts.md" deleted file mode 100644 index 02c7293..0000000 --- "a/_cursor.ai/prompts/\346\233\264\346\226\260\345\205\254\345\205\261\347\273\204\344\273\266\347\232\204\346\226\207\346\241\243.prompts.md" +++ /dev/null @@ -1,16 +0,0 @@ -# 更新公共组件的文档 - -## 第一步,对比 -请检查项目公共组件目录的所有组件,然后检查公共组件文档目录下 - -### 文件位置 -公共组件有三个目录 -- src/components/forms -- src/components/layout -- src/components/plugins - -公共组件文档有三个目录 -- src/components/forms.doc -- src/components/layout.doc -- src/components/plugins.doc - diff --git a/_cursor.ai/rules/type-component-child.mdc b/_cursor.ai/rules/type-component-child.mdc deleted file mode 100644 index 2c314e7..0000000 --- a/_cursor.ai/rules/type-component-child.mdc +++ /dev/null @@ -1,7 +0,0 @@ ---- -description: -globs: src/pages/**/**/cmpt/*.vue -alwaysApply: false ---- - -# 界面子组件 diff --git a/_cursor.ai/rules/type-component-pub.mdc b/_cursor.ai/rules/type-component-pub.mdc deleted file mode 100644 index b9f23bf..0000000 --- a/_cursor.ai/rules/type-component-pub.mdc +++ /dev/null @@ -1,7 +0,0 @@ ---- -description: -globs: src/components/**/**/*.vue -alwaysApply: false ---- - -# 公共组件 \ No newline at end of file diff --git a/_cursor.ai/rules/type-component.mdc b/_cursor.ai/rules/type-component.mdc new file mode 100644 index 0000000..8d4918b --- /dev/null +++ b/_cursor.ai/rules/type-component.mdc @@ -0,0 +1,57 @@ +--- +description: +globs: src/pages/**/**/cmpt/*.vue,src/components/**/**/*.vue +alwaysApply: false +--- + +# 界面子组件&公共组件 + +界面子组件与公共组件,就是一个普通 Vue 组件 + +## 子组件空白模板 + +```html +/** + * CExample - 示范组件 + * @author Tevin + */ + +<template> + <view class="c-example"> + <!-- 组件内容 --> + <AtButton + type="primary" + size="small" + :onClick="evt => handleOpen()" + >示例按钮</AtButton> + </view> +</template> + +<script> +import Taro from '@tarojs/taro'; +import { AtButton } from 'taro-ui-vue'; +import './cExample.scss'; + +export default { + name: 'CExample', + components: { + AtButton, + }, + props: { + onOpened: Function, + }, + data() { + return { + }; + }, + computed: { + }, + methods: { + handleOpen() { + this.onOpened(); + } + }, + mounted() {}, +}; +</script> +``` diff --git "a/_cursor.ai/\346\226\207\346\241\243\350\257\264\346\230\216.md" "b/_cursor.ai/\346\226\207\346\241\243\350\257\264\346\230\216.md" index d509456..84ef597 100644 --- "a/_cursor.ai/\346\226\207\346\241\243\350\257\264\346\230\216.md" +++ "b/_cursor.ai/\346\226\207\346\241\243\350\257\264\346\230\216.md" @@ -19,8 +19,7 @@ - [请求集](/src/components/_cursor.ai/rules/type-fetchers.mdc) - [数据控制器](/src/components/_cursor.ai/rules/type-pilot.mdc) - [界面](/src/components/_cursor.ai/rules/type-surface.mdc) -- [子组件](/src/components/_cursor.ai/rules/type-component-child.mdc) -- [公共组件](/src/components/_cursor.ai/rules/type-component-pub.mdc) +- [子组件&公共组件](/src/components/_cursor.ai/rules/type-component.mdc) ### 规则类型:自主决定 `Agent-Requested` -- Gitblit v1.9.1