1 小程序

1.1 [0]环境:app

01.常用信息1
    a.官方:JS基础模版
        a.生成package.json文件
            npm init -y
        b.安装依赖
            npm install @vant/weapp dayjs decimal.js lodash qs ramda validator weapp-qrcode --save
    b.官方:TS基础模版
        a.生成package.json文件
            npm init -y
        b.安装依赖
            npm install @vant/weapp dayjs decimal.js lodash-es qs ramda validator weapp-qrcode --save

02.常用信息2
    a.mini
        a.默认,只能npm编译
            微信开发者工具 -> 工具 -> 构建npm
            -------------------------------------------------------------------------------------------------
            默认生成 miniprogram_npm 文件夹
        b.ts编译,则需要开启预处理
            报错:
            VM1238:1 /bin/sh: npm: command not found
            -------------------------------------------------------------------------------------------------
            解决:
            详情 => 本地设置 => 编译/预览/上传前,预处理
            source $HOME/.bash_profile;npm run tsc
            source $HOME/.bashrc;npm run tsc
            source $HOME/.zshrc;npm run tsc
    b.http请求
        a.方案
            方案                 可行性    说明
            使用官方 wx.request   可行     小程序原生 API,稳定、无需额外依赖
            封装 wx.request      可行      统一请求、错误处理,可实现拦截器等功能
            引入适配版 axios      可行      如 axios-for-mpweixin、axios-miniprogram-adapter,保留语法习惯
            直接用 [email protected]  不可行     缺少浏览器环境,无法运行
        b.最终选型
            封装 wx.request

03.常用信息3
    a.分包:subpack
        a.限制
            1.主包:包含小程序的启动页、TabBar 页面以及所有分包都需要用到的公共资源和代码    单个分包(或主包)大小不得超过 2MB
            2.分包:根据功能模块拆分出来的代码包,每个分包可以包含多个页面和相关资源         所有分包及主包的总大小不能超过 20MB(限制随微信调整)
        b.分包的加载机制
            主包会在小程序启动时加载
            分包在用户访问到分包内的页面时才会被下载
            同一个分包内的页面共享该分包的资源
        c.独立分包
            可以独立于主包运行的分包
            不需要下载主包即可运行
            适合作为小程序的入口页面,进一步提升启动速度
    b.默认,相对路径
        a.说明
            在微信小程序中,默认不支持直接使用绝对路径引入文件,
            但可以通过配置 app.json 中的 usingComponents 和 resolveAlias(小程序基础库 2.24.0 及以上支持)来实现类似绝对路径的引入效果。
        b.最终效果:app.json
            "resolveAlias": {
              "@assets/*": "/assets/*",
              "@components/*": "/components/*",
              "@modules/*": "/modules/*",
              "@system/*": "/system/*",
              "@utils/*": "/utils/*",
              "@/*": "/*"
            }

04.常用信息4
    a.常见选项
        a.方法1: 开发者工具设置(推荐)
            打开微信开发者工具
            点击右上角 "详情" 按钮
            在左侧选择 "本地设置"
            勾选以下两个选项:
            "不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书"
            "不校验请求域名、TLS 版本以及 HTTPS 证书"
        b.方法2: 配置完成后测试
            重新打开页面,现在应该会看到:
            控制台显示开发环境配置提示
            不再出现域名白名单错误
            自动登录功能正常工作
        c.设置代理
            打开微信开发者工具的 设置 -> 代理。
            检查你是否配置了“手动设置代理”。如果是,请确认代理设置是否正确。
    b.构建app.json
        a.说明
            自动分包扫描系统:系统会自动扫描 pages/ 目录下的所有子目录(除了 app 主包)
            页面有效性检查:每个页面必须包含三个必需文件:index.js、index.wxml、index.json
            分包自动命名:使用 {目录名}-apps 格式命名分包
            问题是:我们需要重新构建 app.json 才能让新页面生效!
        b.根据文档,修改后需要运行构建命令
            # 重新构建 app.json
            npm run build:app-json
            # 或直接运行构建脚本
            node system/app.js --build
    c.校验规则
        a.规则
            ESLint - 代码质量检查
            Prettier - 代码格式化
            TypeScript - 类型检查
            Stylelint - CSS/SCSS 代码规范
        b.重载
            现在请重新加载 VSCode 窗口(Cmd+Shift+P -> "Reload Window")让所有设置生效。

1.2 [1]引擎:skyline

00.汇总
    底层就是flutter

01.发展
    a.说明1
        随着微信小程序的不断发展,用户对小程序的性能和体验要求也越来越高。
        为了满足这些需求,官方推出了 Skyline 渲染引擎,为小程序带来了更流畅的渲染效果、更高的性能表现和更好的开发者体验。
    b.说明2
        Skyline 具体支持版本如下
        正式稳定版:微信小程序基础库 3.0.0+(2023年7月)
    c.说明3
        最低适配要求
        微信安卓:8.0.33+(对应基础库为 2.30.4+)
        微信 iOS:8.0.34+(对应基础库为 2.31.1+)
        开发者工具:Stable 1.06.2307260+(建议使用 Nightly 最新版)

02.Skyline渲染引擎
    a.什么是 Skyline 渲染引擎
        微信小程序 Skyline 渲染引擎是微信团队推出的新一代渲染架构,旨在解决传统 WebView 渲染模式下的性能瓶颈。
        与传统的 WebView 渲染引擎相比,Skyline 渲染引擎在渲染速度、内存占用和动画效果等方面都有显著的提升。
    b.为什么要推出 Skyline 渲染引擎
        小程序运行环境分成渲染层和逻辑层,由2个线程管理:
        渲染层的界面使用了WebView线程进行渲染,其中 WXML 模板和 WXSS 样式工作在渲染层;
        逻辑层采用JSCore线程运行JS脚本;
        -----------------------------------------------------------------------------------------------------
        一个小程序存在多个界面,所以渲染层存在多个WebView线程,这两个线程的通信会经由微信客户端做中转,逻辑层发送网络请求也经由Native转发。
    c.当小程序基于 WebView 环境下时存在问题
        WebView 的 JS 逻辑、DOM 树创建、CSS 解析、样式计算、Layout、Paint (Composite) 都发生在同一线程,在 WebView 上执行过多的 JS 逻辑可能阻塞渲染,导致界面卡顿;
        每个页面都需要实例化一个 JS 引擎(WebView),导致内存占用多,影响应用性能,因此小程序对打开的页面数量有限制(页面栈最多10个);
        页面之间共享资源,需要使用Native进行通信,就会消耗更多性能;

03.Skyline 渲染引擎架构
    a.说明
        在 Skyline 环境下,Skyline 创建了一条渲染线程来负责 Layout、 Composite 和 Paint 等渲染任务,
        并在 AppService 中划出一个独立的上下文,来运行之前 WebView 承担的 JS 逻辑、DOM 树创建等逻辑。
    b.核心线程职责
        AppService 线程:负责逻辑层与视图层的“协调中枢”,确定需更新内容及更新方式
        渲染线程:负责将业务逻辑转化为界面更新,提升渲染性能
        Raster 线程:负责“最终像素生成”,通过分块、缓存和 GPU 加速,提升页面渲染速度和流畅度
    c.整个过程三个线程是怎么协作的?
        举个真实开发场景:用户点击按钮,触发setData修改文字颜色,页面更新。
        用户点击按钮 → 渲染线程捕获触摸事件 → 包装成事件数据(“点击了 id=btn 的按钮”) → 传给 AppService 线程。
        AppService 线程执行onTap回调 → 调用setData({ color: 'red' }) → 修改虚拟节点树的样式属性 → 通知渲染线程 “有样式变更”。
        渲染线程收到通知 → 重新计算受影响节点的样式(文字颜色变红) → 重新布局(尺寸不变) → 生成新的绘制指令(“文字层颜色改为红色”) → 传给 Raster 线程。
        Raster 线程光栅化新的文字层 → 返回位图 → 渲染线程合成新画面 → 屏幕显示更新后的文字。

04.新特性
    a.自定义路由
        小程序采用多 WebView 架构,页面间跳转形式十分单一,仅能从右到左进行动画。
        而原生 App 的动画形式则多种多样,如从底部弹起,页面下沉,半屏等。
        -----------------------------------------------------------------------------------------------------
        Skyline 渲染引擎下,页面有两种渲染模式: WebView 和 Skyline,它们通过页面配置中的 renderer 字段进行区分。
        在连续的 Skyline 页面间跳转时,可实现自定义路由效果。
        -----------------------------------------------------------------------------------------------------
        仅需在路由跳转时,指定对应的 routeType
        // 基础库预设了一批常见的路由动画效果:
        wx://bottom-sheet 半屏弹窗
        wx://upwards 向上进入
        wx://zoom 放大进入

        wx.navigateTo({
          url: 'xxx',
          routeType: 'wx://modal'
        })
    b.截图组件 snapshot
        支持将其子节点的渲染结果导出成图片,如分享海报功能
        多数小程序用 canvas 做自定义分享图,不仅需手动写绘图指令,布局复杂或做长图时还受尺寸限制,成本很高。
        而 Skyline 凭借渲染可控性,可直接对 WXML 子树截图,官方提供的截图组件能复用 WXSS 能力,大幅降低开发成本。
    c.长列表按需渲染 scroll-view
        长列表是一个常用的但又经常遇到性能瓶颈的场景,WebView 下的 scroll-view 组件,
        在快速滑动时容易出现白屏和渲染卡顿。对于长列表的优化,通常离不开按需渲染,即理想状态下仅渲染在屏可视区域节点,超出可视区域的节点及时进行回收。
    d.瀑布流组件 grid-view
        瀑布流是一种常用的列表布局方式,得益于 Skyline 在布局过程中的可控性,官方直接在底层实现并提供出来,渲染性能要比 WebView 更优。

05.总结
    a.核心优势
        多线程架构:渲染与逻辑线程分离,解决传统 WebView 单线程卡顿问题
        性能提升:多页面共享引擎节省内存(无页面栈限制),减少数据通信开销,setData 延迟更低,内存占用减少约 30%
        原生交互体验:支持复杂手势、吸顶布局、自定义路由动画等类原生效果,优化 scroll-view、瀑布流等高频场景渲染效率
        渐进式适配:现有代码可通过简单配置启用,无需重写逻辑
    b.使用建议
        若项目侧重动画、交互或复杂布局,追求高性能且面向高版本用户,优先用 Skyline
        需兼容老版本、快速上线或页面结构复杂时,可继续用 WebView 或混合适配
        Skyline 性能优势明显,生态也随着持续迭代不断成熟,建议按需评估场景,关注官方最新进展以更好地发挥其能力

1.3 [1]分包:subpack

01.设计说明
    a.说明
        在微信小程序中,subpackages(分包加载)是一种优化小程序加载性能的机制。
        它允许你将小程序的代码和资源拆分成多个包,实现按需加载,从而减小主包体积,提升小程序的启动速度。
    b.核心概念
        1.主包:包含小程序的启动页、TabBar 页面以及所有分包都需要用到的公共资源和代码    单个分包(或主包)大小不得超过 2MB
        2.分包:根据功能模块拆分出来的代码包,每个分包可以包含多个页面和相关资源         所有分包及主包的总大小不能超过 20MB(限制随微信调整)
    c.为什么使用分包
        小程序有体积限制(主包大小不超过 2MB,整体所有包不超过 20MB)
        减少初始加载时间,提升用户体验
        按功能模块隔离代码,便于团队协作和维护
        将代码和资源分成多个包,每个包被独立管理和打包,访问时再按需下载对应包资源
    d.优势体现
        提高首次启动速度
        降低整体加载流量消耗
        减少运行时内存占用,提高性能

02.如何配置分包
    a.分包的目录结构
        ├── app.js
        ├── app.json
        ├── app.wxss
        ├── pages                // 主包页面
        │   ├── index
        │   └── logs
        ├── packageA             // 分包A
        │   └── pages
        │       ├── cat
        │       └── dog
        └── packageB             // 分包B
            └── pages
                └── apple
    b.app.json配置subpackages
        {
          "pages": [
            "pages/index/index",    // 主包页面
            "pages/logs/logs"       // 主包页面
          ],
          "subpackages": [
            {
              "root": "packageA",   // 分包根目录
              "name": "packA",      // 分包别名(可选)
              "pages": [
                "pages/cat/cat",    // 分包页面路径,相对于 root
                "pages/dog/dog"
              ],
              "independent": false  // 是否为独立分包(可选,默认false)
            },
            {
              "root": "packageB",
              "pages": [
                "pages/apple/apple"
              ]
            }
          ]
        }
    c.分包的加载机制
        主包会在小程序启动时加载
        分包在用户访问到分包内的页面时才会被下载
        同一个分包内的页面共享该分包的资源
    d.独立分包
        可以独立于主包运行的分包
        不需要下载主包即可运行
        适合作为小程序的入口页面,进一步提升启动速度

1.4 [1]编译:typescript

01.常用信息1
    a.原生支持TypeScript
        a.说明1
            小程序代码包要求代码文件为 wxml / wxss / js / json / wxs。
            如果我们希望使用 TypeScript 或 less 去开发小程序,
            就需要将 ts 文件或 less 文件编译成对应的 js 文件 或 wxss 文件,这个编译过程以前是需要开发者在工具外自行配置。
            从开发者工具 1.05.2109101 以上开始,我们优化工具内置的编译模块,支持以编译插件的形式,扩展编译功能。
        b.说明2
            使用这种方式有两个好处:
            项目内只需要创建 ts 文件即可,无需再生成同名的 js 文件。less 文件同理。
            编译流程由开发者工具控制,按需编译,开发体验更好。
        c.说明3
            详情 => 本地设置 => 编译/预览/上传前,预处理
            npm run tsc                                                                --win10
            source $HOME/.bash_profile;npm run tsc                                     --bash_profile
            source $HOME/.bashrc;npm run tsc                                           --bashrc
            source $HOME/.zshrc;npm run tsc                                            --zshrc
    b.开始使用
        a.旧项目
            在 project.config.json 文件中,修改 setting 下的 useCompilerPlugins 字段为 ["typescript"],即可开启工具内置的 typescript 编译插件。
            如需同时开启 less 编译插件,可将该字段修改为 ["typescript", "less"],目前支持三个编译插件:typescript、less、sass
        b.新建项目
            可在创建小程序项目时,选择对应的语言模板。 目前支持的语言模板有
            TypeScript
            TypeScript + Less
            TypeScript + Sass
        c.TS声明文件更新
            从 开发者工具 1.05.2203032 以上开始,如果是从上述的模板创建的TS项目,遇到小程序相关类型声明过时的情况,可以手动更新。
            具体步骤是在编辑器目录树上,找到 typings/types/wx 目录,右键,点击「更新声明文件」即可

