{"id":22632378,"url":"https://github.com/wotermelon/v2ex-quickapp","last_synced_at":"2025-04-11T04:13:21.325Z","repository":{"id":143798615,"uuid":"141915393","full_name":"wotermelon/v2ex-quickapp","owner":"wotermelon","description":"快应用-v2ex","archived":false,"fork":false,"pushed_at":"2018-08-02T13:23:46.000Z","size":421,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-11T04:13:18.078Z","etag":null,"topics":["javascript","quick-app"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wotermelon.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-07-22T17:11:00.000Z","updated_at":"2020-06-01T08:44:39.000Z","dependencies_parsed_at":null,"dependency_job_id":"f907e6e8-cc4e-498a-97d6-df28110b344b","html_url":"https://github.com/wotermelon/v2ex-quickapp","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wotermelon%2Fv2ex-quickapp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wotermelon%2Fv2ex-quickapp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wotermelon%2Fv2ex-quickapp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wotermelon%2Fv2ex-quickapp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wotermelon","download_url":"https://codeload.github.com/wotermelon/v2ex-quickapp/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248339225,"owners_count":21087215,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["javascript","quick-app"],"created_at":"2024-12-09T02:17:23.173Z","updated_at":"2025-04-11T04:13:21.308Z","avatar_url":"https://github.com/wotermelon.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# V2ex - 快应用\n\n## 启动\n\n```shell\n# 安装依赖\nnpm install\n# 启动并监听自动刷新\nnpm run watch\n# 开启服务器调试\nnpm run server\n```\n\n## 应用调试器\n\n  应用调试器 [下载](https://www.quickapp.cn/docCenter/post/69)\n\n  `打开调试器 --\u003e 点击\"扫码安装\"`，扫描终端窗口中的 `二维码` 即可完成配置\n\n## 安装rpk包\n\n- 1. 复制rpk包到手机中\n\n      将 `/dist` 目录下编译产出的 `rpk包` 通过USB数据线或其他方式，复制到手机文件系统中\n\n- 2. 本地安装rpk包\n      `打开调试器 --\u003e 点击\"本地安装\"`，选择手机文件系统中的rpk包，并自动唤起平台运行rpk包，查看效果\n\n\nps: 快应用调试器手机和电脑要同一网络\n\n# 快应用（Quick App）\n\n## 什么是 `快应用`\n\n\u003e 快应用也叫免安装应用，应用使用`前端技术栈`开发，`原生`渲染，同时具备H5页面和原生应用的双重优点。即点即用，享受原生应用的性能体验。\n\n优势：\n\n- 九大厂商（vivo、oppp、小米、华为、魅族、中兴、联想、努比亚、金立）支持\n- 高效链接用户，低成本助力，流量高转化，厂家丰富，强留存用户，容易生存\n- 使用前端技术栈，同样具备 HTML 5 与 Native App 的双重优势，用户使用微信小程序和快应用，也皆可以「即点即用」\n- #### 免安装，免存储，一键直达，更新直接推送\n\n## 如何开发 `快应用`\n\n\u003e ### 快应用面向所有类型开发者，提供快应用开发平台，开发工具，开发者可自行开发应用发布流程\n\n流程：\n\n![流程](./assets/process.png)\n\n### 1. 环境搭建\n\n- 安装 [Node.js](https://nodejs.org/en/) (6.0以上)\n- 安装 `hap-toolkit`\n  \u003e hap-toolkit是快应用的开发者工具，帮助开发者通过命令行工具辅助开发工作的完成，主要包括创建模板工程，升级工程，编译，调试等功能。\n\n  ```shell\n  npm install -g hap-toolkit\n  ```\n\n- 安装 [快应用调试器](./software/quickapp_debugger.apk)\n  \u003e 调试器是一个Android应用程序，调试程序。扫码安装，本地安装，在线更新，开始调试\n\n### 2. 项目初始化启动\n\n- 初始化并启动\n\n  ```shell\n  # 初始化\n  hap init \u003cProjectName\u003e\n  # 安装依赖\n  npm i\n  # 启动监听，自动编译\n  npm run watch\n  # 打包构建\n  npm run build\n  ```\n\n  ps: 其他命令可在项目根目录的 `package.json` 中的 `script` 查看\n\n  目录结构\b：\n\n  ```\n  ├── sign                      rpk包签名模块\n  │   └── debug                 调试环境\n  │       ├── certificate.pem   证书文件\n  │       └── private.pem       私钥文件\n  ├── src\n  │   ├── Common                公用的资源和组件文件\n  │   │   └── logo.png          应用图标\n  │   ├── Demo                  页面目录\n  │   |   └── index.ux          页面文件，可自定义页面名称\n  │   ├── app.ux                APP文件，可引入公共脚本，暴露公共数据和方法等\n  │   └── manifest.json         项目配置文件，配置应用图标、页面路由等\n  └── package.json              定义项目需要的各种模块及配置信息\n  ```\n\n### 3. [生命周期](https://doc.quickapp.cn/tutorial/framework/lifecycle.html)\n页面生命周期: \n\n| 生命周期 | 对应Vue的生命周期 | 描述 |\n| ---- | ---- | ---- |\n| onInit | created | `ViewModel` 的数据已经准备好\n| onReady | mounted |`ViewModel` 模板已经编译完成\n| onShow | activated | 页面被切换重新显示\n| onHide | deactivated | 页面被切换隐藏\n| onDestroy | destroyed | 页面被销毁时调用\n| onBackPress | |  当用户点击`返回实体按键`、`左上角返回菜单`、`调用返回API`时触发该事件\n| onMenuPress | | 当使用原生的顶部标题栏时\n\n应用生命周期: \n\n| 生命周期 | 描述 |\n| ---- | ---- |\n| onCreate | 当应用创建时调用\n| onDestroy | 当应用销毁时触发\n\n### 4. [样式](https://doc.quickapp.cn/tutorial/framework/page-style-and-layout.html)\n\n- 长度\n\n\u003e 框架目前仅支持长度单位 `px` 和 `%`,与传统web页面不同，px是相对于项目配置基准宽度的单位\n\n100px * 1080px = x * 750px\n\n设计稿1px / 设计稿基准宽度 = 框架样式1px / 项目配置基准宽度\n\n- 选择器\n\n  `内联样式`、`tag选择器`、`class选择器`、`id选择器`、`并列选择`、`后代选择器`\n\n- 布局-flex\n\n- 支持预编译\n\n  `less`, `sass`\n\n\n### 5. [指令](https://doc.quickapp.cn/tutorial/framework/framework-instructions.html)\n\n| 指令 | 对应Vue的指令  | 描述 |\n| ---- | ---- | ---- |\n| for | v-for | 循环输出一个数组类型的数据\n| if/elif/else | v-if/v-else-if/v-else | 是否增加或者删除组件\n| show | v-show | 是否显示组件\n\n### 6. [事件](https://doc.quickapp.cn/tutorial/framework/event-monitoring-and-triggering.html)\n\n- $on | 监听 `ViewModel` 事件\n- $off | 移除 `ViewModel` 事件\n- $emit | 触发 `ViewModel` 事件\n- \\`on${事件名}\\` | 监听原生组件事件\n- $emitElement | 触发原生组件事件\n\n| 通用事件 | 描述 |\n| ---- | ---- |\n| click | 组件被点击时触发\n| longpress | 组件被长按时触发\n| focus | 组件获得焦点时触发\n| appear | 组件出现时触发\n| disappear | 组件消失时触发\n| swipe | 组件上快速滑动后触发 |\n\nps：[通用事件](https://doc.quickapp.cn/widgets/common-events.html)\n\n### 7. [组件](https://doc.quickapp.cn/tutorial/framework/parent-child-component-communication.html)\n\n| 组件 | 对应\bVue | 描述 |\n| ---- | ---- | ---- |\n| block | template | 逻辑区块的组件，没有对应的 `Native` 组件\n| slot | slot | 组件插槽\n\npart1：\n```html\n\u003ctemplate\u003e\n  \u003cdiv\u003e\n    \u003ctext\u003e{{ header }}\u003c/text\u003e\n    \u003cslot\u003e\u003c/slot\u003e\n    \u003ctext\u003e{{ footer }}\u003c/text\u003e\n  \u003c/div\u003e\n\u003c/template\u003e\n```\npage：\n```html\n\u003cimport name=\"part1\" src=\"./part1\"\u003e\u003c/import\u003e\n\u003ctemplate\u003e\n  \u003cpart1 class=\"component\" header=\"{{header}}\" footer=\"{{footer}}\"\u003e\n    \u003ctext\u003eslot节点内容\u003c/text\u003e\n  \u003c/part1\u003e\n\u003c/template\u003e\n```\n\n### 8. [组件通信](https://doc.quickapp.cn/tutorial/framework/parent-child-component-communication.html)\n\n  #### 父子组件之间的通信\n\n- props\n  ```html\n  \u003ccomp-part1 \n    prop1=\"{{data1}}\" \n    prop2-object=\"{{data2}}\"\u003e\n  \u003c/comp-part1\u003e\n  ```\n\n- \\`on${事件名}\\` / $emit\n\n  ```html\n  \u003ccomp-part1 onevt-type3=\"evtTypeHandler\"\u003e\n  \u003c/comp-part1\u003e\n  ```\n\n  ```js\n  $emit('evtType3')\n  ```\n\n- $on / $dispatch\n\n  向上传递：子组件触发，父组件响应\n\n  当传递结束后，可以调用evt.stop()来结束传递\n\n- $broadcast / $on\n\n  向下传递：父组件触发，子组件响应\n\n  当传递结束后，可以调用evt.stop()来结束传递\n\n  #### 兄弟组件之间的通信\n\n  \u003e 传统的兄弟等非父子组件之间通信，是通过Publish/Subscribe模型来完成\n\n  子组件Sub端：part1\n\n  ```html\n  \u003cscript\u003e\n    export default {\n      processMessage (msg) {\n      },\n      /**\n       * 通过events对象：绑定事件\n       */\n      events: {\n        customEventInVm2 (evt) {\n        }\n      }\n    }\n  \u003c/script\u003e\n  ```\n\n  父组件：\n\n  ```html\n  \u003cimport name=\"comp-part2\" src=\"./part2\"\u003e\u003c/import\u003e\n  \u003cimport name=\"comp-part3\" src=\"./part3\"\u003e\u003c/import\u003e\n\n  \u003ctemplate\u003e\n    \u003cdiv class=\"tutorial-page\"\u003e\n      \u003c!-- 兄弟VM通信 --\u003e\n      \u003ccomp-part2 id=\"sibling1\"\u003e\u003c/comp-part2\u003e\n      \u003ccomp-part3 id=\"sibling2\"\u003e\u003c/comp-part3\u003e\n    \u003c/div\u003e\n  \u003c/template\u003e\n\n  \u003cstyle lang=\"less\"\u003e\n  \u003c/style\u003e\n\n  \u003cscript\u003e\n    // 父组件\n    export default {\n      onReady () {\n        this.establishRef()\n      },\n      /**\n       * 建立相互VM的引用\n       */\n      establishRef () {\n        const siblingVm1 = this.$vm('sibling1')\n        const siblingVm2 = this.$vm('sibling2')\n\n        siblingVm1.parentVm = this\n        siblingVm1.nextVm = siblingVm2\n        siblingVm2.parentVm = this\n        siblingVm2.previousVm = siblingVm1\n      }\n    }\n  \u003c/script\u003e\n  ```\n\n  子组件\bPub端：part2\n  ```html\n  \u003cscript\u003e\n    // 子组件: part3\n    export default {\n      sendMesssage () {\n        if (this.previousVm) {\n          // Way1. 调用方法\n          this.previousVm.processMessage('兄弟之间通信的消息内容')\n          // Way2. 触发事件\n          this.previousVm.$emit('customEventInVm2', '兄弟之间通信的消息内容')\n        }\n      }\n    }\n  \u003c/script\u003e\n  ```\n\n### 9. 页面路由切换、页面参数传递\n\n#### 切换页面\n\n```html\n\u003ctemplate\u003e\n  \u003cdiv class=\"tutorial-page\"\u003e\n    \u003c!-- 以'/'开头的应用内页面的路径 --\u003e\n    \u003ca href=\"/PageParams/receiveparams\"\u003e跳转到接收参数页面\u003c/a\u003e\n    \u003c!-- 以非'/'开头的应用内页面的名称 --\u003e\n    \u003ca href=\"PageParams/receiveparams\"\u003e跳转到接收参数页面\u003c/a\u003e\n    \u003c!-- 特殊的,如果uri的值是'/',则跳转到path为'/'的页,没有则跳转到首页--\u003e\n    \u003ca href=\"/\"\u003e跳转到首页\u003c/a\u003e\n  \u003c/div\u003e\n\u003c/template\u003e\n```\n\n#### 传参\n\n```html\n\u003ctemplate\u003e\n  \u003cdiv class=\"tutorial-page\"\u003e\n    \u003c!-- 添加参数 --\u003e\n    \u003ca href=\"/PageParams/receiveparams?key=Hello, world!\"\u003e携带参数key1跳转\u003c/a\u003e\n    \u003c!-- 添加变量参数 --\u003e\n    \u003ca href=\"/PageParams/receiveparams?key={{title}}\"\u003e携带参数key2跳转\u003c/a\u003e\n  \u003c/div\u003e\n\u003c/template\u003e\n\n```\n\n#### 接口router切换页面\n\n```js\n// 导入模块\nimport router from '@system.router'\n\nexport default {\n  routePagePush () {\n    // 跳转到应用内的某个页面\n    router.push({\n      uri: '/PageParams/receiveparams'\n    })\n  },\n  routePageReplace () {\n    // 跳转到应用内的某个页面，当前页面无法返回\n    router.replace({\n      uri: '/PageParams/receiveparams'\n    })\n  },\n  routePageBack () {\n    // 返回上一页面\n    router.back()\n  },\n  routePageClear () {\n    // 清空所有历史页面记录，仅保留当前页面\n    router.clear()\n  }\n}\n```\n\n#### 接口router传递参数\n\n```js\nrouter.push({\n  uri: '/PageParams/receiveparams',\n  params: { key: this.title }\n})\n```\n\n#### 页面\b接收参数\n\n```js\nexport default {\n  protected: {\n    key: ''\n  },\n  onInit () {\n    // js中输出页面传递的参数\n    console.info('key: ' + this.key)\n  }\n}\n```\n\n### 10. [script脚本](https://doc.quickapp.cn/framework/script.html)\n\n\n## 底层接口\n\n  - 界面交互\n    - 分享\n    - 弹窗\n    - 打开网页\n    - 通知消息\n    - 震动\n\n  - 网络访问\n    - 上传下载\n    - 数据请求\n\n  - 文件存储\n    - 数据存储\n    - 文件储存\n\n  - 系统能力\n    - 二维码\n    - 传感器\n    - 剪贴板\n    - 地理位置\n    - 桌面图标\n    - 日历事件\n    - 网络状态\n    - 设备信息\n    - 屏幕亮度\n    - 系统音量\n    - 电量信息\n    - 应用管理\n    - 录音\n    - 联系人\n    - 发送短信\n\n  - 安全\n    - 密码算法（rsa）\n\n  - 图形图像\n    - 多媒体\n    - 图片编辑\n\n  - 声音音频\n    - 音频\n\n  - 厂商服务\n    - 推送\n    - 支付\n    - 统计\n    - 账号\n\n  - 第三方服务\n    - 微信支付\n    - 支付宝支付\n    - 第三方分享 \n    - QQ账户\n    - 微信账户\n    - 微博账户\n\n\n\n## 调试\n\n- 日志输出\n  \u003e 打开工程根目录下的src文件夹的manifest.json，找到config配置，将logLevel修改为最低级别debug，即：允许所有级别的日志输出\n\n  ```json\n  {\n  　\"config\": {\n    　　\"logLevel\": \"debug\"\n    }\n  }\n  ```\n\n  ```js\n  console.debug('debug')\n  console.log('log')\n  console.info('info')\n  console.warn('warn')\n  console.error('error')\n  ```\n\n- 远程调试\n\n  \u003e 远程调试指的是通过 **快应用调试器**、**hap-toolkit的远程调试命令** 、**chrome devtools调试界面**，来调试手机app端的页面\n\n  ```shell\n  # 启动http调试服务器\n  npm run server\n  ```\n\n## 坑。。。\n\n- 构建\n  1. `watch` 只会监听页面变化，`manifest`、`增加图片` 不会刷新\n\n- 样式\n  1. 底层转换，复杂样式无法实现\n\n- 语法\n  1. \b需要手动\b配置支持相关高级语法\n\n- 组件\n\n  1. 通信：`vue` 的老一套套路（`$dispatch`, `$broadcast`），组件嵌套复杂通信困难麻烦\n  2. 系统组件库功能\b部分功能设计不好\n\n- 页面路由切换\n  1. params参数的每个字段值都会被序列化成字符串\n  2. 页面返回回传参数简直无法理解\n\n- 调试\b\n  1. 对写惯前端热加载来说，发狂，调试器断连、崩溃问题\n  2. 调试模式模拟 `chrome devtool`，界面模拟，功能没有！\n  3. 控制台 `console` 不会显示 `object` 详情\n  4. 此处应该要有个ide...\n\n- 莫名其妙出现莫名其妙的报错。。。\n\n\b相关链接：\n\n- [快应用官网](https://www.quickapp.cn/)\n- [开发文档](https://doc.quickapp.cn/)\n- [awesome-quickapp](https://github.com/quickappdev/awesome-quickapp)\n- [v2ex-quickapp](https://github.com/wotermelon/v2ex-quickapp)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwotermelon%2Fv2ex-quickapp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwotermelon%2Fv2ex-quickapp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwotermelon%2Fv2ex-quickapp/lists"}