02.常用信息2
    a.问题
        a.描述
            状态:你删除 pages/index/index.js 后,运行时缺少可执行 JS。
            当前微信开发者工具未把 .ts 自动编译成 .js,所以页面报错。util.js 的 @deprecated 只是提示,不影响运行。
        b.修复1:让 tsc 产出 .js 到源目录,保证任何环境都能跑
            a.修改 libra-wx/tsconfig.json(仅关键项)
                "outDir": "./"
                "include": [".//.ts"]
                "exclude": ["node_modules","miniprogram_npm"]
                可再加:"declaration": false, "sourceMap": false
            b.在 libra-wx/package.json 增加脚本
                "build": "tsc --pretty false -p tsconfig.json"
                "watch": "tsc -w -p tsconfig.json"
            c.执行构建
                cd /Volumes/Samsung/software_xare/libra-boot-test/libra-wx
                npm run build
                结果:自动生成 pages/index/index.js、app.js 等,页面恢复正常。
        c.修复2:使用微信开发者工具内置 TS 编译(不产出 .js 文件)
            a.打开微信开发者工具 → 详情 → 本地设置:
                勾选:使用 npm 模块、增强编译
                开启 TypeScript/编译 TypeScript
            b.保留 .ts 文件
                删除多余的同名 .js(你已删除 index.js 即可)
            c.工具 → 构建 npm(Vant 组件后续再开)
        d.补充检查
            a.app.ts 是否已编译为 app.js
                方案 A 自动生成;方案 B 由开发者工具编译
            b.pages/index/index.json 仍然有效
                且未引用不存在的全局组件
            c.check-status.js 显示 npm 包需构建
                再在工具中“构建 npm”
    b.微信小程序:内置TS编译
        a.开启 TypeScript 编译支持
            右上角 -> 详情 -> 勾选以下选项:使用 npm 模块、增强编译、启用 TypeScript 编译(这是关键)
        b.项目配置调整 project.config.json
            {
              "setting": {
                "es6": true,
                "enhance": true,
                "nodeModules": true,
                // ... 其他设置
              }
            }
        c.重要:重新编译项目
            开启 TypeScript 编译后:在微信开发者工具中按 Ctrl+Shift+R(或 Cmd+Shift+R)强制刷新
            或者关闭项目重新打开
        d.验证编译是否生效
            编译成功后,你会看到:控制台没有 "找不到 index.js" 的错误
            页面能正常显示,TypeScript 代码能正常运行
        e.如果仍然报错
            如果上述步骤后仍然报错,可能需要:
            暂时创建一个空的 pages/index/index.js 文件(内容为空即可)
            等工具识别到 TypeScript 编译后,再删除这个空文件
        f.关键点说明:
            不需要修改 tsconfig.json 的 outDir
            不需要手动运行 tsc 命令
            工具会在内存中编译 TS,不产出实际 .js 文件
            确保 TypeScript 编译选项已正确开启
    c.手动编译生成 .js 文件
        a.tsconfig.json
            {
              "compilerOptions": {
                "outDir": "./",                   // 修改1
                  "include": [
                    "./**/*.ts"                   // 修改2
                  ],
                  "exclude": [
                    "node_modules",
                    "miniprogram_npm"             // 修改3
                  ]
            }
        b.现在的工作流程
            开发时:编辑 .ts 文件
            编译时:运行 npm run build 生成 .js 文件
            调试时:在微信开发者工具中预览
        c.推荐的开发模式:
            方式一:手动编译,npm run build          # 编译一次
            方式二:监听模式(推荐),npm run dev      # 自动监听 .ts 文件变化并编译
    c.功能说明
        a.说明
            目前的 ts 代码转换成 js 代码的逻辑,是由 @babel/plugin-transform-typescript 插件进行处理的,
            因此在编译过程中,仅仅是移除了ts代码中类型声明等信息。类型错误这类信息,在编译过程是没有提示的,只在编辑器中给予提示的。
            启用 typescript 编译插件后,js 文件也是支持的,如果存在同名的 ts 和 js 文件,则优先使用 ts 文件。
            除了普通小程序,小程序插件开发也是支持的。
            miniprogram-ci 从 1.6.1 版本开始,也支持此功能。
        b.less 使用全局变量
            从开发者工具 1.06.2403132 以上开始,支持 less 直接引用 app.less 中声明的变量和方法,编译器会默认为所有的非 app.less 文件增加引用
            -------------------------------------------------------------------------------------------------
            @import (optional, reference) '/app.less';
            -------------------------------------------------------------------------------------------------
            // app.less
            @redcolor: red;

            .blue {
              color: blue;
            }
            -------------------------------------------------------------------------------------------------
            // 页面.less
            .red {
              color: @redcolor; // 直接使用 app.less 中定义的变量
            }
        c.sass 使用全局变量
            从开发者工具 1.06.2403132 以上开始,支持 sass 直接引用全局变量和方法,和 less 不同,
            我们需要新增一个 global.scss 文件放置在 app.scss 同级,将公共的变量和方法写在 global.scss 中,
            编译器会默认为所有的非 global.scss 文件增加引用。
            -------------------------------------------------------------------------------------------------
            @use '/global.scss';
            -------------------------------------------------------------------------------------------------
            // global.scss
            $red: red;
            -------------------------------------------------------------------------------------------------
            // 其他.scss
            .red {
              color: global.$red; // 使用 global 中的变量
            }
    d.20250917,微信小程序TS不编译的问题
        a.描述
            看了一眼js文件,才发现是TS并没有编译成JS
            新建项目的时候用的就是TS的模板,所以相关的依赖都是全的,如果你的不是,那这里并不能解决你的疑惑。
        b.解决方案
            TS(typescript)的是需要走自定义编译流程,才能编译成JS
            具体的操作是:详情 -> 本地设置 -> 项目设置 ->往下滑,直到"启用自定义处理命令" -> 打钩 -> 并在编译/预览/上传前预处理,填入 npm run tsc
            然后清理编译缓存,再点一下编译
        c.package.json
            {
              "name": "miniprogram-ts-quickstart",
              "version": "1.0.0",
              "description": "",
              "scripts": {
                "compile": "./node_modules/typescript/bin/tsc",
                "tsc": "node ./node_modules/typescript/lib/tsc.js"
              },
              "keywords": [],
              "author": "",
              "license": "",
              "dependencies": {},
              "devDependencies": {
                "miniprogram-api-typings": "^2.8.3-1",
                "typescript": "^3.3.3333"
              }
            }
        d.tsconfig.json
            {
              "compilerOptions": {
                "strictNullChecks": true,
                "noImplicitAny": true,
                "module": "CommonJS",
                "target": "ES5",
                "allowJs": false,
                "experimentalDecorators": true,
                "noImplicitThis": true,
                "noImplicitReturns": true,
                "alwaysStrict": true,
                "inlineSourceMap": true,
                "inlineSources": true,
                "noFallthroughCasesInSwitch": true,
                "noUnusedLocals": true,
                "noUnusedParameters": true,
                "strict": true,
                "removeComments": true,
                "pretty": true,
                "strictPropertyInitialization": true,
                "lib": ["es5"],
                "typeRoots": [
                  "./typings"
                ]
              },
              "include": [
                "./**/*.ts"
              ],
              "exclude": [
                "node_modules"
              ]
            }
        e.project.config.json(appid已经隐藏)
            {
              "description": "项目配置文件",
              "packOptions": {
                "ignore": []
              },
              "miniprogramRoot": "miniprogram/",
              "compileType": "miniprogram",
              "libVersion": "2.8.2",
              "projectname": "wechat-hello",
              "scripts": {
                "beforeCompile": "npm run tsc",
                "beforePreview": "npm run tsc",
                "beforeUpload": "npm run tsc"
              },
              "setting": {
                "urlCheck": true,
                "es6": true,
                "enhance": false,
                "postcss": true,
                "preloadBackgroundData": false,
                "minified": true,
                "newFeature": false,
                "coverView": true,
                "nodeModules": false,
                "autoAudits": false,
                "showShadowRootInWxmlPanel": true,
                "scopeDataCheck": false,
                "uglifyFileName": false,
                "checkInvalidKey": true,
                "checkSiteMap": true,
                "uploadWithSourceMap": true,
                "compileHotReLoad": false,
                "useMultiFrameRuntime": true,
                "useApiHook": true,
                "useApiHostProcess": false,
                "babelSetting": {
                  "ignore": [],
                  "disablePlugins": [],
                  "outputPath": ""
                },
                "enableEngineNative": false,
                "bundle": false,
                "useIsolateContext": true,
                "useCompilerModule": true,
                "userConfirmedUseCompilerModuleSwitch": false,
                "userConfirmedBundleSwitch": false,
                "packNpmManually": false,
                "packNpmRelationList": [],
                "minifyWXSS": true
              },
              "simulatorType": "wechat",
              "simulatorPluginLibVersion": {},
              "appid": "******",
              "condition": {}
            }

03.常用信息3
    a.问题
        a.描述
            mac使用zsh的nvm插件安装的node,node npm在命令行都执行正确,但是在开发者工具提示找不到
        b.报错
            VM1238:1 /bin/sh: npm: command not found
    b.方案1
        a.描述
            npm 和 node 都需要软链到 /usr/local/bin/ 目录下,即该目录下需要 node 和 npm
            /usr/local/bin/npm
            /usr/local/bin/node
        b.解决
            # 打开命令行终端,输入:
            which npm
            # 应该会显示
            Users/xxxx/.nvm/versions/node/v10.15.3/bin/npm
            # 做一个替身到/usr/local/bin下
            sudo ln -s  /Users/xxx/.nvm/versions/node/v10.15.3/bin/npm /usr/local/bin/npm
    c.方案2
        a.描述
            貌似用nvm安装的 都有这个问题,还是你这个叼,完美解决了问题,
        b.解决
            详情 => 本地设置 => 编译/预览/上传前,预处理
            source $HOME/.bash_profile;npm run tsc
            source $HOME/.bashrc;npm run tsc
            source $HOME/.zshrc;npm run tsc

1.5 [2]配置:app.json

00.汇总
    a.区别
        维度          全局配置(app.json)                     页面配置(page.json)
        作用范围       整个小程序所有页面                        仅当前页面
        配置权限       可配置 pages、tabBar、window 等          仅可覆盖 window 及配置页面独有属性
        优先级         低(页面配置会覆盖同名 window 配置)       高(同名配置优先生效)
        使用场景       统一小程序基础样式、路由、权限              定制单个页面的特殊样式或行为
    b.为什么配置了 tabBar,页面却不显示标签栏?
        需确保页面路由在 tabBar.list.pagePath 中,且 pages 数组中存在该路由。
    c.为什么页面无法滚动?
        检查是否在页面配置中设置了 disableScroll: true,或页面内容被 scroll-view 包裹且未设置滚动属性。
    d.自定义组件在页面中不生效?
        需在页面配置的 usingComponents 中正确声明组件路径,路径需从根目录开始(如 /components/xxx/xxx)

01.全局配置(app.json)
    a.说明
        全局配置通过根目录下的 app.json 文件定义,作用于整个小程序的所有页面,
        决定小程序的基础框架、窗口默认样式、页面路由等核心属性。
        开发者无需手动引入,微信开发者工具会自动识别并加载。
    b.核心配置项与说明
        配置项                        类型                作用与取值说明
        pages                        Array<string>      必填,定义小程序的所有页面路由,数组第一个元素为「首页」。<br>格式:["pages/index/index", "pages/logs/logs"](每个路径对应页面的文件夹路径)。
        window                       Object             配置小程序默认窗口样式(如导航栏、背景色等),页面配置可覆盖此部分。
        tabBar                       Object             配置小程序的「底部/顶部标签栏」(如首页、我的),仅当页面在 tabBar.list 中时才显示标签栏。
        networkTimeout               Object             配置网络请求的超时时间(如 request 超时、downloadFile 超时),单位:毫秒。
        permission                   Object             配置小程序需要获取的系统权限(如地理位置、相机、麦克风),需提前在微信公众平台申请。
        requiredBackgroundModes      Array<string>      配置小程序「后台运行能力」(如音乐播放、定位),需在公众平台申请,取值:["audio", "location"]。
    c.window配置项:控制窗口默认样式
        子配置项                      类型                作用示例
        navigationBarTitleText       string             导航栏标题文字(如“首页”)
        navigationBarBackgroundColor string             导航栏背景色(需用十六进制,如 `#ffffff`)
        navigationBarTextStyle       string             导航栏标题颜色,仅支持 `black` / `white`
        backgroundColor              string             页面背景色(下拉刷新时显示的背景)
        enablePullDownRefresh        boolean            是否全局开启下拉刷新(默认 `false`),页面可单独关闭
    d.tabBar配置项:控制标签栏
        子配置项                      类型                作用示例
        position                     string             标签栏位置,支持 `bottom`(默认,底部)/ `top`(顶部,不显示图标)
        color                        string             未选中标签的文字颜色(十六进制)
        selectedColor                string             选中标签的文字颜色(十六进制)
        backgroundColor              string             标签栏背景色(十六进制)
        list                         Array<Object>      必填,标签列表(至少2个,最多5个),每个标签包含:
                                                        pagePath:页面路由(必须在 `pages` 中定义)
                                                        text:标签文字
                                                        iconPath:未选中时的图标路径
                                                        selectedIconPath:选中时的图标路径

02.页面配置(page.json)
    a.说明
        页面配置通过单个页面文件夹下的 `page.json` 文件(如 `pages/index/index.json`)定义,
        仅作用于当前页面,用于覆盖全局配置中与页面相关的属性(如窗口样式),或配置当前页面独有的特性(如是否禁用下拉刷新)。
        注意:页面配置仅能覆盖全局配置的 `window` 部分,无法覆盖 `pages`、`tabBar` 等全局属性。
    b.核心配置项与说明
        配置项                         类型          作用与示例
        navigationBarTitleText        string       覆盖全局导航栏标题(如“首页详情”)
        navigationBarBackgroundColor  string       覆盖全局导航栏背景色
        enablePullDownRefresh         boolean      覆盖全局下拉刷新配置(如全局开启,当前页面设为 `false` 禁用)
        onReachBottomDistance         number       页面滚动到底部时触发 `onReachBottom` 事件的距离(默认50px,可调整)
        disableScroll                 boolean      是否禁止页面滚动(默认 `false`,设为 `true` 后页面无法上下滚动,仅适用于非 scroll-view 页面)
        usingComponents               Object       声明当前页面使用的自定义组件(如 `{"my-component": "/components/my-component/my-component"}`)

03.配置示例
    a.全局配置示例(app.json)
        {
          "pages": [
            "pages/index/index",  // 首页(第一个为默认首页)
            "pages/user/user",    // 我的页面
            "pages/logs/logs"     // 日志页面
          ],
          "window": {
            "navigationBarTitleText": "我的小程序",  // 全局默认导航栏标题
            "navigationBarBackgroundColor": "#2f4050",  // 导航栏背景色(深灰)
            "navigationBarTextStyle": "white",  // 导航栏文字白色
            "enablePullDownRefresh": true,  // 全局开启下拉刷新
            "backgroundColor": "#f5f5f5"    // 页面背景色(浅灰)
          },
          "tabBar": {
            "position": "bottom",  // 标签栏在底部
            "color": "#666666",    // 未选中文字灰色
            "selectedColor": "#2f4050",  // 选中文字深灰
            "backgroundColor": "#ffffff",  // 标签栏背景白色
            "list": [
              {
                "pagePath": "pages/index/index",
                "text": "首页",
                "iconPath": "images/home.png",
                "selectedIconPath": "images/home-active.png"
              },
              {
                "pagePath": "pages/user/user",
                "text": "我的",
                "iconPath": "images/user.png",
                "selectedIconPath": "images/user-active.png"
              }
            ]
          },
          "networkTimeout": {
            "request": 5000,  // 网络请求超时5秒
            "downloadFile": 10000  // 文件下载超时10秒
          },
          "permission": {
            "scope.userLocation": {
              "desc": "需要获取您的地理位置,用于展示附近的服务"  // 申请地理位置权限的说明
            }
          }
        }
    b.页面配置示例(pages/index/index.json)
        假设全局配置开启了下拉刷新,但“首页”需要禁用,同时自定义导航栏标题:
        {
          "navigationBarTitleText": "首页",  // 覆盖全局标题,当前页面显示“首页”
          "enablePullDownRefresh": false,   // 禁用当前页面的下拉刷新(全局为true)
          "onReachBottomDistance": 100,     // 滚动到底部100px时触发加载更多
          "usingComponents": {
            "goods-card": "/components/goods-card/goods-card"  // 引入“商品卡片”自定义组件
          }
        }

1.6 [2]配置:绝对路径

01.设计说明
    a.说明
        在微信小程序中,默认不支持直接使用绝对路径引入文件,
        但可以通过配置 app.json 中的 usingComponents 和 resolveAlias(小程序基础库 2.24.0 及以上支持)来实现类似绝对路径的引入效果。
    b.兼容性
        需要基础库版本 2.20.1+
        需要开发者工具版本 1.05.2110080+
    c.使用限制
        仅支持 ES6 import 语法,不支持 require()
        需要在所有引用的地方保持一致性

02.方法1:使用 resolveAlias 配置路径别名(推荐)
    a.说明
        微信小程序在基础库 2.24.0 及以上版本支持 resolveAlias 配置,可在 app.json 中定义路径别名,实现类似绝对路径的引入方式。
    b.在 app.json 中添加 resolveAlias 配置
        {
          "resolveAlias": {
            "@/components": "/components",
            "@/utils": "/utils",
            "@/pages": "/pages"
          },
          // 其他配置...
          "pages": [
            "pages/index/index"
          ]
        }
    c.在代码中使用别名引入
        // 引入工具函数
        import utils from '@/utils/common.js'

        // 引入组件(在页面的json中)
        {
          "usingComponents": {
            "my-component": "@/components/my-component/index"
          }
        }

        // WXML中使用组件
        <my-component />

03.方法2:通过 usingComponents 配置全局组件路径
    a.配置
        对于组件,可在 app.json 的 usingComponents 中配置全局组件,避免重复写相对路径
        -----------------------------------------------------------------------------------------------------
        {
          "usingComponents": {
            "global-component": "/components/global-component/index"
          }
        }
        -----------------------------------------------------------------------------------------------------
        配置后,在任何页面的 WXML 中都可以直接使用 `<global-component />`,无需再次在页面 json 中引入
    b.注意事项:
        1.resolveAlias 需要小程序基础库 2.24.0 及以上版本,低版本不支持
        2.路径别名必须以 / 开头,表示项目根目录
        3.对于图片等资源文件,仍需使用相对路径或绝对路径(如 /images/icon.png)
        4.如果使用第三方构建工具(如 gulp、webpack),可以通过工具配置实现更灵活的路径解析

1.7 [3]框架:小程序

00.汇总
    01.App(Object object)
    02.AppObject getApp(Object object)

01.App(Object object)
    a.功能说明
        注册小程序。接受一个 Object 参数,其指定小程序的生命周期回调等。
        App() 必须在 app.js 中调用,必须调用且只能调用一次。不然会出现无法预期的后果。
    b.参数说明
        a.onLaunch
            类型:function
            默认值:无
            必填:否
            说明:生命周期回调——监听小程序初始化。
        b.onShow
            类型:function
            默认值:无
            必填:否
            说明:生命周期回调——监听小程序启动或切前台。
        c.onHide
            类型:function
            默认值:无
            必填:否
            说明:生命周期回调——监听小程序切后台。
        d.onError
            类型:function
            默认值:无
            必填:否
            说明:错误监听函数。
        e.onPageNotFound
            类型:function
            默认值:无
            必填:否
            说明:页面不存在监听函数。
            最低版本:1.9.90
        f.onUnhandledRejection
            类型:function
            默认值:无
            必填:否
            说明:未处理的 Promise 拒绝事件监听函数。
            最低版本:2.10.0
        g.onThemeChange
            类型:function
            默认值:无
            必填:否
            说明:监听系统主题变化。
            最低版本:2.11.0
        h.其他
            类型:any
            默认值:无
            必填:否
            说明:开发者可以添加任意的函数或数据变量到 Object 参数中,用 this 可以访问。
    c.生命周期回调
        a.onLaunch(Object object)
            说明:小程序初始化完成时触发,全局只触发一次。
            参数:与 wx.getLaunchOptionsSync 一致。
        b.onShow(Object object)
            说明:小程序启动,或从后台进入前台显示时触发。
            参数:与 wx.onAppShow 一致。
        c.onHide()
            说明:小程序从前台进入后台时触发。
            参数:与 wx.onAppHide 一致。
        d.onError(String error)
            说明:小程序发生脚本错误或 API 调用报错时触发。
            参数:与 wx.onError 一致。
        e.onPageNotFound(Object object)
            说明:小程序要打开的页面不存在时触发。
            最低版本:1.9.90
            参数:与 wx.onPageNotFound 一致。
            注意事项:低版本需做兼容处理。
            示例代码:
            App({
              onPageNotFound(res) {
                wx.redirectTo({
                  url: 'pages/...'
                }) // 如果是 tabbar 页面,请使用 wx.switchTab
              }
            })
        f.onUnhandledRejection(Object object)
            说明:小程序有未处理的 Promise 拒绝时触发。
            最低版本:2.10.0
            参数:与 wx.onUnhandledRejection 一致。
            注意事项:低版本需做兼容处理。
        g.onThemeChange(Object object)
            说明:系统切换主题时触发。
            最低版本:2.11.0
            参数:与 wx.onThemeChange 一致。
    d.示例代码
        App({
          onLaunch (options) {
            // Do something initial when launch.
          },
          onShow (options) {
            // Do something when show.
          },
          onHide (options) {
            // Do something when hide.
          },
          onError (msg) {
            console.log(msg)
          },
          globalData: 'I am global data'
        })

02.AppObject getApp(Object object)
    a.功能说明
        获取到小程序全局唯一的 App 实例。
    b.参数说明
        a.allowDefault
            类型:boolean
            默认值:false
            必填:否
            说明:在 App 未定义时返回默认实现。当 App 被调用时,默认实现中定义的属性会被覆盖合并到 App 中。一般用于独立分包。
            最低版本:2.2.4
    c.示例代码
        // other.js
        var appInstance = getApp()
        console.log(appInstance.globalData) // I am global data
    d.注意事项
        a.不要在定义于 App() 内的函数中,或调用 App 前调用 getApp(),使用 this 就可以拿到 app 实例。
        b.通过 getApp() 获取实例之后,不要私自调用生命周期函数。

1.8 [3]框架:页面

00.汇总
    01.Page(Object object)
    02.PageObject[] getCurrentPages()
    03.Router

01.Page(Object object)
    a.功能说明
        注册小程序中的一个页面。接受一个 Object 类型参数,其指定页面的初始数据、生命周期回调、事件处理函数等。
    b.参数说明
        a.data
            类型:Object
            默认值:无
            必填:否
            说明:页面的初始数据。
        b.options
            类型:Object
            默认值:无
            必填:否
            说明:页面的组件选项,同 Component 构造器中的 options。
            最低版本:2.10.1
        c.behaviors
            类型:String Array
            默认值:无
            必填:否
            说明:类似于 mixins 和 traits 的组件间代码复用机制。
            最低版本:2.9.2
        d.onLoad
            类型:function
            默认值:无
            必填:否
            说明:生命周期回调—监听页面加载。
        e.onShow
            类型:function
            默认值:无
            必填:否
            说明:生命周期回调—监听页面显示。
        f.onReady
            类型:function
            默认值:无
            必填:否
            说明:生命周期回调—监听页面初次渲染完成。
        g.onHide
            类型:function
            默认值:无
            必填:否
            说明:生命周期回调—监听页面隐藏。
        h.onUnload
            类型:function
            默认值:无
            必填:否
            说明:生命周期回调—监听页面卸载。
        i.onRouteDone
            类型:function
            默认值:无
            必填:否
            说明:生命周期回调—监听路由动画完成。
        j.onPullDownRefresh
            类型:function
            默认值:无
            必填:否
            说明:监听用户下拉动作。
        k.onReachBottom
            类型:function
            默认值:无
            必填:否
            说明:页面上拉触底事件的处理函数。
        l.onShareAppMessage
            类型:function
            默认值:无
            必填:否
            说明:用户点击右上角转发。
        m.onShareTimeline
            类型:function
            默认值:无
            必填:否
            说明:用户点击右上角转发到朋友圈。
        n.onAddToFavorites
            类型:function
            默认值:无
            必填:否
            说明:用户点击右上角收藏。
        o.onPageScroll
            类型:function
            默认值:无
            必填:否
            说明:页面滚动触发事件的处理函数。
        p.onResize
            类型:function
            默认值:无
            必填:否
            说明:页面尺寸改变时触发。
        q.onTabItemTap
            类型:function
            默认值:无
            必填:否
            说明:当前是 tab 页时,点击 tab 时触发。
        r.onSaveExitState
            类型:function
            默认值:无
            必填:否
            说明:页面销毁前保留状态回调。
        s.其他
            类型:any
            默认值:无
            必填:否
            说明:开发者可以添加任意的函数或数据到 Object 参数中,在页面的函数中用 this 可以访问。这部分属性会在页面实例创建时进行一次深拷贝。
    c.示例代码
        //index.js
        Page({
          data: {
            text: "This is page data."
          },
          onLoad: function(options) {
            // Do some initialize when page load.
          },
          onShow: function() {
            // Do something when page show.
          },
          onReady: function() {
            // Do something when page ready.
          },
          onHide: function() {
            // Do something when page hide.
          },
          onUnload: function() {
            // Do something when page close.
          },
          onPullDownRefresh: function() {
            // Do something when pull down.
          },
          onReachBottom: function() {
            // Do something when page reach bottom.
          },
          onShareAppMessage: function () {
            // return custom share data when user share.
          },
          onPageScroll: function() {
            // Do something when page scroll
          },
          onResize: function() {
            // Do something when page resize
          },
          onTabItemTap(item) {
            console.log(item.index)
            console.log(item.pagePath)
            console.log(item.text)
          },
          // Event handler.
          viewTap: function() {
            this.setData({
              text: 'Set some data for updating view.'
            }, function() {
              // this is setData callback
            })
          },
          customData: {
            hi: 'MINA'
          }
        })
    d.data属性说明
        a.功能
            data 是页面第一次渲染使用的初始数据。
        b.注意事项
            页面加载时,data 将会以 JSON 字符串的形式由逻辑层传至渲染层,
            因此 data 中的数据必须是可以转成 JSON 的类型:字符串,数字,布尔值,对象,数组。
        c.示例代码
            <view>{{text}}</view>
            <view>{{array[0].msg}}</view>
            Page({
              data: {
                text: 'init data',
                array: [{msg: '1'}, {msg: '2'}]
              }
            })
    e.生命周期回调函数
        a.onLoad(Object query)
            页面加载时触发。一个页面只会调用一次,可以在 onLoad 的参数中获取打开当前页面路径中的参数。
            参数:
                query:打开当前页面路径中的参数。
        b.onShow()
            页面显示/切入前台时触发。
        c.onReady()
            页面初次渲染完成时触发。一个页面只会调用一次,代表页面已经准备妥当,可以和视图层进行交互。
            注意:对界面内容进行设置的 API 如 wx.setNavigationBarTitle,请在 onReady 之后进行。
        d.onHide()
            页面隐藏/切入后台时触发。如 wx.navigateTo 或底部 tab 切换到其他页面,小程序切入后台等。
        e.onUnload()
            页面卸载时触发。如 wx.redirectTo 或 wx.navigateBack 到其他页面时。
        f.onRouteDone()
            路由动画完成时触发。如 wx.navigateTo 页面完全推入后 或 wx.navigateBack 页面完全恢复时。
    f.页面事件处理函数
        a.onPullDownRefresh()
            监听用户下拉刷新事件。
            -------------------------------------------------------------------------------------------------
            注意:
            需要在 app.json 的 window 选项中或页面配置中开启 enablePullDownRefresh。
            可以通过 wx.startPullDownRefresh 触发下拉刷新,调用后触发下拉刷新动画,效果与用户手动下拉刷新一致。
            当处理完数据刷新后,wx.stopPullDownRefresh 可以停止当前页面的下拉刷新。
        b.onReachBottom()
            监听用户上拉触底事件。
            -------------------------------------------------------------------------------------------------
            注意:
            可以在 app.json 的 window 选项中或页面配置中设置触发距离 onReachBottomDistance。
            在触发距离内滑动期间,本事件只会被触发一次。
        c.onPageScroll(Object object)
            监听用户滑动页面事件。
            -------------------------------------------------------------------------------------------------
            参数:
            scrollTop:页面在垂直方向已滚动的距离(单位px)。
            -------------------------------------------------------------------------------------------------
            注意:
            请只在需要的时候才在 page 中定义此方法,不要定义空方法。
            请避免在 onPageScroll 中过于频繁的执行 setData 等引起逻辑层-渲染层通信的操作。
        d.onAddToFavorites(Object object)
            监听用户点击右上角菜单“收藏”按钮的行为,并自定义收藏内容。
            -------------------------------------------------------------------------------------------------
            参数:
            webViewUrl:页面中包含 web-view 组件时,返回当前 web-view 的 url。
            -------------------------------------------------------------------------------------------------
            返回内容:
            title:自定义标题。
            imageUrl:自定义图片,显示图片长宽比为 1:1。
            query:自定义 query 字段。
            -------------------------------------------------------------------------------------------------
            示例代码:
            Page({
              onAddToFavorites(res) {
                console.log('webViewUrl: ', res.webViewUrl)
                return {
                  title: '自定义标题',
                  imageUrl: 'http://demo.png',
                  query: 'name=xxx&age=xxx',
                }
              }
            })
        e.onShareAppMessage(Object object)
            监听用户点击页面内转发按钮或右上角菜单“转发”按钮的行为,并自定义转发内容。
            -------------------------------------------------------------------------------------------------
            参数:
            from:转发事件来源。
            target:如果 from 值是 button,则 target 是触发这次转发事件的 button,否则为 undefined。
            webViewUrl:页面中包含 web-view 组件时,返回当前 web-view 的 url。
            -------------------------------------------------------------------------------------------------
            返回内容:
            title:转发标题。
            path:转发路径。
            imageUrl:自定义图片路径。
            promise:用于异步返回转发内容。
            -------------------------------------------------------------------------------------------------
            示例代码:
            Page({
              onShareAppMessage() {
                const promise = new Promise(resolve => {
                  setTimeout(() => {
                    resolve({
                      title: '自定义转发标题'
                    })
                  }, 2000)
                })
                return {
                  title: '自定义转发标题',
                  path: '/page/user?id=123',
                  promise
                }
              }
            })
        f.onShareTimeline()
            监听右上角菜单“分享到朋友圈”按钮的行为,并自定义分享内容。
            -------------------------------------------------------------------------------------------------
            返回内容:
            title:自定义标题。
            query:自定义页面路径中携带的参数。
            imageUrl:自定义图片路径。
        g.onResize(Object object)
            页面尺寸改变时触发。
        h.onTabItemTap(Object object)
            点击 tab 时触发。
            -------------------------------------------------------------------------------------------------
            参数:
            index:被点击 tabItem 的序号。
            pagePath:被点击 tabItem 的页面路径。
            text:被点击 tabItem 的按钮文字。
            -------------------------------------------------------------------------------------------------
            示例代码
            Page({
              onTabItemTap(item) {
                console.log(item.index)
                console.log(item.pagePath)
                console.log(item.text)
              }
            })
        i.onSaveExitState()
            每当小程序可能被销毁之前,页面回调函数 onSaveExitState 会被调用,可以进行退出状态的保存。
    g.组件事件处理函数
        a.说明
            Page 中还可以定义组件事件处理函数。在渲染层的组件中加入事件绑定,当事件被触发时,就会执行 Page 中定义的事件处理函数。
            -------------------------------------------------------------------------------------------------
            <view bindtap="viewTap"> click me </view>
            Page({
              viewTap: function() {
                console.log('view tap')
              }
            })
        b.Page.route
            基础库 1.2.0 开始支持,低版本需做兼容处理。
            到当前页面的路径,类型为String。
            -------------------------------------------------------------------------------------------------
            Page({
              onShow: function() {
                console.log(this.route)
              }
            })
        c.Page.prototype.setData(Object data, Function callback)
            功能:
            setData 函数用于将数据从逻辑层发送到视图层(异步),同时改变对应的 this.data 的值(同步)。
            -------------------------------------------------------------------------------------------------
            参数:
            data:这次要改变的数据。
            callback:setData 引起的界面更新渲染完毕后的回调函数。
            -------------------------------------------------------------------------------------------------
            注意:
            直接修改 this.data 而不调用 this.setData 是无法改变页面的状态的。
            单次设置的数据不能超过 1024kB。
            -------------------------------------------------------------------------------------------------
            示例代码:
            <!--index.wxml-->
            <view>{{text}}</view>
            <button bindtap="changeText"> Change normal data </button>
            <view>{{num}}</view>
            <button bindtap="changeNum"> Change normal num </button>
            <view>{{array[0].text}}</view>
            <button bindtap="changeItemInArray"> Change Array data </button>
            <view>{{object.text}}</view>
            <button bindtap="changeItemInObject"> Change Object data </button>
            <view>{{newField.text}}</view>
            <button bindtap="addNewField"> Add new data </button>
            -------------------------------------------------------------------------------------------------
            示例代码:
            Page({
              data: {
                text: 'init data',
                num: 0,
                array: [{text: 'init data'}],
                object: {
                  text: 'init data'
                }
              },
              changeText: function() {
                this.setData({
                  text: 'changed data'
                })
              },
              changeNum: function() {
                this.data.num = 1
                this.setData({
                  num: this.data.num
                })
              },
              changeItemInArray: function() {
                this.setData({
                  'array[0].text':'changed data'
                })
              },
              changeItemInObject: function(){
                this.setData({
                  'object.text': 'changed data'
                });
              },
              addNewField: function() {
                this.setData({
                  'newField.text': 'new data'
                })
              }
            })
    h.页面间通信
        a.功能
            如果一个页面由另一个页面通过 wx.navigateTo 打开,这两个页面间将建立一条数据通道。
        b.方法
            被打开的页面可以通过 this.getOpenerEventChannel() 方法来获得一个 EventChannel 对象。
            wx.navigateTo 的 success 回调中也包含一个 EventChannel 对象。

02.PageObject[] getCurrentPages()
    a.说明
        获取当前页面栈。数组中第一个元素为首页,最后一个元素为当前页面。
    b.注意事项
        不要尝试修改页面栈,会导致路由以及页面状态错误。
        不要在 App.onLaunch 的时候调用 getCurrentPages(),此时 page 还没有生成。

03.Router
    a.说明
        基础库 2.16.1 开始支持,低版本需做兼容处理。
        页面路由器对象。可以通过 this.pageRouter 或 this.router 获得当前页面或自定义组件的路由器对象。
    b.路由的相对路径
        a.说明
            页面路由器有 switchTab reLaunch redirectTo navigateTo navigateBack 五个方法,
            与 wx 对象向同名的五个方法 switchTab reLaunch redirectTo navigateTo navigateBack 功能相同;
            唯一的区别是,页面路由器中的方法调用时,相对路径永远相对于 this 指代的页面或自定义组件。
        b.示例代码
            // index/index.js
            Page({
              wxNavAction: function () {
                wx.navigateTo({
                  url: './new-page'
                })
              },
              routerNavAction: function () {
                this.pageRouter.navigateTo({
                  url: './new-page'
                })
              }
            })
        c.说明
            页面 index/index 的 js 代码如上所示。如果此时已经跳转到了一个新页面 pack/index ,
            然后才调用到上面的 wxNavAction 方法,跳转的新页面路径将是 pack/new-page ;
            而如果调用的是 routerNavAction 方法,跳转的新页面路径仍然是 index/new-page 。
            -------------------------------------------------------------------------------------------------
            换而言之, this.pageRouter 获得的路由器对象具有更好的基路径稳定性。
            通常情况下,使用 this.pageRouter.navigateTo 代替 wx.navigateTo 是更优的。
    c.相对于自定义组件路径的路由
        this.pageRouter 和 this.router 在页面中将获得同样的页面路由器对象。
        但如果在自定义组件中调用, this.pageRouter 将相对于自定义组件所在的页面来进行路由跳转,而 this.router 相对于自定义组件自身的路径。

1.9 [3]框架:自定义组件

00.汇总
    01.Component(Object object)
    02.Behavior(Object object)

01.Component(Object object)
    a.功能说明
        创建自定义组件,接受一个 Object 类型的参数。
    b.参数说明
        a.properties
            类型:Object Map
            是否必填:否
            描述:组件的对外属性,是属性名到属性设置的映射表。
        b.data
            类型:Object
            是否必填:否
            描述:组件的内部数据,和 properties 一同用于组件的模板渲染。
        c.observers
            类型:Object
            是否必填:否
            描述:组件数据字段监听器,用于监听 properties 和 data 的变化。
            最低版本:2.6.1
        d.methods
            类型:Object
            是否必填:否
            描述:组件的方法,包括事件响应函数和任意的自定义方法。
        e.behaviors
            类型:String Array
            是否必填:否
            描述:类似于 mixins 和 traits 的组件间代码复用机制。
        f.created
            类型:Function
            是否必填:否
            描述:组件生命周期函数-在组件实例刚刚被创建时执行,注意此时不能调用 setData。
        g.attached
            类型:Function
            是否必填:否
            描述:组件生命周期函数-在组件实例进入页面节点树时执行。
        h.ready
            类型:Function
            是否必填:否
            描述:组件生命周期函数-在组件布局完成后执行。
        i.moved
            类型:Function
            是否必填:否
            描述:组件生命周期函数-在组件实例被移动到节点树另一个位置时执行。
        j.detached
            类型:Function
            是否必填:否
            描述:组件生命周期函数-在组件实例被从页面节点树移除时执行。
        k.relations
            类型:Object
            是否必填:否
            描述:组件间关系定义。
        l.externalClasses
            类型:String Array
            是否必填:否
            描述:组件接受的外部样式类。
        m.options
            类型:Object Map
            是否必填:否
            描述:一些选项。
        n.lifetimes
            类型:Object
            是否必填:否
            描述:组件生命周期声明对象。
            最低版本:2.2.3
        o.pageLifetimes
            类型:Object
            是否必填:否
            描述:组件所在页面的生命周期声明对象。
            最低版本:2.2.3
    c.组件实例属性
        a.is
            类型:String
            描述:组件的文件路径。
        b.id
            类型:String
            描述:节点id。
        c.dataset
            类型:String
            描述:节点dataset。
        d.data
            类型:Object
            描述:组件数据,包括内部数据和属性值。
        e.properties
            类型:Object
            描述:组件数据,包括内部数据和属性值(与 data 一致)。
        f.router
            类型:Object
            描述:相对于当前自定义组件的 Router 对象。
        g.pageRouter
            类型:Object
            描述:相对于当前自定义组件所在页面的 Router 对象。
        h.renderer
            类型:String
            描述:渲染当前组件的渲染后端。
    d.组件实例方法
        a.setData
            参数:Object newData
            描述:设置 data 并执行视图层渲染。
        b.hasBehavior
            参数:Object behavior
            描述:检查组件是否具有 behavior。
        c.triggerEvent
            参数:String name, Object detail, Object options
            描述:触发事件。
        d.createSelectorQuery
            描述:创建一个 SelectorQuery 对象,选择器选取范围为这个组件实例内。
        e.createIntersectionObserver
            描述:创建一个 IntersectionObserver 对象,选择器选取范围为这个组件实例内。
        f.createMediaQueryObserver
            描述:创建一个 MediaQueryObserver 对象。
            最低版本:2.11.1
        g.selectComponent
            参数:String selector
            描述:使用选择器选择组件实例节点,返回匹配到的第一个组件实例对象。
        h.selectAllComponents
            参数:String selector
            描述:使用选择器选择组件实例节点,返回匹配到的全部组件实例对象组成的数组。
        i.selectOwnerComponent
            描述:选取当前组件节点所在的组件实例(即组件的引用者),返回它的组件实例对象。
            最低版本:2.8.2
        j.getRelationNodes
            参数:String relationKey
            描述:获取这个关系所对应的所有关联节点。
        k.groupSetData
            参数:Function callback
            描述:立刻执行 callback,其中的多个 setData 之间不会触发界面绘制。
            最低版本:2.4.0
        l.getTabBar
            描述:返回当前页面的 custom-tab-bar 的组件实例。
            最低版本:2.6.2
        m.getPageId
            描述:返回页面标识符(一个字符串),可以用来判断几个自定义组件实例是不是在同一个页面内。
            最低版本:2.7.1
        n.animate
            参数:String selector, Array keyframes, Number duration, Function callback
            描述:执行关键帧动画。
            最低版本:2.9.0
        o.clearAnimation
            参数:String selector, Object options, Function callback
            描述:清除关键帧动画。
            最低版本:2.9.0
        p.applyAnimatedStyle
            参数:String selector, Function updater, Object config, Function callback
            描述:绑定由 worklet 驱动的样式到相应的节点。
            最低版本:2.29.0
        q.clearAnimatedStyle
            参数:String selector, Array styleIds, Function callback
            描述:清除节点上 worklet 驱动样式的绑定关系。
            最低版本:2.30.1
        r.setUpdatePerformanceListener
            参数:Object options, Function listener
            描述:设置更新性能统计信息接收函数。
            最低版本:2.12.0
    e.示例代码
        Component({
          behaviors: [],
          properties: {
            myProperty: {
              type: String,
              value: ''
            },
            myProperty2: String
          },
          data: {},
          lifetimes: {
            attached: function () { },
            moved: function () { },
            detached: function () { },
          },
          attached: function () { },
          ready: function() { },
          pageLifetimes: {
            show: function () { },
            hide: function () { },
            resize: function () { },
          },
          methods: {
            onMyButtonTap: function(){
              this.setData({
                // 更新属性和数据的方法与更新页面数据的方法类似
              })
            },
            _myPrivateMethod: function(){
              this.setData({
                'A[0].B': 'myPrivateData'
              })
            },
            _propertyChange: function(newVal, oldVal) {

            }
          }
        })
    f.properties定义
        a.type
            描述:属性的类型。
            是否必填:是
        b.optionalTypes
            描述:属性的类型(可以指定多个)。
            是否必填:否
            最低版本:2.6.5
        c.value
            描述:属性的初始值。
            是否必填:否
        d.observer
            描述:属性值变化时的回调函数。
            是否必填:否
        e.示例代码
            Component({
              properties: {
                min: {
                  type: Number,
                  value: 0
                },
                max: {
                  type: Number,
                  value: 0,
                  observer: function(newVal, oldVal) {
                    // 属性值变化时执行
                  }
                },
                lastLeaf: {
                  type: Number,
                  optionalTypes: [String, Object],
                  value: 0
                }
              }
            })
    g.Bug & Tip
        使用 this.data 可以获取内部数据和属性值;但直接修改它不会将变更应用到界面上,应使用 setData 修改。
        生命周期函数无法在组件方法中通过 this 访问到。
        属性名应避免以 data 开头,即不要命名成 dataXyz 这样的形式,因为在 WXML 中, data-xyz="" 会被作为节点 dataset 来处理,而不是组件属性。
        在一个组件的定义和使用时,组件的属性名和 data 字段相互间都不能冲突(尽管它们位于不同的定义段中)。
        从基础库 2.0.9 开始,对象类型的属性和 data 字段中可以包含函数类型的子字段,即可以通过对象类型的属性字段来传递函数。低于这一版本的基础库不支持这一特性。
        bug: 位于 slot 中的自定义组件没有触发 pageLifetimes 中声明的页面生命周期,此问题在 2.5.2 中修复。
        bug: 对于 type 为 Object 或 Array 的属性,如果通过该组件自身的 this.setData 来改变属性值的一个子字段,则依旧会触发属性 observer ,且 observer 接收到的 newVal 是变化的那个子字段的值, oldVal 为空, changedPath 包含子字段的字段名相关信息;目前推荐使用 observers 定义段代替。

02.Behavior(Object object)
    a.功能说明
        注册一个 behavior,接受一个 Object 类型的参数。
    b.参数说明
        a.properties
            类型:Object Map
            是否必填:否
            描述:组件的对外属性,是属性名到属性设置的映射表。
        b.data
            类型:Object
            是否必填:否
            描述:组件的内部数据,和 properties 一同用于组件的模板渲染。
        c.observers
            类型:Object
            是否必填:否
            描述:组件数据字段监听器,用于监听 properties 和 data 的变化。
            最低版本:2.6.1
        d.methods
            类型:Object
            是否必填:否
            描述:组件的方法,包括事件响应函数和任意的自定义方法。
        e.behaviors
            类型:String Array
            是否必填:否
            描述:类似于 mixins 和 traits 的组件间代码复用机制。
        f.created
            类型:Function
            是否必填:否
            描述:组件生命周期函数-在组件实例刚刚被创建时执行,注意此时不能调用 setData。
        g.attached
            类型:Function
            是否必填:否
            描述:组件生命周期函数-在组件实例进入页面节点树时执行。
        h.ready
            类型:Function
            是否必填:否
            描述:组件生命周期函数-在组件布局完成后执行。
        i.moved
            类型:Function
            是否必填:否
            描述:组件生命周期函数-在组件实例被移动到节点树另一个位置时执行。
        j.detached
            类型:Function
            是否必填:否
            描述:组件生命周期函数-在组件实例被从页面节点树移除时执行。
        k.relations
            类型:Object
            是否必填:否
            描述:组件间关系定义。
        l.lifetimes
            类型:Object
            是否必填:否
            描述:组件生命周期声明对象。
            最低版本:2.2.3
        m.pageLifetimes
            类型:Object
            是否必填:否
            描述:组件所在页面的生命周期声明对象。
            最低版本:2.2.3
        n.definitionFilter
            类型:Function
            是否必填:否
            描述:定义段过滤器,用于自定义组件扩展。
            最低版本:2.2.3
    c.示例代码
        // my-behavior.js
        module.exports = Behavior({
          behaviors: [],
          properties: {
            myBehaviorProperty: {
              type: String
            }
          },
          data: {
            myBehaviorData: {}
          },
          attached: function(){},
          methods: {
            myBehaviorMethod: function(){}
          }
        })

1.10 [3]框架:模块化

00.汇总
    01.require
    02.Object module
    03.Object exports
    04.any requirePlugin(string path)
    05.any requireMiniProgram()

01.require
    a.功能说明
        引入模块。返回模块通过 module.exports 或 exports 暴露的接口。
        支持同步调用和异步调用。
    b.参数说明
        a.path
            类型:string
            是否必填:是
            描述:需要引入模块文件相对于当前文件的相对路径,或 npm 模块名,或 npm 模块路径。
            注意:默认不支持绝对路径,可通过配置 resolveAlias 自定义路径映射。
        b.callback
            类型:function
            是否必填:否
            描述:异步加载成功回调函数,该回调函数参数为成功加载的模块。
        c.error
            类型:function
            是否必填:否
            描述:异步加载失败回调函数,该回调函数参数为错误信息和模块名。
    c.require.async 链式调用
        a.功能
            可以通过链式调用的方式使用异步加载模块。
        b.示例代码
            require
            .async('path/to/mod')
            .then((mod) => {
                console.log(mod)
            })
            .catch(({ errMsg, mod }) => {
                console.error(`path: ${mod}, ${errMsg}`)
            })
    d.示例代码
        a.同一包内调用
            // common.js
            function sayHello(name) {
              console.log(`Hello ${name} !`)
            }
            function sayGoodbye(name) {
              console.log(`Goodbye ${name} !`)
            }

            module.exports.sayHello = sayHello
            exports.sayGoodbye = sayGoodbye

            var common = require('common.js')
            Page({
              helloMINA: function() {
                common.sayHello('MINA')
              },
              goodbyeMINA: function() {
                common.sayGoodbye('MINA')
              }
            })
        b.跨分包异步调用
            // subpackage/common.js 分包 common 文件
            export const sayHello = () => console.log("hello")

            // pages/index.js 主包页面
            let common;
            require('../../subpackage/common.js', (mod) => {
                common = mod
            }, ({ errMsg, mod }) => {
                console.error(`path: ${mod}, ${errMsg}`)
            })

            Page({
                sayHello() {
                    common && common.sayHello()
                }
            })

02.Object module
    a.功能说明
        当前模块对象,用于描述当前模块的相关信息。
    b.属性说明
        a.exports
            类型:Object
            描述:模块向外暴露的对象,使用 require 引用该模块时可以获取。
    c.示例代码
        // common.js
        function sayHello(name) {
          console.log(`Hello ${name} !`)
        }
        function sayGoodbye(name) {
          console.log(`Goodbye ${name} !`)
        }

        module.exports.sayHello = sayHello
        exports.sayGoodbye = sayGoodbye

03.Object exports
    a.功能说明
        module.exports 的引用,用于向外暴露模块的接口。
    b.示例代码
        // common.js
        function sayHello(name) {
          console.log(`Hello ${name} !`)
        }
        function sayGoodbye(name) {
          console.log(`Goodbye ${name} !`)
        }

        module.exports.sayHello = sayHello
        exports.sayGoodbye = sayGoodbye

04.any requirePlugin(string path)
    a.功能说明
        引入插件。返回插件通过 main 暴露的接口。
    b.参数说明
        a.module
            类型:string
            描述:需要引入的插件的 alias。
            注意:基础库 2.14.0 起,也可以是插件的 AppID。
    c.示例代码
        var myPluginInterface = requirePlugin('myPlugin');

        myPluginInterface.hello();
        var myWorld = myPluginInterface.world;

        var myPluginInterface = requirePlugin('wxIDxxxxxxxxxx'); // 2.14.0 起

05.any requireMiniProgram()
    a.功能说明
        插件引入当前使用者小程序。返回使用者小程序通过插件配置中 export 暴露的接口。
        注意:该接口仅在插件中存在。
    b.参数说明
        该接口不需要参数。
    c.示例代码
        // in plugin
        var mp = requireMiniProgram()
        console.log(mp.whoami)  // 'Wechat MiniProgram'

1.11 [3]框架:基础功能

00.汇总
    01.控制台:console
    02.定时器:number setTimeout(function callback, number delay, any rest)
    03.Object WXWebAssembly

01.控制台:console
    a.功能说明
        向调试面板中打印日志。console 是一个全局对象,可以直接访问。
        在微信客户端中,向 vConsole 中输出日志。
    b.方法说明
        a.console.debug()
            描述:向调试面板中打印 debug 日志。
        b.console.log()
            描述:向调试面板中打印 log 日志。
        c.console.info()
            描述:向调试面板中打印 info 日志。
        d.console.warn()
            描述:向调试面板中打印 warn 日志。
        e.console.error()
            描述:向调试面板中打印 error 日志。
        f.console.group(string label)
            描述:在调试面板中创建一个新的分组。随后输出的内容都会被添加一个缩进,表示该内容属于当前分组。
        g.console.groupEnd()
            描述:结束由 console.group 创建的分组。
    c.注意事项
        a.由于 vConsole 功能有限
            以及不同客户端对 console 方法的支持情况有差异,建议开发者在小程序中只使用本文档中提供的方法。
        b.部分内容展示的限制请参见调试。

02.定时器:number setTimeout(function callback, number delay, any rest)
    a.功能说明
        设定一个定时器。在定时到期以后执行注册的回调函数。
        注意:以 Promise 风格调用不支持;小程序插件支持。
    b.参数说明
        a.function callback
            描述:回调函数。
        b.number delay
            描述:延迟的时间,函数的调用会在该延迟之后发生,单位 ms。
        c.any rest
            描述:param1, param2, ..., paramN 等附加参数,它们会作为参数传递给回调函数。
    c.返回值
        类型:number
        描述:定时器的编号。这个值可以传递给 clearTimeout 来取消该定时。

03.Object WXWebAssembly
    a.功能说明
        WXWebAssembly 类似于 Web 标准里的 WebAssembly,能够在一定程度上提高小程序的性能。
    b.参考
        具体请参考 WXWebAssembly。

1.12 [4]语法:WXS

00.汇总
    01.模块
    02.变量
    02.变量
    04.运算符
    05.语句
    06.数据类型
    07.基础类库

01.模块
    a.介绍
        a.功能说明
            WXS(WeiXin Script)代码可以编写在 WXML 文件中的 <wxs> 标签内,或以 .wxs 为后缀名的文件内。
            每个 .wxs 文件和 <wxs> 标签都是一个独立的模块,具有独立的作用域。
            模块中的变量与函数默认为私有,需通过 module.exports 对外暴露。
        b.注意事项
            <wxs> 模块只能在定义模块的 WXML 文件中被访问到。
            使用 <include> 或 <import> 时,<wxs> 模块不会被引入到对应的 WXML 文件中。
            <template> 标签中,只能使用定义该 <template> 的 WXML 文件中定义的 <wxs> 模块。
    b.wxs文件
        a.wxs文件
            a.说明
                在微信开发者工具中,右键可以直接创建 .wxs 文件
            b.示例代码
                // /pages/comm.wxs
                var foo = "'hello world' from comm.wxs";
                var bar = function(d) {
                  return d;
                }
                module.exports = {
                  foo: foo,
                  bar: bar
                };
        b.module 对象
            a.说明
                每个 wxs 模块均有一个内置的 module 对象。
            b.属性
                exports:用于对外共享模块的私有变量与函数。
            c.示例代码
                // /pages/tools.wxs
                var foo = "'hello world' from tools.wxs";
                var bar = function (d) {
                  return d;
                }
                module.exports = {
                  FOO: foo,
                  bar: bar,
                };
                module.exports.msg = "some msg";

                <!-page/index/index.wxml -->
                <wxs src="./../tools.wxs" module="tools" />
                <view> {{tools.msg}} </view>
                <view> {{tools.bar(tools.FOO)}} </view>
            d.页面输出
                some msg
                'hello world' from tools.wxs
        c.require 函数
            a.功能
                在 .wxs 模块中引用其他 wxs 文件模块。
            b.注意事项
                只能引用 .wxs 文件模块,且必须使用相对路径。
                wxs 模块均为单例,wxs 模块在第一次被引用时,会自动初始化为单例对象。多个页面,多个地方,多次引用,使用的都是同一个 wxs 模块对象。
                如果一个 wxs 模块在定义之后,一直没有被引用,则该模块不会被解析与运行。
            c.示例代码
                // /pages/tools.wxs
                var foo = "'hello world' from tools.wxs";
                var bar = function (d) {
                  return d;
                }
                module.exports = {
                  FOO: foo,
                  bar: bar,
                };
                module.exports.msg = "some msg";

                // /pages/logic.wxs
                var tools = require("./tools.wxs");
                console.log(tools.FOO);
                console.log(tools.bar("logic.wxs"));
                console.log(tools.msg);

                <!-/page/index/index.wxml -->
                <wxs src="./../logic.wxs" module="logic" />
            d.控制台输出
                'hello world' from tools.wxs
                logic.wxs
                some msg
    c.<wxs>标签
        a.属性
            module:当前 <wxs> 标签的模块名,必填。
            src:引用 .wxs 文件的相对路径,仅当标签为空或为单闭合标签时有效。
        b.module 属性
            a.说明
                模块名建议在单个 WXML 文件内唯一。
            b.命名规则
                首字符:字母(a-zA-Z),下划线(_)。
                剩余字符:字母(a-zA-Z),下划线(_),数字(0-9)。
            c.示例代码
                <!--wxml-->
                <wxs module="foo">
                var some_msg = "hello world";
                module.exports = {
                  msg : some_msg,
                }
                </wxs>
                <view> {{foo.msg}} </view>
            d.页面输出
                hello world
        c.src 属性
            a.说明
                用于引用其他 wxs 文件模块。
            b.注意事项
                只能引用 .wxs 文件模块,且必须使用相对路径。
                wxs 模块为单例,首次引用时初始化为单例对象。
            c.示例代码
                // /pages/index/index.js
                Page({
                  data: {
                    msg: "'hello wrold' from js",
                  }
                })

                <!-/pages/index/index.wxml -->
                <wxs src="./../comm.wxs" module="some_comms"></wxs>
                <!-也可以直接使用单标签闭合的写法 -->
                <!-<wxs src="./../comm.wxs" module="some_comms" /> -->

                <!-调用 some_comms 模块里面的 bar 函数,且参数为 some_comms 模块里面的 foo -->
                <view> {{some_comms.bar(some_comms.foo)}} </view>
                <!-调用 some_comms 模块里面的 bar 函数,且参数为 page/index/index.js 里面的 msg -->
                <view> {{some_comms.bar(msg)}} </view>
            d.页面输出
                'hello world' from comm.wxs
                'hello wrold' from js

02.变量
    a.概念
        WXS 中的变量均为值的引用。
        没有声明的变量直接赋值使用,会被定义为全局变量。
        如果只声明变量而不赋值,则默认值为 undefined。
        var表现与javascript一致,会有变量提升。
        -----------------------------------------------------------------------------------------------------
        var foo = 1;
        var bar = "hello world";
        var i; // i === undefined
        上面代码,分别声明了 foo、 bar、 i 三个变量。然后,foo 赋值为数值 1 ,bar 赋值为字符串 "hello world"。
    b.变量名
        首字符必须是:字母(a-zA-Z),下划线(_)
        剩余字符可以是:字母(a-zA-Z),下划线(_), 数字(0-9)
    c.保留标识符,以下标识符不能作为变量名
        delete
        void
        typeof
        -----------------------------------------------------------------------------------------------------
        null
        undefined
        NaN
        Infinity
        var
        -----------------------------------------------------------------------------------------------------
        if
        else
        -----------------------------------------------------------------------------------------------------
        true
        false
        -----------------------------------------------------------------------------------------------------
        require
        -----------------------------------------------------------------------------------------------------
        this
        function
        arguments
        return
        -----------------------------------------------------------------------------------------------------
        for
        while
        do
        break
        continue
        switch
        case
        default

03.注释
    a.注释方法
        单行注释://
        多行注释:/* ... */
        结尾注释:/* 后的所有代码均被注释
    b.示例
        <wxs module="sample">
        // 方法一:单行注释
        -----------------------------------------------------------------------------------------------------
        /*
        方法二:多行注释
        */
        -----------------------------------------------------------------------------------------------------
        /*
        方法三:结尾注释。即从 /* 开始往后的所有 WXS 代码均被注释,方法三 和 方法二 的唯一区别是,没有 */ 结束符
        var a = 1;
        var b = 2;
        var c = "fake";
        </wxs>

04.运算符
    a.基本运算符
        加法(+)、减法(-)、乘法(*)、除法(/)、取余(%)。
    b.一元运算符
        自增(++)、自减(--)、正值(+)、负值(-)、否运算(~)、取反运算(!)。
    c.位运算符
        左移(<<)、右移(>>)、无符号右移(>>>)、与(&)、异或(^)、或(|)。
    d.比较运算符
        小于(<)、大于(>)、小于等于(<=)、大于等于(>=)。
    e.等值运算符
        等号(==)、非等号(!=)、全等号(===)、非全等号(!==)。
    f.赋值运算符
        =, +=, -=, *=, /=, %=, <<=, >>=, >>>=, &=, ^=, |=。
    g.二元逻辑运算符
        逻辑与(&&)、逻辑或(||)。
    h.其他运算符
        条件运算符(?:)、逗号运算符(,)。
    i.运算符优先级
        优先级从高到低,括号最高,逗号最低。

05.语句
    a.if 语句
        a.功能说明
            在 WXS 中,if 语句用于根据表达式的值(truthy 或 falsy)来决定是否执行某段代码。
        b.语法格式
            a.if 语句
                if (表达式) 语句;

                if (表达式)
                  语句;

                if (表达式) {
                  代码块;
                }
            b.if...else 语句
                if (表达式) 语句;
                else 语句;

                if (表达式)
                  语句;
                else
                  语句;

                if (表达式) {
                  代码块;
                } else {
                  代码块;
                }
            c.if...else if...else 语句
                if (表达式) {
                  代码块;
                } else if (表达式) {
                  代码块;
                } else if (表达式) {
                  代码块;
                } else {
                  代码块;
                }
        c.示例代码
            var value = 10;

            if (value > 10) {
              console.log("Value is greater than 10");
            } else if (value === 10) {
              console.log("Value is equal to 10");
            } else {
              console.log("Value is less than 10");
            }
        d.输出
            Value is equal to 10
    b.switch 语句
        a.功能说明
            switch 语句用于根据表达式的值匹配 case 分支,并执行对应的代码块。
        b.语法格式
            switch (表达式) {
              case 变量:
                语句;
              case 数字:
                语句;
                break;
              case 字符串:
                语句;
              default:
                语句;
            }
            -------------------------------------------------------------------------------------------------
            default 分支可以省略。
            case 关键词后面只能使用变量、数字或字符串。
        c.示例代码
            var exp = 10;

            switch (exp) {
            case "10":
              console.log("string 10");
              break;
            case 10:
              console.log("number 10");
              break;
            case exp:
              console.log("var exp");
              break;
            default:
              console.log("default");
            }
        d.输出
            number 10
    c.for 语句
        a.功能说明
            for 语句用于循环执行代码块,直到条件表达式为 false。
        b.语法格式
            for (初始化; 条件; 迭代) 语句;

            for (初始化; 条件; 迭代) {
              代码块;
            }
            -------------------------------------------------------------------------------------------------
            支持使用 break 和 continue 关键词。
        c.示例代码
            for (var i = 0; i < 3; ++i) {
              console.log(i);
              if (i >= 1) break;
            }
        d.输出
            0
            1
    d.while 语句
        a.功能说明
            while 语句用于在表达式为 true 时,循环执行代码块。
        b.语法格式
            while (表达式)
              语句;

            while (表达式) {
              代码块;
            }

            do {
              代码块;
            } while (表达式);
            -------------------------------------------------------------------------------------------------
            支持使用 break 和 continue 关键词。
        c.示例代码
            var i = 0;

            while (i < 3) {
              console.log(i);
              i++;
            }

            do {
              console.log(i);
              i--;
            } while (i > 0);
        d.输出
            0
            1
            2
            3
            2
            1

06.数据类型
    a.汇总
        a.数据类型
            number:数值。
            string:字符串。
            boolean:布尔值。
            object:对象。
            function:函数。
            array:数组。
            date:日期。
            regexp:正则。
        b.数据类型判断
            使用 constructor 属性或 typeof 关键字。
    b.number
        a.语法,包括两种数值:整数和小数
            var a = 10;
            var PI = 3.141592653589793;
        b.属性
            constructor:返回字符串 "Number"。
        c.方法
            toString
            toLocaleString
            valueOf
            toFixed
            toExponential
            toPrecision
    c.string
        a.语法,有两种写法
            'hello world';
            "hello world";
        b.属性
            constructor:返回字符串 "String"。
            length:字符串长度。
        c.方法
            toString
            valueOf
            charAt
            charCodeAt
            concat
            indexOf
            lastIndexOf
            localeCompare
            match
            replace
            search
            slice
            split
            substring
            toLowerCase
            toLocaleLowerCase
            toUpperCase
            toLocaleUpperCase
            trim
    d.boolean
        a.语法
            布尔值只有两个特定的值:true 和 false。
        b.属性
            constructor:返回字符串 "Boolean"。
        c.方法
            toString
            valueOf
    e.object
        a.语法
            object 是一种无序的键值对。
            -------------------------------------------------------------------------------------------------
            var o = {}; //生成一个新的空对象
            o = {
              'string': 1,  //key 可以是字符串
              const_var: 2, //key 可以是标识符
              func: {},     //value 可以是任何类型
            };
            console.log(1 === o['string']);
            console.log(2 === o.const_var);
        b.属性
            constructor:返回字符串 "Object"。
        c.方法
            toString:返回字符串 "[object Object]"
    f.function
        a.语法
            方法 1:
            function a(x) {
              return x;
            }
            -------------------------------------------------------------------------------------------------
            方法 2:
            var b = function(x) {
              return x;
            }
            -------------------------------------------------------------------------------------------------
            支持匿名函数和闭包:
            var a = function(x) {
              return function() { return x; }
            }
            var b = a(100);
            console.log(100 === b());
        b.arguments
            length:传递给函数的参数个数。
            [index]:通过 index 下标遍历参数。
            -------------------------------------------------------------------------------------------------
            var a = function() {
              console.log(3 === arguments.length);
              console.log(100 === arguments[0]);
              console.log(200 === arguments[1]);
              console.log(300 === arguments[2]);
            };
            a(100, 200, 300);
        c.属性
            constructor:返回字符串 "Function"。
            length:返回函数的形参个数。
        d.方法
            toString:返回字符串 "[function Function]"
    g.array
        a.语法
            支持以下定义方式:
            var a = []; //生成一个新的空数组
            var a = [1, "2", {}, function(){}]; //生成一个新的非空数组
        b.属性
            constructor:返回字符串 "Array"。
            length:数组长度。
        c.方法
            toString
            concat
            join
            pop
            push
            reverse
            shift
            slice
            sort
            splice
            unshift
            indexOf
            lastIndexOf
            every
            some
            forEach
            map
            filter
            reduce
            reduceRight
    h.date
        a.语法
            使用 getDate 函数生成 date 对象。
            -------------------------------------------------------------------------------------------------
            var date = getDate(); //返回当前时间对象
            date = getDate(1500000000000);
            date = getDate('2017-7-14');
            date = getDate(2017, 6, 14, 10, 40, 0, 0);
        b.属性
            constructor:返回字符串 "Date"。
        c.方法
            toString
            toDateString
            toTimeString
            toLocaleString
            toLocaleDateString
            toLocaleTimeString
            valueOf
            getTime
            getFullYear
            getUTCFullYear
            getMonth
            getUTCMonth
            getDate
            getUTCDate
            getDay
            getUTCDay
            getHours
            getUTCHours
            getMinutes
            getUTCMinutes
            getSeconds
            getUTCSeconds
            getMilliseconds
            getUTCMilliseconds
            getTimezoneOffset
            setTime
            setMilliseconds
            setUTCMilliseconds
            setSeconds
            setUTCSeconds
            setMinutes
            setUTCMinutes
            setHours
            setUTCHours
            setDate
            setUTCDate
            setMonth
            setUTCMonth
            setFullYear
            setUTCFullYear
            toUTCString
            toISOString
            toJSON
    i.regexp
        a.语法
            使用 getRegExp 函数生成 regexp 对象。
            -------------------------------------------------------------------------------------------------
            var a = getRegExp("x", "img");
            console.log("x" === a.source);
            console.log(true === a.global);
            console.log(true === a.ignoreCase);
            console.log(true === a.multiline);
        b.属性
            constructor:返回字符串 "RegExp"。
            source
            global
            ignoreCase
            multiline
            lastIndex
        c.方法
            exec
            test
            toString
    j.数据类型判断
        a.constructor 属性
            使用 constructor 属性判断数据类型
            -------------------------------------------------------------------------------------------------
            var number = 10;
            console.log("Number" === number.constructor);

            var string = "str";
            console.log("String" === string.constructor);

            var boolean = true;
            console.log("Boolean" === boolean.constructor);

            var object = {};
            console.log("Object" === object.constructor);

            var func = function(){};
            console.log("Function" === func.constructor);

            var array = [];
            console.log("Array" === array.constructor);

            var date = getDate();
            console.log("Date" === date.constructor);

            var regexp = getRegExp();
            console.log("RegExp" === regexp.constructor);
        b.typeof
            使用 typeof 区分部分数据类型
            -------------------------------------------------------------------------------------------------
            var number = 10;
            var boolean = true;
            var object = {};
            var func = function(){};
            var array = [];
            var date = getDate();
            var regexp = getRegExp();
            console.log('number' === typeof number);
            console.log('boolean' === typeof boolean);
            console.log('object' === typeof object);
            console.log('function' === typeof func);
            console.log('object' === typeof array);
            console.log('object' === typeof date);
            console.log('object' === typeof regexp);
            console.log('undefined' === typeof undefined);
            console.log('object' === typeof null);

07.基础类库
    a.console
        console.log 方法用于在 console 窗口输出信息。它可以接受多个参数,将它们的结果连接起来输出
    b.Math
        属性:E, LN10, LN2, LOG2E, LOG10E, PI, SQRT1_2, SQRT2
        方法:abs, acos, asin, atan, atan2, ceil, cos, exp, floor, log, max, min, pow, random, round, sin, sqrt, tan
        -----------------------------------------------------------------------------------------------------
        以上属性的具体使用请参考 ES5 标准
    c.JSON
        方法:stringify(object): 将 object 对象转换为 JSON 字符串,并返回该字符串
        方法:parse(string): 将 JSON 字符串转化成对象,并返回该对象
        -----------------------------------------------------------------------------------------------------
        console.log(undefined === JSON.stringify());
        console.log(undefined === JSON.stringify(undefined));
        console.log("null"===JSON.stringify(null));

        console.log("111"===JSON.stringify(111));
        console.log('"111"'===JSON.stringify("111"));
        console.log("true"===JSON.stringify(true));
        console.log(undefined===JSON.stringify(function(){}));


        console.log(undefined===JSON.parse(JSON.stringify()));
        console.log(undefined===JSON.parse(JSON.stringify(undefined)));
        console.log(null===JSON.parse(JSON.stringify(null)));

        console.log(111===JSON.parse(JSON.stringify(111)));
        console.log("111"===JSON.parse(JSON.stringify("111")));
        console.log(true===JSON.parse(JSON.stringify(true)));

        console.log(undefined===JSON.parse(JSON.stringify(function(){})));
        -----------------------------------------------------------------------------------------------------
        以上属性的具体使用请参考 ES5 标准
    d.Number
        属性:MAX_VALUE, MIN_VALUE, NEGATIVE_INFINITY, POSITIVE_INFINITY
        -----------------------------------------------------------------------------------------------------
        以上属性的具体使用请参考 ES5 标准
    e.Date
        属性:parse, UTC, now
        -----------------------------------------------------------------------------------------------------
        以上属性的具体使用请参考 ES5 标准
    f.Global
        属性:NaN, Infinity, undefined
        方法:parseInt, parseFloat, isNaN, isFinite, decodeURI, decodeURIComponent, encodeURI, encodeURIComponent。
        -----------------------------------------------------------------------------------------------------
        以上属性的具体使用请参考 ES5 标准

1.13 [4]语法:WXML

00.汇总
    01.介绍
    02.数据绑定
    03.列表渲染
    04.条件渲染
    05.模板
    06.引用

01.介绍
    a.功能说明
        WXML(WeiXin Markup Language)是框架设计的一套标签语言,结合基础组件、事件系统,可以构建出页面的结构。
    b.示例功能
        a.数据绑定
            <!--wxml-->
            <view> {{message}} </view>
            // page.js
            Page({
              data: {
                message: 'Hello MINA!'
              }
            })
        b.列表渲染
            <!--wxml-->
            <view wx:for="{{array}}"> {{item}} </view>
            // page.js
            Page({
              data: {
                array: [1, 2, 3, 4, 5]
              }
            })
        c.条件渲染
            <!--wxml-->
            <view wx:if="{{view == 'WEBVIEW'}}"> WEBVIEW </view>
            <view wx:elif="{{view == 'APP'}}"> APP </view>
            <view wx:else="{{view == 'MINA'}}"> MINA </view>
            // page.js
            Page({
              data: {
                view: 'MINA'
              }
            })
        d.模板
            <!--wxml-->
            <template name="staffName">
              <view>
                FirstName: {{firstName}}, LastName: {{lastName}}
              </view>
            </template>

            <template is="staffName" data="{{...staffA}}"></template>
            <template is="staffName" data="{{...staffB}}"></template>
            <template is="staffName" data="{{...staffC}}"></template>
            // page.js
            Page({
              data: {
                staffA: {firstName: 'Hulk', lastName: 'Hu'},
                staffB: {firstName: 'Shang', lastName: 'You'},
                staffC: {firstName: 'Gideon', lastName: 'Lin'}
              }
            })
    c.具体能力
        数据绑定、列表渲染、条件渲染、模板、引用。

02.数据绑定
    a.功能说明
        WXML 中的动态数据均来自对应 Page 的 data。
    b.简单绑定
        a.内容
            <view> {{ message }} </view>
            Page({
              data: {
                message: 'Hello MINA!'
              }
            })
        b.组件属性
            <view id="item-{{id}}"> </view>
            Page({
              data: {
                id: 0
              }
            })
        c.控制属性
            <view wx:if="{{condition}}"> </view>
            Page({
              data: {
                condition: true
              }
            })
        d.关键字
            true:boolean 类型的 true,代表真值。
            false:boolean 类型的 false,代表假值。
            <checkbox checked="{{false}}"> </checkbox>
    c.运算
        a.三元运算
            <view hidden="{{flag ? true : false}}"> Hidden </view>
        b.算数运算
            <view> {{a + b}} + {{c}} + d </view>
            Page({
              data: {
                a: 1,
                b: 2,
                c: 3
              }
            })
        c.逻辑判断
            <view wx:if="{{length > 5}}"> </view>
        d.字符串运算
            <view>{{"hello" + name}}</view>
            Page({
              data:{
                name: 'MINA'
              }
            })
        e.数据路径运算
            <view>{{object.key}} {{array[0]}}</view>
            Page({
              data: {
                object: {
                  key: 'Hello '
                },
                array: ['MINA']
              }
            })
    d.组合
        a.数组
            <view wx:for="{{[zero, 1, 2, 3, 4]}}"> {{item}} </view>
            Page({
              data: {
                zero: 0
              }
            })
        b.对象
            <template is="objectCombine" data="{{foo: a, bar: b}}"></template>
            Page({
              data: {
                a: 1,
                b: 2
              }
            })
        c.扩展运算符
            <template is="objectCombine" data="{{...obj1, ...obj2, e: 5}}"></template>
            Page({
              data: {
                obj1: {
                  a: 1,
                  b: 2
                },
                obj2: {
                  c: 3,
                  d: 4
                }
              }
            })
        d.间接表达
            <template is="objectCombine" data="{{foo, bar}}"></template>
            Page({
              data: {
                foo: 'my-foo',
                bar: 'my-bar'
              }
            })
        e.覆盖规则
            <template is="objectCombine" data="{{...obj1, ...obj2, a, c: 6}}"></template>
            Page({
              data: {
                obj1: {
                  a: 1,
                  b: 2
                },
                obj2: {
                  b: 3,
                  c: 4
                },
                a: 5
              }
            })
        f.注意事项
            花括号和引号之间如果有空格,将最终被解析成为字符串。

03.列表渲染
    a.wx:for
        a.功能
            在组件上使用 wx:for 控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。
        b.示例代码
            <view wx:for="{{array}}">
              {{index}}: {{item.message}}
            </view>
            Page({
              data: {
                array: [{
                  message: 'foo',
                }, {
                  message: 'bar'
                }]
              }
            })
        c.嵌套示例
            <view wx:for="{{[1, 2, 3, 4, 5, 6, 7, 8, 9]}}" wx:for-item="i">
              <view wx:for="{{[1, 2, 3, 4, 5, 6, 7, 8, 9]}}" wx:for-item="j">
                <view wx:if="{{i <= j}}">
                  {{i}} * {{j}} = {{i * j}}
                </view>
              </view>
            </view>
    b.block wx:for
        a.功能
            将 wx:for 用在 <block/> 标签上,以渲染一个包含多节点的结构块。
        b.示例代码
            <block wx:for="{{[1, 2, 3]}}">
              <view> {{index}}: </view>
              <view> {{item}} </view>
            </block>
    c.wx:key
        a.功能
            指定列表中项目的唯一标识符。
        b.示例代码
            <switch wx:for="{{objectArray}}" wx:key="unique" style="display: block;"> {{item.id}} </switch>
            <button bindtap="switch"> Switch </button>
            <button bindtap="addToFront"> Add to the front </button>
        c.注意事项
            当 wx:for 的值为字符串时,会将字符串解析成字符串数组。

04.条件渲染
    a.wx:if
        a.功能
            使用 wx:if="" 来判断是否需要渲染该代码块。
        b.示例代码
            <view wx:if="{{condition}}"> True </view>
        c.使用 wx:elif 和 wx:else
            <view wx:if="{{length > 5}}"> 1 </view>
            <view wx:elif="{{length > 2}}"> 2 </view>
            <view wx:else> 3 </view>
    b.block wx:if
        a.功能
            使用 <block/> 标签将多个组件包装起来,并在上边使用 wx:if 控制属性。
        b.示例代码
            <block wx:if="{{true}}">
              <view> view1 </view>
              <view> view2 </view>
            </block>
    c.wx:if vs hidden
        a.比较
            wx:if 有更高的切换消耗而 hidden 有更高的初始渲染消耗。
            如果需要频繁切换的情景下,用 hidden 更好;如果在运行时条件不大可能改变则 wx:if 较好。

05.模板
    a.定义模板
        a.说明
            使用 name 属性,作为模板的名字。
        b.示例代码
            <template name="msgItem">
              <view>
                <text> {{index}}: {{msg}} </text>
                <text> Time: {{time}} </text>
              </view>
            </template>
    b.使用模板
        a.说明
            使用 is 属性,声明需要的使用的模板。
        b.示例代码
            <template is="msgItem" data="{{...item}}"/>
            Page({
              data: {
                item: {
                  index: 0,
                  msg: 'this is a template',
                  time: '2016-09-15'
                }
              }
            })
        c.动态渲染模板
            <template name="odd">
              <view> odd </view>
            </template>
            <template name="even">
              <view> even </view>
            </template>

            <block wx:for="{{[1, 2, 3, 4, 5]}}">
              <template is="{{item % 2 == 0 ? 'even' : 'odd'}}"/>
            </block>
    c.模板的作用域
        模板拥有自己的作用域,只能使用 data 传入的数据以及模板定义文件中定义的 <wxs /> 模块。

06.引用
    a.import
        a.功能
            import可以在该文件中使用目标文件定义的template
        b.在 item.wxml 中定义了一个叫item的template
            <!-- item.wxml -->
            <template name="item">
              <text>{{text}}</text>
            </template>
        c.在 index.wxml 中引用了 item.wxml,就可以使用item模板
            <import src="item.wxml"/>
            <template is="item" data="{{text: 'forbar'}}"/>
    b.import 的作用域
        a.说明
            import 有作用域的概念,即只会 import 目标文件中定义的 template,而不会 import 目标文件 import 的 template。
        b.示例
            C import B,B import A,在C中可以使用B定义的template,在B中可以使用A定义的template,但是C不能使用A定义的template。
            -------------------------------------------------------------------------------------------------
            <!-- A.wxml -->
            <template name="A">
              <text> A template </text>
            </template>
            -------------------------------------------------------------------------------------------------
            <!-- B.wxml -->
            <import src="a.wxml"/>
            <template name="B">
              <text> B template </text>
            </template>
            -------------------------------------------------------------------------------------------------
            <!-- C.wxml -->
            <import src="b.wxml"/>
            <template is="A"/>  <!-- Error! Can not use tempalte when not import A. -->
            <template is="B"/>
    c.include
        a.功能
            将目标文件除了 <template/> <wxs/> 外的整个代码引入。
        b.示例代码
            include 可以将目标文件除了 <template/> <wxs/> 外的整个代码引入,相当于是拷贝到 include 位置,
            -------------------------------------------------------------------------------------------------
            <!-- index.wxml -->
            <include src="header.wxml"/>
            <view> body </view>
            <include src="footer.wxml"/>
            -------------------------------------------------------------------------------------------------
            <!-- header.wxml -->
            <view> header </view>
            -------------------------------------------------------------------------------------------------
            <!-- footer.wxml -->
            <view> footer </view>

1.14 [4]示例:travel模块

00.汇总
    01.四大组件
    02.组件示例

01.四大组件
    a.汇总
        四者的关系可以用“房子”来类比四者的协同:
        index.wxml = 房子的“框架结构”(墙、窗、门的位置)
        index.wxss = 房子的“装修风格”(墙的颜色、地板材质、家具样式)
        index.js = 房子的“控制系统”(灯光开关、空调调节、门锁响应)
        index.json = 房子的“基础设置”(门牌号、窗户大小、是否装防盗网)
    b.index.wxml:页面的“结构视图”文件(相当于网页的 HTML)
        a.说明
            wxml 是微信小程序的模板语言文件,负责定义页面的“骨架”——即用户能看到的所有元素(如文字、按钮、图片、列表等),
            类似网页开发中的 HTML,但语法和标签更贴合小程序特性。
        b.核心作用
            搭建页面布局:通过小程序专属标签(如 <view>、<text>、<button>)组织页面结构;
            数据绑定:通过 {{ 数据名 }} 语法将 index.js 中定义的“数据”渲染到页面上;
            事件绑定:通过 bindtap、bindinput 等属性,将页面操作(如点击按钮、输入文字)与 index.js 中的“事件函数”关联;
            条件渲染/列表渲染:通过 wx:if(条件显示)、wx:for(循环生成列表)等指令实现动态页面效果。
        c.简单示例
            <!-- index.wxml -->
            <!-- 1. 数据绑定:渲染 js 中的 "pageTitle" 数据 -->
            <view class="title">{{ pageTitle }}</view>

            <!-- 2. 事件绑定:点击按钮触发 js 中的 "handleClick" 函数 -->
            <button bindtap="handleClick">点击我</button>

            <!-- 3. 列表渲染:循环渲染 js 中的 "list" 数组 -->
            <view class="list">
              <view wx:for="{{ list }}" wx:key="index">
                第{{ index+1 }}项:{{ item }}
              </view>
            </view>
    c.index.wxss:页面的“样式美化”文件(相当于网页的 CSS)
        a.说明
            wxss 是微信小程序的样式表文件,负责定义 index.wxml 中元素的外观(如颜色、大小、间距、布局方式等),
            类似网页开发中的 CSS,但增加了小程序专属特性(如 rpx 自适应单位)。
        b.核心作用
            美化页面元素:设置字体大小、颜色、背景色、边框等基础样式;
            控制布局:通过 flex、position 等属性调整元素在页面中的位置;
            自适应适配:使用小程序专属单位 rpx(自动适配不同屏幕宽度,1rpx ≈ 屏幕宽度/750),无需手动适配不同手机;
            样式作用域:index.wxss 的样式 仅对当前 index 页面生效,不会影响其他页面(避免样式冲突)。
        c.简单示例
            /* index.wxss */
            /* 给 "title" 类的元素设置样式 */
            .title {
              font-size: 32rpx; /* 自适应字体大小 */
              color: #333; /* 文字颜色 */
              margin: 20rpx 0; /* 上下间距 */
              text-align: center; /* 文字居中 */
            }

            /* 给按钮设置样式 */
            button {
              background-color: #07c160; /* 微信绿 */
              color: white;
              padding: 15rpx 30rpx;
              border-radius: 50rpx; /* 圆角 */
            }
    d.index.js:页面的“逻辑控制”文件(相当于网页的 JavaScript)
        a.说明
            index.js 是页面的逻辑处理核心,负责管理页面的“数据”、“事件响应”、“生命周期”等,
            是页面实现交互功能的关键(如点击按钮后更新内容、加载数据、跳转页面等)。
        b.核心作用
            管理页面数据:通过 Page({ data: { ... } }) 定义页面需要渲染的数据(如 pageTitle、list),数据变化时通过 this.setData({ ... }) 更新(更新后会自动同步到 index.wxml);
            处理用户交互:定义 handleClick、handleInput 等事件函数,响应 index.wxml 中绑定的点击、输入等操作;
            控制页面生命周期:小程序页面有一套固定的“生命周期钩子”(如页面加载、显示、隐藏时触发的函数),可在 index.js 中定义这些钩子,实现初始化数据、清理资源等逻辑;
            调用小程序 API:通过 wx.xxx 调用微信提供的原生 API(如跳转页面 wx.navigateTo、获取用户信息 wx.getUserProfile、发起网络请求 wx.request 等)。
        c.简单示例
            // index.js
            // 页面逻辑入口:通过 Page() 函数注册页面
            Page({
              // 1. 页面初始数据(会渲染到 wxml 中)
              data: {
                pageTitle: "我的首页",
                list: ["苹果", "香蕉", "橙子"] // 用于 wxml 循环渲染
              },

              // 2. 事件函数:响应按钮点击(与 wxml 中的 bindtap 绑定)
              handleClick() {
                // 更新数据:修改 pageTitle,并同步到 wxml
                this.setData({
                  pageTitle: "点击后的首页"
                });

                // 调用小程序 API:弹出提示框
                wx.showToast({
                  title: "按钮被点击啦!",
                  icon: "none"
                });
              },

              // 3. 生命周期钩子:页面加载时触发(仅触发一次)
              onLoad(options) {
                console.log("页面加载完成,可在这里初始化数据");
                // 示例:发起网络请求,获取数据后更新 list
                // wx.request({
                //   url: "https://xxx.com/api/list",
                //   success: (res) => {
                //     this.setData({ list: res.data });
                //   }
                // });
              },

              // 生命周期钩子:页面显示时触发(每次进入页面都会触发)
              onShow() {
                console.log("页面显示了");
              }
            });
    e.index.json:页面的“配置”文件(控制页面基础属性)
        a.说明
            index.json 是页面的配置文件,用于设置当前页面的“窗口样式”、“导航栏标题”、“是否允许下拉刷新”等基础属性,
            配置项会覆盖全局配置(app.json)中对应的项。
        b.核心作用
            配置导航栏:设置导航栏标题文字(navigationBarTitleText)、背景色(navigationBarBackgroundColor)、文字颜色(navigationBarTextStyle);
            控制页面窗口:设置是否允许下拉刷新(enablePullDownRefresh)、页面背景色(backgroundColor)、下拉刷新时的 loading 样式(backgroundTextStyle);
            配置页面路由:若页面需要接收其他页面跳转时传递的参数,可在此配置路由相关规则(较少用,通常在 app.json 的 pages 中配置页面路径);
            页面单独配置:每个页面的 json 配置仅对当前页面生效,可实现“不同页面不同导航栏样式”(如首页导航栏是红色,详情页是蓝色)。
        c.简单示例
            {
              "navigationBarTitleText": "首页", // 导航栏标题
              "navigationBarBackgroundColor": "#07c160", // 导航栏背景色(微信绿)
              "navigationBarTextStyle": "white", // 导航栏文字颜色(仅支持 black/white)
              "enablePullDownRefresh": true, // 允许下拉刷新
              "backgroundColor": "#f5f5f5", // 页面背景色
              "backgroundTextStyle": "dark" // 下拉刷新 loading 颜色(仅支持 dark/light)
            }

02.组件示例
    a.index.js
        // 出差申请页面 - 功能开发中
        Page({
          data: {
            pageTitle: '出差申请'
          },

          onLoad() {
            // 页面加载
          },

          // 返回工作台
          goBack() {
            wx.navigateBack({
              fail: () => {
                // 如果无法返回,跳转到工作台
                wx.switchTab({
                  url: '/pages/app/work/index'
                })
              }
            })
          }
        })
    b.index.json
        {
          "navigationBarTitleText": "出差申请",
          "usingComponents": {
            "van-icon": "@vant/weapp/icon/index",
            "van-button": "@vant/weapp/button/index"
          }
        }
    c.index.wxml
        <!--出差申请页面-->
        <view class="dev-page-container">
          <!-- 开发中提示 -->
          <view class="dev-content">
            <view class="dev-icon">
              <van-icon name="location-o" size="120rpx" color="#cccccc" />
            </view>
            <view class="dev-title">出差申请</view>
            <view class="dev-subtitle">功能开发中</view>
            <view class="dev-description">该功能正在紧张开发中,敬请期待...</view>

            <!-- 返回按钮 -->
            <view class="dev-actions">
              <van-button type="primary" size="large" bind:tap="goBack">返回工作台</van-button>
            </view>
          </view>
        </view>
    d.index.wxss
        /* 功能开发中页面样式 */
        .dev-page-container {
          min-height: 100vh;
          background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
          display: flex;
          align-items: center;
          justify-content: center;
          padding: 40rpx;
        }

        .dev-content {
          background: white;
          border-radius: 24rpx;
          padding: 80rpx 60rpx;
          text-align: center;
          box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.1);
          max-width: 600rpx;
          width: 100%;
        }

        .dev-icon {
          margin-bottom: 40rpx;
        }

        .dev-title {
          font-size: 48rpx;
          font-weight: bold;
          color: #333333;
          margin-bottom: 16rpx;
        }

        .dev-subtitle {
          font-size: 32rpx;
          color: #999999;
          margin-bottom: 24rpx;
        }

        .dev-description {
          font-size: 28rpx;
          color: #666666;
          line-height: 1.6;
          margin-bottom: 60rpx;
        }

        .dev-actions {
          width: 100%;
        }

1.15 [5]API:开发接口

00.汇总
    a.登录
        wx.pluginLogin(Object args)       可以此凭证换取用于识别用户的标识 openpid
        wx.login(Object object)           调用接口获取登录凭证(code)
        wx.checkSession(Object object)    检查登录态 session_key 是否过期
    b.账号信息
        Object wx.getAccountInfoSync()    获取当前账号信息
    c.用户信息
        wx.getUserProfile(Object object)  获取用户信息。页面产生点击事件(例如 button 上 bindtap 的回调中)后才可调用,每次请求都会弹出授权窗口,用户同意后返回 userInfo。该接口用于替换 wx.getUserInfo
        wx.getUserInfo(Object object)     获取用户信息
        UserInfo                          用户昵称、用户头像图片的URL、用户性别、用户所在国家、用户所在省份、用户所在城市
    d.授权
        

    
01.登录
	a.wx.pluginLogin(Object args)
		a.功能说明
			该接口仅在小程序插件中可调用,调用接口获得插件用户标志凭证(code)。
			插件可以此凭证换取用于识别用户的标识 openpid。
			用户不同、宿主小程序不同或插件不同的情况下,该标识均不相同,即当且仅当同一个用户在同一个宿主小程序中使用同一个插件时,openpid 才会相同。
		b.支持情况
			基础库 2.20.1 开始支持,低版本需做兼容处理。
			以 Promise 风格 调用:不支持
			小程序插件:支持,需要小程序基础库版本不低于 2.20.1
			微信 Windows 版:支持
			微信 鸿蒙 OS 版:支持
		c.参数说明
			a.Object args
				success:接口调用成功的回调函数。
				fail:接口调用失败的回调函数。
				complete:接口调用结束的回调函数(调用成功、失败都会执行)。
			b.args.success 回调函数
				参数:Object res
				code:用于换取 openpid 的凭证(有效期五分钟)
		d.示例代码
			wx.pluginLogin({
			  success(res) {
				console.log('Code:', res.code);
				// 在开发者服务器后台调用 getPluginOpenPId 换取 openpid
			  },
			  fail(err) {
				console.error('Plugin login failed:', err);
			  },
			  complete() {
				console.log('Plugin login completed.');
			  }
			});
	b.wx.login(Object object)
		a.功能说明
			调用接口获取登录凭证(code)
			通过凭证进而换取用户登录态信息,包括用户在当前小程序的唯一标识(openid)、微信开放平台账号下的唯一标识(unionid,若当前小程序已绑定到微信开放平台账号)及本次登录的会话密钥(session_key)等。
			用户数据的加解密通讯需要依赖会话密钥完成。
		b.支持情况
			以 Promise 风格 调用:不支持
			小程序插件:支持,需要小程序基础库版本不低于 2.3.1
			在小程序插件中使用时,需要在用户信息功能页中获得用户授权或满足一定条件后调用。否则将返回 fail。详见 用户信息功能页
			微信 Windows 版:支持
			微信 Mac 版:支持
			微信 鸿蒙 OS 版:支持
			相关文档: 小程序登录、UnionID 机制说明、接口调用频率规范
		c.参数说明
			a.Object object
				timeout:超时时间,单位 ms。
				success:接口调用成功的回调函数。
				fail:接口调用失败的回调函数。
				complete:接口调用结束的回调函数(调用成功、失败都会执行)。
			b.object.success 回调函数
				参数:Object res
				属性:code:用户登录凭证(有效期五分钟)。
			c.object.fail 回调函数
				参数:Object err
				属性:errMsg:错误信息。
					 errno:错误码(基础库 2.24.0 起支持)。
		d.示例代码
			wx.login({
			  success(res) {
				if (res.code) {
				  // 发起网络请求
				  wx.request({
					url: 'https://example.com/onLogin',
					data: {
					  code: res.code
					}
				  });
				} else {
				  console.log('登录失败!' + res.errMsg);
				}
			  },
			  fail(err) {
				console.error('Login failed:', err);
			  },
			  complete() {
				console.log('Login completed.');
			  }
			});
	c.wx.checkSession(Object object)
		a.功能说明
			检查登录态 session_key 是否过期。
			session_key 具有唯一性,在使用小程序时,同一用户在同一时刻仅有一个有效的 session_key。
			通过 wx.login 接口获得的用户登录态拥有一定的时效性。用户越久未使用小程序,用户登录态越有可能过期。反之如果用户一直在使用小程序,则用户登录态一直保持有效。具体时效逻辑由微信维护,对开发者透明。除了过期失效外,触发获取临时登录凭证 code 的操作(小程序登录 和 数据预拉取)可能会生成新的登录态session_key,从而使旧的 session_key 被顶替而失效。
			开发者可以调用 wx.checkSession 接口检测用户登录态是否过期。注意,wx.checkSession 的校验对象是最后一次获取 code 操作对应的登录态 session_key,调用成功说明该 session_key 未过期,调用失败说明 session_key 已过期。如果要校验指定的 session_key 是否有效,可以在开发者服务器后台调用 checkSessionKey。
			登录态失效后开发者可以再调用 wx.login 获取新的用户登录态。
		b.支持情况
			以 Promise 风格 调用:支持
			小程序插件:不支持
			微信 Windows 版:支持
			微信 Mac 版:支持
			相关文档: 小程序登录、接口调用频率规范
		c.参数说明
			a.Object object
				success:接口调用成功的回调函数。
				fail:接口调用失败的回调函数。
				complete:接口调用结束的回调函数(调用成功、失败都会执行)。
		d.示例代码
			wx.checkSession({
			  success() {
				// session_key 未过期,并且在本生命周期一直有效
				console.log('Session key is valid.');
			  },
			  fail() {
				// session_key 已经失效,需要重新执行登录流程
				console.log('Session key expired. Re-login required.');
				wx.login(); // 重新登录
			  },
			  complete() {
				console.log('Check session completed.');
			  }
			});

02.账号信息
    a.Object wx.getAccountInfoSync()
        a.功能说明
            获取当前账号信息。线上小程序版本号仅支持在正式版小程序中获取,开发版和体验版中无法获取。
        b.支持情况
            基础库 2.2.2 开始支持,低版本需做兼容处理。
            小程序插件:支持,需要小程序基础库版本不低于 2.2.2
            微信 Windows 版:支持
            微信 Mac 版:支持
            微信 鸿蒙 OS 版:支持
        c.返回值
            a.Object
                账号信息
            b.属性说明
                a.miniProgram
                    类型:Object
                    描述:小程序账号信息
                    结构属性:appId:string,小程序 appId
                            envVersion:string,小程序版本(基础库 2.10.0 起支持)
                            version:string,线上小程序版本号(基础库 2.10.2 起支持)
                b.plugin
                    类型:Object
                    描述:插件账号信息(仅在插件中调用时包含这一项)
                    结构属性:appId:string,插件 appId。
                            version:string,插件版本号(格式为 'a.b.c')
        d.示例代码
            const accountInfo = wx.getAccountInfoSync();
            console.log(accountInfo.miniProgram.appId); // 小程序 appId
            console.log(accountInfo.miniProgram.envVersion); // 小程序版本
            console.log(accountInfo.miniProgram.version); // 线上小程序版本号
            console.log(accountInfo.plugin.appId); // 插件 appId
            console.log(accountInfo.plugin.version); // 插件版本号,'a.b.c' 这样的形式

03.用户信息
    a.wx.getUserProfile(Object object)
        a.功能说明
            获取用户信息。
            页面产生点击事件(例如 button 上 bindtap 的回调中)后才可调用。
            每次请求都会弹出授权窗口,用户同意后返回 userInfo。
            用于替换 wx.getUserInfo,详见用户信息接口调整说明。
        b.支持情况
            基础库:2.10.4 起支持
            小程序插件:不支持
            微信 Windows 版:支持
            微信 鸿蒙 OS 版:支持
        c.参数说明
            a.Object object
                lang:显示用户信息的语言,默认值为 "en"。
                desc:声明获取用户个人信息后的用途,不超过30个字符,必填。
                success:接口调用成功的回调函数。
                fail:接口调用失败的回调函数。
                complete:接口调用结束的回调函数(调用成功、失败都会执行)。
            b.object.success 回调函数
                参数:Object res
                userInfo:用户信息对象(基础库 2.10.4 起支持)。
                rawData:不包括敏感信息的原始数据字符串,用于计算签名。
                signature:使用 sha1(rawData + sessionkey) 得到字符串,用于校验用户信息。
                encryptedData:包括敏感数据在内的完整用户信息的加密数据。
                iv:加密算法的初始向量。
                cloudID:敏感数据对应的云 ID,仅开通云开发的小程序返回。
        d.Bug & Tip
            a.说明
                tip:仅小程序中 wx.getUserInfo 接口进行调整,小游戏中不受影响。
                tip:开发者工具中仅 2.10.4 及以上版本可访问 wx.getUserProfile 接口。
                tip:wx.getUserProfile 返回的加密数据中不包含 openId 和 unionId 字段。
                bug:开发者工具中 2.10.4~2.16.1 基础库版本通过 <button open-type="getUserInfo"> 会返回真实数据,真机上此区间会按照公告返回匿名数据。
            b.代码示例
                <view class="container">
                  <view class="userinfo">
                    <block wx:if="{{!hasUserInfo}}">
                      <button wx:if="{{canIUseGetUserProfile}}" bindtap="getUserProfile"> 获取头像昵称 </button>
                      <button wx:else open-type="getUserInfo" bindgetuserinfo="getUserInfo"> 获取头像昵称 </button>
                    </block>
                    <block wx:else>
                      <image bindtap="bindViewTap" class="userinfo-avatar" src="{{userInfo.avatarUrl}}" mode="cover"></image>
                      <text class="userinfo-nickname">{{userInfo.nickName}}</text>
                    </block>
                  </view>
                </view>
                ---------------------------------------------------------------------------------------------
                Page({
                  data: {
                    userInfo: {},
                    hasUserInfo: false,
                    canIUseGetUserProfile: false,
                  },
                  onLoad() {
                    if (wx.getUserProfile) {
                      this.setData({
                        canIUseGetUserProfile: true
                      })
                    }
                  },
                  getUserProfile(e) {
                    // 推荐使用wx.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认
                    // 开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
                    wx.getUserProfile({
                      desc: '用于完善会员资料', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
                      success: (res) => {
                        this.setData({
                          userInfo: res.userInfo,
                          hasUserInfo: true
                        })
                      }
                    })
                  },
                  getUserInfo(e) {
                    // 不推荐使用getUserInfo获取用户信息,预计自2021年4月13日起,getUserInfo将不再弹出弹窗,并直接返回匿名的用户个人信息
                    this.setData({
                      userInfo: e.detail.userInfo,
                      hasUserInfo: true
                    })
                  },
                })
    b.wx.getUserInfo(Object object)
        a.功能说明
            获取用户信息。
            用户头像昵称获取规则已调整,详见用户信息接口调整说明。
            必须在用户授权的情况下调用。
            敏感数据(如 openId 和 unionId)需要通过加密数据解密算法或云调用直接获取开放数据。
        b.支持情况
            基础库:2.3.1 起支持。
            用户授权:需要 scope.userInfo。
            小程序插件:支持。
            微信 Windows 版:支持。
            微信 Mac 版:支持。
            微信 鸿蒙 OS 版:支持。
        c.参数说明
            a.Object object
                withCredentials:boolean,是否带上登录态信息。
                    true:要求此前调用过 wx.login 且登录态未过期,返回的数据包含 encryptedData 和 iv 等敏感信息。
                    false:不要求登录态,返回的数据不包含敏感信息。
                lang:string,显示用户信息的语言,默认值为 "en"。
                    en:英文。
                    zh_CN:简体中文。
                    zh_TW:繁体中文。
                success:接口调用成功的回调函数。
                fail:接口调用失败的回调函数。
                complete:接口调用结束的回调函数(调用成功、失败都会执行)。
            b.object.success 回调函数
                参数:Object res
                属性:
                userInfo:用户信息对象,不包含 openid 等敏感信息。
                rawData:不包括敏感信息的原始数据字符串,用于计算签名。
                signature:使用 sha1(rawData + sessionkey) 得到字符串,用于校验用户信息。
                encryptedData:包括敏感数据在内的完整用户信息的加密数据。
                iv:加密算法的初始向量。
                cloudID:敏感数据对应的云 ID,仅开通云开发的小程序返回(基础库 2.7.0 起支持)。
            c.示例代码
                // 必须是在用户已经授权的情况下调用
                wx.getUserInfo({
                  withCredentials: true, // 是否带上登录态信息
                  lang: 'zh_CN', // 显示用户信息的语言
                  success: function(res) {
                    var userInfo = res.userInfo;
                    var nickName = userInfo.nickName;
                    var avatarUrl = userInfo.avatarUrl;
                    var gender = userInfo.gender; // 性别 0:未知、1:男、2:女
                    var province = userInfo.province;
                    var city = userInfo.city;
                    var country = userInfo.country;
                    console.log('用户信息:', userInfo);
                  },
                  fail: function(err) {
                    console.error('获取用户信息失败:', err);
                  },
                  complete: function() {
                    console.log('获取用户信息完成');
                  }
                });
        d.敏感数据获取方式
            a.加密数据解密算法
                使用 encryptedData 和 iv 进行解密,获取敏感数据
            b.使用 云调用直接获取开放数据 获取得到的开放数据为以下 json 结构
                {
                  "openId": "OPENID",
                  "nickName": "NICKNAME",
                  "gender": GENDER,
                  "city": "CITY",
                  "province": "PROVINCE",
                  "country": "COUNTRY",
                  "avatarUrl": "AVATARURL",
                  "unionId": "UNIONID",
                  "watermark": {
                    "appid": "APPID",
                    "timestamp": TIMESTAMP
                  }
                }
        e.小程序用户信息组件示例代码
            a.代码1
                <!-- 如果只是展示用户头像昵称,可以使用 <open-data /> 组件 -->
                <open-data type="userAvatarUrl"></open-data>
                <open-data type="userNickName"></open-data>
                <!-- 需要使用 button 来授权登录 -->
                <button wx:if="{{canIUse}}" open-type="getUserInfo" bindgetuserinfo="bindGetUserInfo">授权登录</button>
                <view wx:else>请升级微信版本</view>
            b.代码2
                Page({
                  data: {
                    canIUse: wx.canIUse('button.open-type.getUserInfo')
                  },
                  onLoad: function() {
                    // 查看是否授权
                    wx.getSetting({
                      success(res) {
                        if (res.authSetting['scope.userInfo']) {
                          // 已经授权,可以直接调用 getUserInfo 获取头像昵称
                          wx.getUserInfo({
                            success: function(res) {
                              console.log(res.userInfo);
                            }
                          });
                        }
                      }
                    });
                  },
                  bindGetUserInfo(e) {
                    console.log(e.detail.userInfo);
                  }
                });
    c.UserInfo
        a.功能说明
            用户信息对象。
            用户头像昵称获取规则已调整,详见用户信息接口调整说明。
            部分字段已不再返回,详见相关公告。
        b.属性说明
            a.nickName
                类型:string
                描述:用户昵称。
            b.avatarUrl
                类型:string
                描述:用户头像图片的 URL。
                说明:
                    URL 最后一个数值代表正方形头像大小。
                    可选数值:0、46、64、96、132。
                        0:640x640 的正方形头像。
                        46:46x46 的正方形头像。
                        64:64x64 的正方形头像。
                        96:96x96 的正方形头像。
                        132:132x132 的正方形头像(默认)。
                    用户没有头像时该项为空。
                    若用户更换头像,原有头像 URL 将失效。
            c.gender
                类型:number
                描述:用户性别(不再返回,参考相关公告)。
                合法值:0:未知。1:男性。2:女性。
            d.country
                类型:string
                描述:用户所在国家(不再返回,参考相关公告)。
            e.province
                类型:string
                描述:用户所在省份(不再返回,参考相关公告)。
            f.city
                类型:string
                描述:用户所在城市(不再返回,参考相关公告)。
            g.language
                类型:string
                描述:显示 country,province,city 所用的语言。
                强制返回值:"zh_CN"(参考相关公告)。
                合法值:en:英文。zh_CN:简体中文。zh_TW:繁体中文。

04.授权
    a.
    
    
    

        
        



2 uniapp

2.1 nuve:原理

01.主要说明
    a.说明1
        uni-app App 端内置了一个基于 weex 改进的原生渲染引擎,提供了原生渲染能力。
        在 App 端,如果使用 vue 页面,则使用 webview 渲染;如果使用 nvue 页面(native vue 的缩写),则使用原生渲染。
        一个 App 中可以同时使用两种页面,比如首页使用 nvue,二级页使用 vue 页面,hello uni-app 示例就是如此。
    b.说明2
        虽然 nvue 也可以多端编译,输出 H5 和小程序,但 nvue 的 css 写法受限,所以如果你不开发 App,那么不需要使用 nvue。
        以往的 weex ,有个很大的问题是它只是一个高性能的渲染器,没有足够的 API 能力(比如各种 push sdk 集成、蓝牙等能力调用),
        使得开发时非常依赖原生工程师协作,开发者本来想节约成本,结果需要前端、iOS、Android 3 拨人开发,适得其反。
        nvue 解决了这个问题,让前端工程师可以直接开发完整 App,并提供丰富的插件生态和云打包。这些组合方案,帮助开发者切实的提高效率、降低成本。
    c.说明3
        同时uni-app扩展了 weex 原生渲染引擎的很多排版能力,修复了很多 bug。比如
        Android 端良好支持边框阴影,详情
        iOS 端支持高斯模糊,详情
        可实现区域滚动长列表+左右拖动列表+吸顶的复杂排版效果
        优化圆角边框绘制性能
        扩展了更多的 css

02.适用场景
    a.说明1
        nvue 的组件和 API 写法与 vue 页面一致,其内置组件还比 vue 页面内置组件增加了更多,详见。
        如果你熟悉 weex 或 react native 开发,那么 nvue 是你的更优选择,能切实提升你的开发效率,降低成本。
        如果你是 web 前端,不熟悉原生排版,那么建议你仍然以使用 vue 页面为主,
    b.说明2
        在 App 端某些 vue 页面表现不佳的场景下使用 nvue 作为强化补充。这些场景如下:
        需要高性能的区域长列表或瀑布流滚动。webview 的页面级长列表滚动是没有性能问题的(就是滚动条覆盖 webview 整体高度),但页面中某个区域做长列表滚动,则需要使用 nvue 的list、recycle-list、waterfall等组件(详见)。这些组件的性能要高于 vue 页面里的区域滚动组件scroll-view。
        复杂高性能的自定义下拉刷新。uni-app 的 pages.json 里可以配置原生下拉刷新,但引擎内置的下拉刷新样式只有雪花和 circle 圈 2 种样式。如果你需要自己做复杂的下拉刷新,推荐使用 nvue 的 refresh 组件。当然插件市场里也有很多 vue 下的自定义下拉刷新插件,只要是基于 renderjs 或 wxs 的,性能也可以商用,只是没有 nvue 的refresh组件更极致。
        左右拖动的长列表。在 webview 里,通过swiper+scroll-view实现左右拖动的长列表,前端模拟下拉刷新,这套方案的性能不好。此时推荐使用 nvue,比如新建 uni-app 项目时的新闻示例模板,就采用了 nvue,切换很流畅。
        实现区域滚动长列表+左右拖动列表+吸顶的复杂排版效果,效果可参考 hello uni-app 模板里的swiper-list

03.纯原生渲染模式
    a.说明
        uni-app 在 App 端,支持 vue 页面和 nvue 页面混搭、互相跳转。也支持纯 nvue 原生渲染。
        启用纯原生渲染模式,可以减少 App 端的包体积、减少使用时的内存占用。因为 webview 渲染模式的相关模块将被移除。
        在 manifest.json 源码视图的"app-plus"下配置"renderer":"native",即代表 App 端启用纯原生渲染模式。
        此时 pages.json 注册的 vue 页面将被忽略,vue 组件也将被原生渲染引擎来渲染。
    b.如果不指定该值,默认是不启动纯原生渲染的。
        // manifest.json
        {
           // ...
            // App平台特有配置
           "app-plus": {
              "renderer": "native", //App端纯原生渲染模式
           }
        }

04.编译模式
    a.说明
        weex 编译模式和 uni-app 编译模式
        如你之前是 weex 开发者,可以继续查阅本章节,否则可以跳过看下一节快速上手。
        weex 的组件和 JS API,与 uni-app 不同。uni-app 与微信小程序相同。
        考虑到 weex 用户的迁移,uni-app 也支持 weex 的代码写法。在 manifest.json 中可以配置使用weex 编译模式或uni-app 编译模式。
        选择 weex 编译模式时将不支持 uni-app 的组件和 jsapi,需要开发者参考 weex 官方文档的写法来写代码。
        比如 weex 编译模式用<div>。uni-app 编译模式则使用<view>。
        一般情况建议使用uni-app模式,除非历史 weex 代码较多,需要逐步过渡。
        同时注意 weex 编译模式的切换是项目级的,不支持同项目下某个 nvue 页面使用 weex 模式,另一个 nvue 页面使用 uni-app 模式。
    b.对比
        weex       编译模式                             uni-app 编译模式
        平台        仅 App                              所有端,包含小程序和 H5
        组件        weex 组件如 div                      uni-app 组件如 view
        生命周期     只支持 weex 生命周期                  支持所有 uni-app 生命周期
        JS API      weex API、uni API、Plus API         weex API、uni API、Plus API
        单位         750px 是屏幕宽度,wx 是固定像素单位    750rpx 是屏幕宽度,px 是固定像素单位
        全局样式     手动引入                             app.vue 的样式即为全局样式
        页面滚动     必须给页面套或组件                     默认支持页面滚动
    c.在 manifest.json 中修改 2 种编译模式,manifest.json -> app-plus -> nvueCompiler 切换编译模式。
        nvueCompiler 有两个值:
        weex
        uni-app
        -----------------------------------------------------------------------------------------------------
        // manifest.json
        {
            // ...
            // App平台特有配置
            "app-plus": {
                "nvueCompiler":"uni-app" //是否启用 uni-app 模式
            }
        }
        -----------------------------------------------------------------------------------------------------
        在 manifest.json 配置文件中,HBuilderX2.4 之前版本,默认值为 weex 模式,HBuilderX2.4+版本默认值改为 uni-app 模式。

2.2 nuve:页面

01.新建 nvue 页面
    在 HBuilderX 的 uni-app 项目中,新建页面,弹出界面右上角可以选择是建立vue页面还是nvue页面,或者 2 个同时建。
    不管是 vue 页面还是 nvue 页面,都需要在pages.json中注册。如果在 HBuilderX 中新建页面是会自动注册的,如果使用其他编辑器,则需要自行在 pages.json 里注册。
    如果一个页面路由下同时有 vue 页面和 nvue 页面,即出现同名的 vue 和 nvue 文件。那么在 App 端,会仅使用 nvue 页面,同名的 vue 文件将不会被编译到 App 端。而在非 App 端,会优先使用 vue 页面。
    如果不同名,只有 nvue 页面,则在非 app 端,只有 uni-app 编译模式的 nvue 文件才会编译。

02.开发 nvue 页面
    a.说明
        nvue 页面结构同 vue, 由 template、style、script 构成。
    b.template:模板写法、数据绑定同 vue。组件支持 2 种模式,
        weex 组件,同 weex 写法,参考:weex 内置组件;
        uni-app 组件,同 uni-app 写法。
        App 端 nvue 专用组件,详见https://uniapp.dcloud.io/component/barcode。
    c.style
        由于采用原生渲染,并非所有浏览器的 css 均支持,布局模型只支持 flex 布局,虽然不会造成某些界面布局无法实现,但写法要注意。详见:样式
    d.script:写法同 vue,并支持 3 种 API:
        nvue API :仅支持 App 端,uni-app 编译模式也可使用。使用前需先引入对应模块,参考:模块引入 API
        uni API:https://uniapp.dcloud.io/api/README
        plus API:仅支持 App 端。http://www.html5plus.org/doc/h5p.html

03.调试 nvue 页面
    a.说明
        HBuilderX 内置了 weex 调试工具的强化版,包括审查界面元素、看 log、debug 打断点

2.3 nuve:对比vue

00.汇总
    a.分类1
        01.nvue 页面控制显隐只可以使用v-if不可以使用v-show
        02.nvue 页面只能使用flex布局,不支持其他布局方式。页面开发前,首先想清楚这个页面的纵向内容有什么,哪些是要滚动的,然后每个纵向内容的横轴排布有什么,按 flex 布局设计好界面。
        03.nvue 页面的布局排列方向默认为竖排(column),如需改变布局方向,可以在 manifest.json -> app-plus -> nvue -> flex-direction 节点下修改,仅在 uni-app 模式下生效。详情。
        04.nvue页面编译为H5、小程序时,会做一件css默认值对齐的工作。因为weex渲染引擎只支持flex,并且默认flex方向是垂直。而H5和小程序端,使用web渲染,默认不是flex,并且设置display:flex后,它的flex方向默认是水平而不是垂直的。所以nvue编译为H5、小程序时,会自动把页面默认布局设为flex、方向为垂直。当然开发者手动设置后会覆盖默认设置。
        05.文字内容,必须、只能在<text>组件下。不能在<div>、<view>的text区域里直接写文字。否则即使渲染了,也无法绑定js里的变量。
        06.只有text标签可以设置字体大小,字体颜色。
        07.布局不能使用百分比、没有媒体查询。
        08.nvue 切换横竖屏时可能导致样式出现问题,建议有 nvue 的页面锁定手机方向。
        09.支持的css有限,不过并不影响布局出你需要的界面,flex还是非常强大的。详见
        10.不支持背景图。但可以使用image组件和层级来实现类似web中的背景效果。因为原生开发本身也没有web这种背景图概念
    b.分类2
        11.css选择器支持的比较少,只能使用 class 选择器。详见
        12.nvue 的各组件在安卓端默认是透明的,如果不设置background-color,可能会导致出现重影的问题。
        13.class 进行绑定时只支持数组语法。
        14.Android端在一个页面内使用大量圆角边框会造成性能问题,尤其是多个角的样式还不一样的话更耗费性能。应避免这类使用。
        15.nvue页面没有bounce回弹效果,只有几个列表组件有bounce效果,包括 list、recycle-list、waterfall。
        16.原生开发没有页面滚动的概念,页面内容高过屏幕高度并不会自动滚动,只有部分组件可滚动(list、waterfall、scroll-view/scroller),要滚的内容需要套在可滚动组件下。这不符合前端开发的习惯,所以在 nvue 编译为 uni-app模式时,给页面外层自动套了一个 scroller,页面内容过高会自动滚动。(组件不会套,页面有recycle-list时也不会套)。后续会提供配置,可以设置不自动套。
        17.在 App.vue 中定义的全局js变量不会在 nvue 页面生效。globalData和vuex是生效的。
        18.App.vue 中定义的全局css,对nvue和vue页面同时生效。如果全局css中有些css在nvue下不支持,编译时控制台会报警,建议把这些不支持的css包裹在条件编译里,APP-PLUS-NVUE
        19.不能在 style 中引入字体文件,nvue 中字体图标的使用参考:加载自定义字体。如果是本地字体,可以用plus.io的API转换路径。
        20.目前不支持在 nvue 页面使用 typescript/ts。
        21.nvue 页面关闭原生导航栏时,想要模拟状态栏,可以参考文章。但是,仍然强烈建议在nvue页面使用原生导航栏。nvue的渲染速度再快,也没有原生导航栏快。原生排版引擎解析json绘制原生导航栏耗时很少,而解析nvue的js绘制整个页面的耗时要大的多,尤其在新页面进入动画期间,对于复杂页面,没有原生导航栏会在动画期间产生整个屏幕的白屏或闪屏。

01.显隐控制方式差异
    a.nvue
        - 仅支持 `v-if`。
        <view v-if="showContent">显示内容</view>
        <text v-if="isLogin">已登录</text>
        <text v-if="!isLogin">未登录</text>
    b.vue
        - 支持 `v-if` 和 `v-show`。
        <view v-show="showContent">显示内容</view>
        <text v-if="isLogin">已登录</text>
        <text v-show="!isLogin">未登录</text>

02.布局方式差异
    a.nvue
        - 仅支持 flex 布局。
        <view class="container">
          <view class="item">项目1</view>
          <view class="item">项目2</view>
        </view>
        <style>
        .container {
          display: flex;
          flex-direction: row;
        }
        .item {
          flex: 1;
        }
        </style>
    b.vue
        - 支持多种布局方式(如浮动布局、网格布局)。
        <view class="float-container">
          <view class="float-left">左浮动</view>
          <view class="float-right">右浮动</view>
        </view>
        <style>
        .float-left { float: left; }
        .float-right { float: right; }
        </style>

03.文字内容容器差异
    a.nvue
        - 文字必须在 `<text>` 组件内。
        <view>
          <text>这是一段文字</text>
        </view>
    b.vue
        - 文字可直接在容器内。
        <view>这是一段文字</view>

04.字体样式设置差异
    a.nvue
        - 仅 `<text>` 可设置字体样式。
        <text style="font-size: 16px; color: #ff0000;">红色16号文字</text>
    b.vue
        - 任意容器可设置字体样式。
        <view style="font-size: 16px; color: #ff0000;">红色16号文字</view>

05.背景图实现差异
    a.nvue
        - 不支持背景图,需用 `<image>` 模拟。
        <view class="bg-container">
          <image src="/static/bg.png" class="bg-image"></image>
          <text class="bg-text">文字内容</text>
        </view>
        <style>
        .bg-container {
          position: relative;
          width: 100%;
          height: 200px;
        }
        .bg-image {
          width: 100%;
          height: 100%;
          position: absolute;
        }
        .bg-text {
          position: absolute;
          color: white;
        }
        </style>
    b.vue
        - 支持 `background-image`。
        <view style="background-image: url('/static/bg.png'); height: 200px;">
          <text style="color: white;">文字内容</text>
        </view>

06.CSS选择器支持差异
    a.nvue
        - 仅支持 class 选择器。
        <view class="container">
          <text class="text-primary">主文字</text>
        </view>
        <style>
        .container { padding: 10px; }
        .text-primary { color: #007aff; }
        </style>
    b.vue
        - 支持多种选择器(如 id、伪类选择器)。
        <view id="container">
          <text class="text-primary">主文字</text>
        </view>
        <style>
        #container { padding: 10px; }
        .text-primary { color: #007aff; }
        </style>

07.class绑定语法差异
    a.nvue
        - 仅支持数组语法。
        <view :class="[isActive ? 'active' : '']">内容</view>
        <style>
        .active { background-color: #eee; }
        </style>
    b.vue
        - 支持多种绑定语法(如对象语法)。
        <text :class="{ success: type === 'success', error: type === 'error' }">状态文字</text>
        <style>
        .success { color: green; }
        .error { color: red; }
        </style>

08.页面滚动实现差异
    a.nvue
        - 需用可滚动组件包裹(如 `scroll-view` 或 `list`)。
        <scroll-view class="scroll-container" scroll-y>
          <view v-for="i in 20" :key="i" class="item">{{ i }}</view>
        </scroll-view>
        <style>
        .scroll-container {
          flex: 1;
          height: 100%;
        }
        .item {
          height: 50px;
          margin: 5px;
          background-color: #eee;
        }
        </style>
    b.vue
        - 内容超出自动滚动。
        <view class="container">
          <view v-for="i in 20" :key="i" class="item">{{ i }}</view>
        </view>
        <style>
        .item {
          height: 50px;
          margin: 5px;
          background-color: #eee;
        }
        </style>

09.全局JS变量生效差异
    a.nvue
        - 不支持 App.vue 的全局变量,需用 globalData 或 vuex。
        <text>{{ getApp().globalData.userName }}</text>
        <script>
        App({
          globalData: {
            userName: '张三'
          }
        })
        </script>
        ---
    b.vue
        - 支持 App.vue 的全局变量。
        <text>{{ globalVar.appName }}</text>
        <script>
        export default {
          onLaunch() {
            Vue.prototype.globalVar = {
              appName: '我的应用'
            }
          }
        }
        </script>

10.字体文件引入差异
    a.nvue
        - 需通过 plus.io 转换路径。
        <text class="custom-font">自定义字体</text>
        <script>
        export default {
          onLoad() {
            const fontPath = plus.io.convertLocalFileSystemURL('/static/fonts/custom.ttf')
            const domModule = weex.requireModule('dom')
            domModule.addRule('fontFace', {
              'fontFamily': 'CustomFont',
              'src': `url('${fontPath}')`
            })
          }
        }
        </script>
        <style>
        .custom-font {
          fontFamily: 'CustomFont';
          font-size: 18px;
        }
        </style>
    b.vue
        - 可直接在 style 中引入。
        <text class="custom-font">自定义字体</text>
        <style>
        @font-face {
          font-family: 'CustomFont';
          src: url('/static/fonts/custom.ttf');
        }
        .custom-font {
          font-family: 'CustomFont';
          font-size: 18px;
        }
        </style>