15、电脑、移动端基础、vant-ui相关、微信小程序、uniapp跨端框架(1700行)

一、电脑
1、构成
  (1)硬件系统
    A、核心硬件(主机内部组件)
      a、中央处理器(CPU),负责数据运算和指令调度,是电脑的运算核心与控制核心
      b、内存(RAM),临时存储运行中的程序和数据,读写速度快,断电后数据丢失
      c、外存,固态硬盘/机械硬盘(SSD/HDD),长期存储数据、系统和软件,断电后数据不会丢失
      d、图形处理器(GPU),负责图像渲染、视频解码和并行计算,提升游戏、设计类场景的流畅度
      e、主板(Mainboard),承载并连接所有核心硬件,通过芯片组协调各部件的数据通信
      f、电源(Power Supply),将市电转换为各硬件所需的稳定电压,为整机供电
    B、外设硬件(主机外部设备)
      a、输入设备:向电脑传递指令和数据,如键盘、鼠标、扫描仪、摄像头、麦克风
      b、输出设备:将电脑处理结果反馈给用户,如显示器、打印机、音箱、耳机
      c、输入输出一体设备:兼具输入和输出功能,如触摸屏、U盘、移动硬盘
  (2)软件系统
    A、系统软件(电脑运行的基础)
      a、操作系统(OS),管理硬件资源、提供人机交互界面,如Windows、macOS、Linux
      b、驱动程序(Driver),连接操作系统和硬件的桥梁,确保硬件正常工作,如显卡驱动、声卡驱动、打印机驱动
      c、系统工具软件(System Utility Software),维护系统运行,如磁盘分区工具、杀毒软件、系统备份工具
    B、应用软件(满足特定需求的工具)
      a、办公类:如 Word、Excel、PPT、WPS
      b、创作类:如 Photoshop、Premiere、VS Code、CAD
      c、娱乐类:如各类游戏、视频播放器、音乐软件
      d、网络类:如浏览器、即时通讯软件、邮件客户端
2、常见全局功能
  (1)查看剪贴板:win+v;
  (2)查看命令行:win+r; cmd; 确定
  (3)查看电脑配置:win+r; msinfo32; 确定
  (4)设置自动锁屏时长:Windows+I>设置>系统>电源和睡眠
  (5)设置输入法:Windows+I -> 时间和语言 -> 语言
  (6)搜狗输入法的快捷键界面:S图标-更多设置-属性设置-按键
    A、中英切换
    B、系统功能快捷键-系统功能快捷键设置
  (7)广告屏保的位置与删除
    A、重启
    B、此电脑-(上方中间的)查看-显示-隐藏的项目
    C、打开,C:\Users\制造商(NINGMEI)\AppData\Local\Temp
    D、删除该位置下的所有文件
  (8)谷歌截全屏的步骤
    A、F12
    B、ctrl+shift+p
    C、输入full
    D、点击Capture full size screenshot
    另,免费在线网页转图片,https://www.url2pic.com/url2pic/index.html
      
二、移动端基础
1、常用术语
  (1)Uni,统一的
  (2)IDE,集成开发环境(Integrated Development Environment),如VS Code、HBuilderX等
  (3)SDK,软件开发工具包(Software Development Kit),是软件开发工具的集合,通常包括编译器、调试器、API文档和代码示例等
  (4)uniCloud,基于serverless模式和js编程的云开发平台,提供免费服务器空间,由数字天堂联合阿里云、腾讯云等云厂商共同推出
2、各种单位
  (1)常用(px、%、em、rem,vw、vh、vmin、vmax)
    A、px,像素(pixel)
      a、CSS中的基本长度单位,屏幕显示的最小单位
      b、在标准密度屏幕(dpr=1)下,1个CSS像素等于1个设备独立像素
      c、在高清屏(dpr>1)下,1个CSS像素可能对应多个物理像素
    B、%,
      a、width/左右padding/左右margin:相对于父元素的宽度
      b、height/上下padding/上下margin:相对于父元素的高度(若父元素高度未显式设置,则无法生效)
      c、font-size:相对于父元素的font-size
    C、em,
      a、用于字体尺寸时,相对于父元素的font-size
      b、用于其他属性(width, height, margin等)时,
        b1、相对于当前元素自身的font-size,如{ font-size:20px; width:2em; } 
        b2、如果当前元素未设置font-size,则继承父元素的计算值
    D、rem,即root em,是相对于“根元素”html的font-size来定义的尺寸单位,3种定义
      a、html { font-size: 20px; } 
      b、:root { font-size: 20px; } 
      c、document.documentElement.style.fontSize = document.documentElement.clientWidth/10+'px';
    E、vw,视口宽度(viewport width),1vw等于视口宽度的1%
    F、vh,视口高度(viewport height),1vh等于视口高度的1%
    G、vmin,视口宽度和高度中较小值的1%
    H、vmax,视口宽度和高度中较大值的1%
  (2)不常用(dpi、ppi;dip、dp、sp、pt;dpr)
    A、密度
      a、dpi,每英寸点数(Dots Per Inch)
      b、ppi,每英寸像素数(Pixels Per Inch)
    B、dip(设备独立像素,Device-IndependentPixel,也简称dp),是一种与设备屏幕密度解耦的抽象单位
      a、在跨平台(Android、iOS)的原生开发中,
      b、Android系统布局文件使用dip(或dp)为单位,渲染时按照以下公式换算:物理像素(px)=dip值×屏幕密度(如屏幕dpi/160)
      c、Android系统字体常用sp为单位,其基础换算逻辑与dp一致,但sp会额外跟随用户在系统设置中调整的字体大小缩放比例
      d、iOS系统布局文件使用pt为单位,渲染时按照以下公式进行:物理像素(px)=pt值×缩放因子(如@1x、@2x、@3x)
    C、dpr,设备像素比(Device Pixel Ratio)
      a、在Web前端(HTML/CSS/JS)开发中,物理像素=CSS逻辑像素×dpr
      b、(屏幕硬件的)物理像素,体现在硬件的发光点上
      c、(浏览器软件的)逻辑像素,体现在CSS上的数值上
      d、硬件原生dpr,是有效dpr的初始基准值,缩放比不修改这个初始值
    D、缩放比
      a、浏览器缩放,Ctrl+滚轮
      b、系统缩放,右键桌面->显示设置->屏幕->更改文本、应用等项目的大小
      c、相似效果。27寸:缩放比200%;50寸:缩放比100%
    E、有效dpr
      a、定义,原生dpr×缩放比,或,物理像素÷缩放后的逻辑像素
      b、获取,window.devicePixelRatio,始终返回该值(初始值或叠加缩放后的结果)
      c、越小,每行展示内容越多
      d、大于1时,多个物理像素显示一个逻辑像素,提高显示精度
3、使用dpr
  (1)最早使用,2010年,苹果公司推出首款Retina(视网膜)屏iPhone4,dpr=2
  (2)非图片元素,矢量渲染,不需要额外处理即可清晰显示
  (3)图片元素,像素点阵渲染,处理不当会出现模糊。解决方案,提供二倍图、多倍图!!!
    A、img标签,2013年,浏览器首次支持img标签的srcset属性
      <img 
        src="images/icon@1x.png"  <!-- 兜底图片,兼容不支持srcset的浏览器 -->
        srcset="
          images/icon@1x.png 1x,  <!-- 普通屏(DPR=1) -->
          images/icon@2x.png 2x,  <!-- 高清屏(DPR=2,如iPhone8) -->
          images/icon@3x.png 3x   <!-- 超高清屏(DPR=3,如iPhone14) -->
        "
        alt="图标"
        width="100"  <!-- 固定显示宽度,避免图片变形 -->
      >
    B、背景图,2010年,浏览器首次支持background-image样式的mage-set属性
      通过background-size属性值,如contains、cover、contain、100%等实现全覆盖
      .bg-image {
        width: 100px;
        height: 100px;
        /* image-set 语法:图片路径 像素比 */
        background-image: image-set(
          url('images/icon@1x.png') 1x,
          url('images/icon@2x.png') 2x,
          url('images/icon@3x.png') 3x
        );
        background-size: 100% 100%; /* 必须设置,否则背景图尺寸会按原图像素显示 */
      }
4、自适应实现方案,以postcss.config.js为例
  附、属性说明,<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
    A、viewport,声明这是一个控制视口的meta标签
    B、width=device-width,视口宽度等于设备屏幕的逻辑像素宽度
    C、initial-scale=1.0,初始缩放比例
    D、user-scalable=no,禁止用户(用手指)缩放
  (1)px转rem
    module.exports = () => ({
      plugins: [
        require('autoprefixer')(), 
        require('postcss-pxtorem')({
          rootValue: 37.5, //转换基准值
          //1.定义rem:
          // 1.1.在main.js里引入并运行flexible.js
          // 1.2.将浏览器屏幕逻辑像素宽的1/10设为“根元素(html)字体大小”,即1rem。这样屏幕宽就是10rem
          //2.转换rem:设rootValue为37.5
          // 2.1.使用375px一倍图设计稿,
          //   2.1.1.开发时,开发者在CSS中写设计稿原尺寸
          //   2.1.2.构建时,插件自动用“CSS的px值/37.5”转换为rem值,10rem“等于”设计稿总宽
          // 2.2.使用750px二倍图设计稿,
          //   2.2.1.开发时,开发者在CSS中写设计稿原尺寸/2
          //   2.2.2.构建时,插件自动用“CSS的px值/37.5”转换为rem值,10rem“对应”设计稿总宽
          //3.渲染rem:!!!
          // 3.1.浏览器根据根元素字体大小(1rem对应的逻辑像素值)解析rem为逻辑像素,交给操作系统
          // 3.2.操作系统根据dpr把逻辑像素换算为物理像素,最终交由屏幕硬件显示
          propList: ['*'], 
          selectorBlackList: ['.norem'] 
        }),
      ]
    });
  (2)px转vw
    module.exports = {
      plugins: {
        autoprefixer: {},
        'postcss-px-to-viewport': {
          exclude: undefined, //忽略某些文件夹下的文件或特定文件,例如 'node_modules' 下的文件
          fontViewportUnit: 'vw', //字体使用的视口单位
          include: undefined, //如果设置了include,那将只有匹配到的文件才会被转换
          landscape: false, //是否添加根据 landscapeWidth 生成的媒体查询条件 @media (orientation: landscape)
          landscapeUnit: 'vw', //横屏时使用的单位
          landscapeWidth: 1920, //横屏时使用的视口宽度
          mediaQuery: false, //媒体查询里的单位`px`是否需要转换,false为默认值
          minPixelValue: 1, //设置最小的转换数值,只有大于`1px`的值转换为视窗单位
          propList: ['*'], //能转化为vw的属性列表
          replace: true, //是否直接更换属性值,而不添加备用属性
          selectorBlackList: ['p', '.hairlines'], //需要忽略的CSS选择器,不会转为视口单位,使用原有的px等单位
          unitPrecision: 5, //转换后保留的小数位数,precision精确
          unitToConvert: 'px', //需要转换的单位,默认为"px"
          viewportWidth: 375, //设计稿的视口宽度,375px=100vw
          viewportHeight: 1334, //视窗的高度,1334px=100vh
          viewportUnit: 'vw', //指定转换后的视窗单位,建议使用vw
        },
        'postcss-viewport-units': {
          //排除会产生警告的部份
          filterRule: rule => rule.nodes.findIndex(i => i.prop === 'content') === -1
        },
        cssnano: {//集成了部分PostCSS插件,用false禁用其中的某个插件,nano毫微
          preset: 'advanced', //预设: 高级(转换)
          autoprefixer: false, //禁用autoprefixer,和上面的autoprefixer: {}具有相同效果
          'postcss-zindex': false
        }
      }
    }
5、移动端的系统与应用
  (1)系统
    A、安卓系统
      a、2003年,安卓公司成立,开始研发安卓系统
      b、2005年,谷歌收购安卓,将其转为移动操作系统项目
      c、2007年,谷歌正式公布安卓系统
      d、2008年,首款安卓手机发布,搭载Android1.0系统 
      e、2011年,Android4.0,实现手机与平板系统统一
      f、2014年,Android5.0,引入Material Design设计语言
      g、2019年,Android10,首次采用数字版本号命名
    B、苹果系统
      a、2007年,首款苹果手机发布,系统名为iPhone OS
      b、2010年,系统更名为iOS,并推出适用于iPad的版本
      c、2013年,iOS7采用扁平化设计风格
      d、2016年,iOS10开放更多系统功能接口
      e、2019年,苹果将iPad的系统独立为iPadOS,专注于平板体验优化
      f、2020年,iOS14引入主屏幕小组件、App资源库等新功能
      g、3种系统,macOS(台式机电脑、笔记本电脑)、iPadOS(平板电脑)、iOS(手机)
  (2)应用!!!
    A、原生应用(Native)
      a、完全使用平台专属语言(安卓用Kotlin/Java,苹果用Swift/Objective-C)编写的应用程序
      b、直接调用系统提供的原生UI组件和API
      c、能获得最佳的性能、流畅的交互体验和最完整的系统功能访问权限
    B、原生应用的缺陷与解决方案
      a、缺陷,需用两种平台专属语言,为安卓和iOS开发两套代码
      b、解决,用前端熟悉的React Native技术,写一套JS/JSX代码,最终由双平台各自渲染为原生组件,降低开发成本与门槛
    C、混合应用(Hybrid)
      a、把系统内置的网页渲染容器(如安卓的WebView、苹果的WKWebView)作为外壳
      b、大部分的业务逻辑和用户界面是通过运行在容器中的Web技术(HTML、CSS、JavaScript)来实现的
      c、一套Web代码可同时运行在两个平台,开发效率高,其它方面如性能、体验、集成能力,与原生应用相比显弱
    D、网页渲染容器(网页渲染组件)
      a、封装了网页渲染引擎和(应用与网页)双向通信接口的组件/类,能识别px、rem,能渲染H5网页
      b、postcss-pxtorem把开发人员设置的固定值px转换为相对值rem,以实现对不同分辨率网页容器的适配
    E、操作系统分配执行环境给应用的过程
      a、通过识别应用程序的组成结构(如是否包含WebView组件或特定框架的运行时库)
      b、来动态地为其分配合适的执行环境(如原生的ART虚拟机或混合模式下的WebView引擎)
      c、以确保应用能够正确且高效地运行
    F、react.js与React Native的关系
      a、同属Facebook(现Meta)开发的技术体系
      b、共享React核心思想(如组件化、声明式编程、虚拟DOM)和JSX语法
      c、状态管理逻辑(如Hooks)一致
      d、React.js用于Web端DOM渲染
      e、React Native用于移动端原生组件渲染,组件类型和渲染底层不同
      f、开发者可复用React知识快速上手
  (3)QQ
    A、1999年,腾讯QQ(当时名为OICQ,后因侵权诉讼改名)正式上线
    B、2002年,QQ群功能诞生,开启“多对多”社交模式,用户量迅速增长
    C、2004年,QQ注册用户突破3亿,腾讯在香港主板上市
    D、2010年,3Q大战
      a、1月21日,腾讯推QQ医生3.2仿360,赠诺顿并借春节强推
      b、5月31日,QQ医生升4.0为QQ电脑管家,含360主流功能
      c、9月27日,360发“隐私保护器”,查QQ是否窥用户隐私
      d、10月27日,腾讯联合多公司发声明,要求调查360
      e、10月29日,360推“360扣扣保镖”,称保QQ用户安全
      f、11月3日,腾讯发信,装360电脑停QQ,逼用户二选一
      g、11月4日,四家厂商召开发布会,客户端不兼容360
      h、11月10日,经协调,360召回软件,腾讯恢复QQ与360兼容
    E、2023年,推出QQ9.0版本,实现多端统一
  (4)微信
    A、H5,使用(微信基于系统网页渲染容器加工后的)专属容器加载运行
    B、小程序(rpx)
      a、小程序使用自研的双线程容器运行
      b、小程序规定屏幕宽度为750rpx,即Responsive Pixel,响应式像素
      c、小程序根据实际屏幕宽度的px值和元素尺寸的rpx值,计算出元素尺寸的px值
      d、计算公式为,设备实际屏幕宽度px值÷750×元素尺寸rpx值=元素尺寸px值
    C、微信的发展历程
      a、2011年,1月,微信上线,实现文字、图片即时通讯;5月,新增语音对讲
      b、2012年,新增语音通话、视频通话、朋友圈、公众号
      c、2013年,新增微信支付,绑定银行卡,开启移动支付
      d、2014年,新增微信红包功能
      e、2017年,新增小程序,整合服务与内容,构建生态闭环

三、vant-ui移动端Vue组件库!!!
1、<input type="">中type取值及含义
  (1)基础文本输入类(核心用于文本/数值类内容输入)
    A、text,含义:单行普通文本输入框,无格式限制,是最基础的输入类型,适用于姓名、账号、备注等普通文本输入
    B、password,含义:密码输入框,输入内容会被掩码(●)隐藏,仅视觉上保护敏感信息,适用于密码、验证码等隐私输入
    C、number,含义:数字输入框,仅允许输入数字、小数点、正负号,移动端会唤起数字键盘,适用于手机号、年龄、金额等数值输入
    D、email,含义:邮箱输入框,自带基础邮箱格式验证(需包含@符号),移动端唤起邮箱适配键盘,适用于邮箱地址输入
    E、tel,含义:电话号码输入框,用于输入固定电话或手机号,移动端唤起数字键盘(支持+、-等分隔符),适用于联系方式输入
    F、url,含义:网址输入框,自带URL格式验证(需包含http:///https://),适用于网站地址输入
    G、search,含义:搜索输入框,外观与text类似,部分浏览器会显示“清除按钮”,语义上更贴合搜索功能场景
  (2)选择交互类(用于选择、筛选、上传类操作,非纯文本输入)
    A、checkbox,含义:复选框,支持多选,需配合<label>或name属性分组,适用于协议勾选、兴趣爱好选择等多选项场景
    B、radio,含义:单选框,同组(name相同)下互斥选择,适用于性别、支付方式等二选一/多选一场景。
    C、range,含义:滑块选择器,通过min/max/step设置数值范围和步长,可视化调整数值,适用于音量、亮度、价格区间筛选
    D、date,含义:日期选择器,唤起系统日期选择面板(年-月-日),返回格式为YYYY-MM-DD,适用于生日、预约日期选择
    E、time,含义:时间选择器,唤起系统时间选择面板(时:分),返回格式为HH:MM,适用于具体时段选择
    F、datetime-local,含义:本地日期时间选择器,唤起日期+时间选择面板,返回格式为YYYY-MM-DDTHH:MM
    G、month,含义:月份选择器,选择年-月,返回格式为YYYY-MM,适用于按月筛选账单、报表等场景
    H、week,含义:周选择器,选择年-周,返回格式为YYYY-Www(如2026-W02),适用于按周统计数据场景
    I、color,含义:颜色选择器,唤起系统颜色面板,返回16进制颜色值(如#ff0000),适用于主题色、字体色选择
    J、file,含义:文件上传框,打开文件选择对话框,支持multiple(多文件)、accept(指定类型),适用于图片、文档上传
  (3)功能操作类(无输入内容,用于触发表单/页面操作)
    A、button,含义:普通按钮,无默认行为,需绑定onclick事件触发自定义操作,适用于重置表单、打开弹窗等场景
    B、submit,含义:提交按钮,包裹在<form>中时,点击自动提交表单数据到action指定地址,适用于表单提交操作
    C、reset,含义:重置按钮,包裹在<form>中时,点击清空表单所有输入内容,恢复初始状态,适用于表单重置操作
    D、image,含义:图片提交按钮,以图片作为提交按钮,需通过src指定图片地址,功能同submit,适用于自定义提交按钮样式
  (4)隐藏/特殊类(非可视化或兼容性特殊类型)
    A、hidden,含义:隐藏输入框,不在页面显示,用于存储无需用户输入但需随表单提交的隐藏数据(如用户ID、订单ID)
    B、datetime,含义:日期时间选择器(已废弃),原用于选择UTC日期时间,现被datetime-local替代,不建议使用
2、标签完整分类说明
  (1)基础布局类(页面结构搭建核心)
    A、van-row,div,行容器。栅格布局的行容器,配合 van-col 实现多列布局,用于快速划分页面区域、适配不同屏幕宽度
    B、van-col,div,列容器。栅格布局的列容器,通过 span 属性设置列宽占比,实现响应式页面布局
    C、van-cell,div,单元格。列表/表单的基础单元格,可展示文字、图标、箭头等,常用于个人中心、设置页面的单行条目
    D、van-cell-group,div,单元格组。包裹 van-cell 的容器,提供统一的上下边框和间距,让单元格组更规整
    E、van-container,div,页面容器。适配移动端页面的根容器,自动处理状态栏、导航栏高度,避免内容被遮挡
  (2)表单交互类(用户输入/选择核心)
    D、van-radio,input type="radio":单选框,需配合 van-radio-group 使用,实现互斥选择,如性别、支付方式选择
    F、van-switch,input type="checkbox",样式改造。开关组件,用于开启/关闭类操作,如消息通知、夜间模式切换
    C、van-checkbox,input type="checkbox":复选框,支持单独使用或通过van-checkbox-group实现多选
    G、van-slider,input type="range":滑动选择器,用于数值区间选择,如音量调节、价格区间筛选
    A、van-field,input/textarea:表单输入框,支持文本、密码、多行文本等类型,内置验证、清除、字数统计等功能
    E、van-picker,select,增强版。滚动选择器,支持单列/多列选择,如日期、地区、自定义选项选择,替代原生 select 提升交互体验
    B、van-button,button:按钮组件,支持默认、主要、危险等样式,可设置禁用、加载状态,适配移动端点击交互
  (3)反馈提示类(用户操作后告知核心)
    A、van-toast,无直接对应 html 标签(动态创建 DOM。轻量级提示框,支持文字、加载、成功/失败图标,自动消失,用于操作结果提示
    B、van-dialog,dialog,增强版。模态对话框,支持确认/取消按钮、自定义内容,用于重要操作确认(如删除、退出)
    C、van-loading,无直接对应 html 标签(动态创建 DOM。加载提示组件,支持全屏/局部加载,用于数据请求、页面渲染时的加载状态展示
    D、van-notify,无直接对应 html 标签(动态创建 DOM。顶部通知栏,支持文字、图标,自动消失,用于系统通知、操作提醒
    E、van-action-sheet,div,弹窗层。底部弹出的操作菜单,替代原生 confirm,支持多按钮、取消按钮,如分享、更多操作选择
  (4)导航操作类(页面跳转/功能入口核心)
    A、van-nav-bar,header:页面导航栏,支持左侧返回、右侧操作按钮、标题自定义,适配移动端导航样式
    B、van-tabbar,footer:底部标签栏,配合 van-tabbar-item 实现页面切换,用于 APP 底部导航(如首页、我的、消息)
    C、van-tabs,div,选项卡容器。顶部选项卡,配合 van-tab 实现内容切换,如订单列表的 “全部/待付款/已完成” 切换
    D、van-sidebar,aside:侧边导航栏,配合 van-sidebar-item 实现二级菜单切换,如分类页面的左侧分类导航
    E、van-search,input type="search",增强版。搜索框组件,支持搜索图标、清除按钮、搜索建议,用于页面搜索功能
  (5)内容展示类(数据/媒体展示核心)
    A、van-list,ul/li:列表加载组件,支持上拉加载、下拉刷新,用于长列表数据展示(如商品列表、消息列表)
    B、van-grid,div,网格容器。宫格布局组件,配合 van-grid-item 实现图标 + 文字的功能入口,如首页功能导航
    C、van-swipe,div,轮播容器。轮播图组件,支持自动播放、指示器、无限滚动,用于 banner 图、商品轮播展示
    D、van-card,div,卡片容器。卡片组件,支持标题、图片、价格、操作按钮,用于商品展示、信息卡片
    E、van-image,img,增强版。图片组件,支持懒加载、占位图、点击预览、缩放,解决移动端图片展示的常见问题
    F、van-collapse,details/summary,增强版。折叠面板,配合 van-collapse-item 实现内容展开/收起,用于分类说明、常见问题展示
3、动态内容标签完整分类说明
  (1)轻量提示类(无遮罩,自动/手动消失,仅信息告知)
    A、notify:消息提示,页面顶部显示,有样式变化(成功/失败/警告等),3秒后自动消失,用于轻量级系统通知、操作结果提醒
    B、toast:轻提示,页面居中显示,无样式变化,3秒后自动消失,用于快速反馈操作状态(如“加载中”“提交成功”)
    C、NoticeBar:通知栏,固定位置显示,有样式变化(滚动/可关闭/链接跳转),不消失(需手动关闭),用于公告、活动提醒、系统通知
    D、Loading:加载提示,可居中/内联/全屏显示,无样式变化,需手动控制显示/隐藏,用于数据请求、页面加载时的状态提示
  (2)弹出交互类(无遮罩,触发显示,操作后消失,精准定位)
    A、Popover:气泡弹出框,点击处显示,基于reference插槽内容定位,点击外部/选项后消失,常用于下拉选项、操作菜单
    B、DropdownMenu:下拉菜单,顶部/指定位置显示,点击菜单项/外部区域后消失,适用于筛选条件切换
  (3)遮罩层基础类(仅遮罩,无内容,配合其他组件使用)
    A、overlay:遮罩层,全屏罩住页面内容,可配置透明度/点击关闭,需手动控制显示/隐藏,用于配合popup/dialog等实现遮罩效果
  (4)遮罩弹出类(有遮罩,固定/自定义位置,确认后消失,核心交互)
    A、popup:弹出层,常用触底/居中/侧边显示,确认后消失,用于省市县选择、日期选择、自定义筛选面板
    B、dialog:弹出框,居中显示,确认/取消后消失,支持自定义标题/按钮,用于重要操作确认(如删除、退出)、信息提示
    C、ActionSheet:动作面板,底部弹出显示,确认/取消后消失,用于多选项操作(如分享、删除、更多功能)
    D、Drawer:抽屉,侧边(左/右)弹出显示,滑动/点击关闭后消失,用于筛选条件、二级菜单展示
    E、ImagePreview:图片预览,全屏显示,滑动切换/点击关闭后消失,用于图片放大预览、多图浏览
    F、Picker:选择器弹窗,底部弹出显示,确认/取消后消失,专用于单列/多列滚动选择(时间、地区等)
    G、Calendar:日历选择器,居中/底部弹出显示,确认/取消后消失,用于日期区间、单日期选择
4、van-field标签
  (1)输入框,正常
  (2)文本框,type="textarea"
  (3)下拉框的逻辑
    输入框禁用,右侧添加三角,
    点击事件让下方气泡popup出现、传出序号、计算-从总数据中找出的相关数据-成下拉选项,
    点击事件从自身数据中找出的相关数据-成为下拉选项,气泡popup出现
    点击确定时,给对应的v-model赋值,气泡消失
  (4)其它,用input插槽,
    自定义输入框,使用此插槽后,与输入框相关的属性和事件将失效
    在Form组件进行表单校验时,会使用input插槽中子组件的value,而不是Field组件的value
  (5)<van-uploader/>的部分属性
    capture,图片选取模式,可选值为camera,直接调起摄像头
    after-read,文件读取完成后的回调函数
    before-read,文件读取前的回调函数,返回false可终止文件读取,支持返回Promise
4、Rule验证规则内部各项说明
  (1)校验辅助属性(体验层,不影响校验结果,优化使用体验)
    A、message,
      a、含义:校验失败时的提示文本,值为字符串类型;
      b、用法:自定义失败提示文案,会在输入框下方/Toast中展示;
      c、典型场景:“手机号格式错误”“密码长度需6-16位”。
    B、trigger,
      a、含义:触发校验的时机,值为字符串类型;可选值:blur(失焦)/change(值变化)/input(实时输入)/submit(表单提交);
      b、用法:控制校验触发的时机;
      c、典型场景:手机号失焦(blur)校验、验证码实时(input)校验、性别提交(submit)时校验。
  (2)校验主体属性
    A、required,
      a、含义:是否为必填项,值为布尔类型(true/false);
      b、用法:设为true时,输入框为空则校验失败;
      c、典型场景:手机号、密码等核心表单字段。
    B、type,
      a、含义:内置类型校验,值为字符串类型;可选值:string/number/boolean/mobile/email等;
      b、用法:快速校验基础类型或常用格式(如type="mobile"直接校验手机号);
      c、典型场景:邮箱、手机号、数字类输入。
    C、min/max,
      a、含义:数值/长度限制,值为数字/字符串类型;
      b、用法:对数字类型校验数值范围,对字符串校验字符长度;
      c、典型场景:密码长度(6-16位)、年龄(1-120)。
    D、pattern,
      a、含义:正则表达式校验,值为RegExp类型;
      b、用法:通过自定义正则匹配输入内容;
      c、典型场景:身份证号、银行卡号等特殊格式校验。
    E、enum,
      a、含义:枚举值校验,值为数组类型;
      b、用法:输入值必须在枚举数组内才通过校验;
      c、典型场景:性别(['男','女'])、职业(['学生','上班族'])等固定选项输入。
    F、whitespace,
      a、含义:是否校验空白字符,值为布尔类型(true/false);
      b、用法:设为true时,仅输入空格会判定为校验失败;
      c、典型场景:用户名、密码等禁止纯空格输入。
    G、transform,
      a、含义:校验前值转换函数,值为Function类型;
      b、用法:接收输入值并返回转换后的值,用于校验前格式化内容;
      c、典型场景:去除输入值两端空格、统一大小写。
    H、validator,
      a、含义:同步自定义校验函数,值为Function类型;
      b、用法:接收(value,callback)参数,value为输入值,callback无参表示通过、传Error表示失败;
      c、典型场景:两次密码一致校验、金额范围自定义判断。
    I、asyncValidator,
      a、含义:异步自定义校验函数,值为Function类型;
      b、用法:接收(value,callback)参数,支持异步请求校验;
      c、典型场景:校验手机号是否已注册、邀请码是否有效。
5、van-uploader标签上传示例
  (1)单文件手动上传
    <template>
      <div class="single-upload-container" style="padding: 20px;">
        <!-- 单文件上传核心组件 -->
        <van-uploader
          v-model="fileList"
          auto-upload="false"  <!-- 关闭自动上传,交由自定义逻辑!!! -->
          multiple="false"     <!-- 限制仅能选择单个文件,为true时,从备选图片中一次可选多张 -->
          :before-read="beforeRead"  <!-- 文件选择前校验,属性绑定 -->
          @after-read="handleCustomUpload"  <!-- 读取后触发自定义上传,事件监听 -->
          @delete="handleFileDelete"  <!-- 删除文件逻辑 -->
          accept=".jpg,.png,.jpeg"  <!-- 仅允许图片格式(可按需修改) -->
          :max-size="5 * 1024 * 1024"  <!-- 限制文件大小5MB -->
        />
        <!-- 上传进度展示(单文件专属) -->
        <div class="upload-progress" v-if="fileList[0]?.progress">
          <van-progress 
            :percentage="fileList[0].progress" 
            style="margin-top: 10px;"
          />
        </div>
        <!-- 上传结果提示(可选) -->
        <div class="upload-result" v-if="uploadResult">
          <span :style="{ color: uploadResult.success ? 'green' : 'red' }">
            {{ uploadResult.msg }}
          </span>
        </div>
      </div>
    </template>
    <script setup>
      import { ref } from 'vue';
      import axios from 'axios';
      import { showToast, showLoadingToast, closeToast } from 'vant';
      // 绑定单文件列表(始终只有1个元素)
      const fileList = ref([]);
      // 上传结果反馈
      const uploadResult = ref(null);
      // 后端上传接口地址(替换为你的实际接口)
      const UPLOAD_API = 'https://your-domain.com/api/upload/single';
      // 1. 文件选择前校验(格式+大小,单文件场景提前拦截非法文件)
      const beforeRead = (file) => {
        // 校验文件类型(仅图片)
        const allowTypes = ['image/jpeg', 'image/png', 'image/jpg'];
        if (!allowTypes.includes(file.file.type)) {
          showToast('仅支持上传jpg/png/jpeg格式图片');
          return false; // 终止文件读取
        }
        // 大小校验(已通过max-size限制,这里做兜底提示)
        if (file.file.size > 5 * 1024 * 1024) {
          showToast('文件大小不能超过5MB');
          return false;
        }
        return true; // 校验通过,继续读取文件
      };
      // 2. 核心:自定义单文件上传逻辑
      const handleCustomUpload = async (fileItem) => {
        // 清空之前的上传结果
        uploadResult.value = null;
        // 显示加载提示
        showLoadingToast('正在上传文件...');
        try {
          // 构建FormData(后端接收文件的标准格式)
          const formData = new FormData();
          formData.append('file', fileItem.file); // 文件字段(与后端约定)
          formData.append('uploadType', 'single'); // 自定义业务参数
          formData.append('token', localStorage.getItem('token')); // 自定义请求参数(如token)
          // 发起自定义上传请求
          const response = await axios.post(UPLOAD_API, formData, {
            headers: {
              'Content-Type': 'multipart/form-data', // 必须的文件上传头
              'Authorization': `Bearer ${localStorage.getItem('token')}` // 自定义请求头(如鉴权)
            },
            timeout: 30000, // 超时时间30秒
            // 实时更新上传进度(单文件进度展示核心)
            onUploadProgress: (e) => {
              if (e.total > 0) {
                fileItem.progress = Math.round((e.loaded / e.total) * 100);
              }
            }
          });
          // 上传成功:更新状态+反馈
          fileItem.status = 'success'; // 组件自动显示成功对勾
          uploadResult.value = {
            success: true,
            msg: `上传成功!文件地址:${response.data.fileUrl}`
          };
          // 可将文件地址存入业务数据
          // console.log('后端返回的文件地址:', response.data.fileUrl);
        } catch (error) {
          // 上传失败:更新状态+反馈
          fileItem.status = 'failed'; // 组件自动显示失败叉号
          uploadResult.value = {
            success: false,
            msg: `上传失败:${error.message || '网络异常,请重试'}`
          };
          console.error('单文件上传失败:', error);
        } finally {
          // 关闭加载提示
          closeToast();
        }
      };
      //3. 删除文件:清空列表+重置状态
      const handleFileDelete = () => {
        fileList.value = [];
        uploadResult.value = null;
      };
    </script>
    <style scoped>
      .single-upload-container {
        max-width: 500px;
        margin: 0 auto;
      }
      .upload-progress {
        width: 100%;
      }
      .upload-result {
        margin-top: 10px;
        font-size: 14px;
      }
    </style>
  (2)上传至OSS
    附、说明:
     A、依赖,import OSS from "ali-oss";
     B、OSS,OpenStorageService的简称,是阿里云对外提供的云存储服务,用户通过API在任何时间、地点、设备上进行数据的上传和下载
    <template>
      <van-uploader 
        accept="video/*"  <!-- 优化 accept,只接受视频类型 -->
        v-if="!showUpload"  
        :name="idx"  
        :before-read="uploadVideo"
        :disabled="isUploading"  <!-- 增加禁用状态,防止重复点击 -->
        <!-- auto-upload="true"(默认值):选择文件后自动触发上传!!! -->
      >
        <van-button icon="plus" type="primary" :loading="isUploading">
          {{ isUploading ? '上传中...' : '上传视频' }}
        </van-button>
      </van-uploader>
    </template>
    <script>
      export default {
        data() {
          return {
            showUpload: false,
            videoUploadPercent: 0,
            videoType: ['avi', 'mp4', 'rmvb', 'mov'],
            videoName: [],
            formData: [],
            isUploading: false, // 新增上传中状态
            client: null // 保存OSS客户端实例,方便中断上传
          };
        },
        methods: {
          uploadVideo(file, detail) {
            // 1. 前置校验:禁止重复上传
            if (this.isUploading) {
              this.$dialog.alert({
                title: '提示',
                message: '已有文件正在上传,请稍等',
                theme: 'round-button'
              });
              return false; // 返回false阻止上传
            }
            // 2. 优化文件格式校验
            let fileName = file.name || '';
            let suffixIndex = fileName.lastIndexOf(".");
            // 无后缀的情况直接判定为不合法
            if (suffixIndex === -1) {
              this.$dialog.alert({
                title: '提示',
                message: '仅支持 .avi, .mp4, .rmvb, .mov 格式的视频',
                theme: 'round-button'
              });
              return false;
            }
            let type = fileName.substring(suffixIndex + 1).toLowerCase();
            if (!this.videoType.includes(type)) {
              this.$dialog.alert({
                title: '提示',
                message: '仅支持 .avi, .mp4, .rmvb, .mov 格式的视频',
                theme: 'round-button'
              });
              return false;
            }
            // 3. 文件大小校验(1G)
            const maxSize = 1024 * 1024 * 1024;
            if (file.size > maxSize) {
              this.$dialog.alert({
                title: '提示',
                message: '上传视频大小不能超过 1G!',
                theme: 'round-button'
              });
              return false;
            }
            // 4. 标记上传中状态
            this.isUploading = true;
            this.showUpload = true;
            // 5. 请求OSS凭证并上传
            myRequest({
              tokenName: "ios"
            })
            .then(data => {
              const ossData = data.data.data;
              this.client = new OSS({
                region: "oss-cn-beijing",
                accessKeyId: ossData.accessKeyId,
                accessKeySecret: ossData.accessKeySecret,
                bucket: ossData.bucketName,
                stsToken: ossData.securityToken,
                timeout: 60000 // 新增超时时间,60秒
              });
              // 生成文件路径(优化后缀截取)
              const suffix = fileName.substring(suffixIndex);
              const fileUrl = `test/${Date.now()}${suffix}`;
              // 分片上传(优化分片大小为5MB)
              return this.client.multipartUpload(fileUrl, file, {
                progress: (p) => {
                  this.videoUploadPercent = Math.round(p * 100);
                },
                partSize: 5 * 1024 * 1024,
                retry: 3 // 新增重试次数,失败自动重试3次
              });
            })
            .then((res) => {
              // 6. 成功处理:优化formData操作
              this.videoName[detail.name] = res.name;
              let url = res.res.requestUrls[0];
              const finalUrl = url.split("?")[0];
              // 数组操作优化:确保下标存在,不存在则push,存在则替换
              if (this.formData.length > detail.name) {
                this.formData.splice(detail.name, 1, finalUrl);
              } else {
                this.formData[detail.name] = finalUrl;
              }
              this.$dialog.alert({
                title: '提示',
                message: '上传成功',
                theme: 'round-button'
              });
            })
            .catch((err) => {
              console.error('上传失败:', err);
              this.$dialog.alert({
                title: '提示',
                message: '上传失败,请重试',
                theme: 'round-button'
              });
            })
            .finally(() => {
              // 7. 无论成功失败,重置状态
              this.isUploading = false;
              this.showUpload = false;
              this.videoUploadPercent = 0;
              this.client = null;
            });
            // 阻止vant uploader的默认上传行为
            return false;
          }
        }
      };
    </script>
  
四、微信小程序-从注册到上线的步骤
 附、微信发展历史!!!
  (1)2011年1月,微信1.0发布;5月,微信2.0语音对讲发布;10月,微信3.0新增摇一摇功能
  (2)2012年3月,微信用户突破1亿;4月份,微信4.0朋友圈发布;同年7月,微信4.2发布公众平台
  (3)2013年8月,微信5.0发布微信支付
  (4)2014年9月,发布企业号、卡包
  (5)2015年1月,微信第一条朋友圈广告
  (6)2016年1月,企业微信发布
  (7)2017年1月,小程序发布
1、注册与账号准备(核心是AppID+备案/认证)
  (1)访问微信公众平台,选择「小程序」注册;填写未被占用的邮箱,完成邮箱验证,设置密码
  (2)选择主体类型(个人/企业/政府/媒体等),完成实名/资质核验:
    A、个人:身份证+人脸核验;
    B、企业:营业执照+法人信息+对公账户验证(可选企业微信快速注册)
  (3)进入后台,在「开发管理→开发设置」获取AppID(小程序ID)(核心开发凭证,不要用测试号)
  (4)完成小程序备案(必须):在后台「小程序备案」模块提交信息,经腾讯初审后转通管局(省通信管理局)审核;备案通过后才能发布正式版
  (5)可选:完成微信认证(企业主体300元/年),解锁微信支付、开放平台接口等高级功能
2、开发环境搭建与项目开发
  (1)下载安装微信开发者工具,用管理员微信扫码登录
  (2)新建项目:填写项目名称、本地目录,输入AppID,选择开发模式(原生/云开发/第三方框架如Taro);可勾选「快速启动模板」或「云开发」
  (3)开发与调试:
    A、编写代码(JSON/WXML/WXSS/JS),实现页面与功能逻辑;
    B、用开发者工具预览、真机调试(扫码在手机上测试);
    C、云开发用户:配置云环境、数据库、云函数、存储等
  (4)测试与优化:完成功能测试、兼容性测试、性能优化;生成体验版二维码,邀请测试用户体验并反馈
3、代码上传、审核与正式上线
  (1)上传代码:在开发者工具右上角点击「上传」,填写版本号与更新说明,提交至微信后台
  (2)版本管理与提交审核:
    A、登录公众平台,进入「开发管理→版本管理」,找到上传的开发版本;
    B、补充审核信息(名称、类目、功能说明、页面路径等),确认合规后提交审核
  (3)等待审核:常规1–3个工作日(节假日顺延),审核结果在后台与管理员微信通知;若驳回,按提示修改后重新提交
  (4)正式发布:审核通过后,在后台「审核版本」中点击「发布」,可选择全量发布或灰度发布(逐步扩大用户范围)
  (5)上线后运维:监控用户反馈、性能数据,迭代版本;必要时配置微信支付、客服、数据分析等功能
4、关键补充与避坑提示
  (1)备案周期:腾讯初审1–2天,管局备案普遍约10天(最长20天),建议备案与开发同步进行
  (2)类目选择:必须与小程序功能一致,否则审核驳回
  (3)审核要点:无违规内容、功能可正常使用、隐私合规(含用户授权、数据安全)、资质齐全(如电商需电商资质)

五、微信小程序-目录说明
  来源,https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html
  来源,https://developers.weixin.qq.com/miniprogram/dev/framework/structure.html
1、目录结构
  ├── app.wxss
  ├── app.js
  ├── app.json
  ├── pages
  │   │── index
  │   │   ├── index.wxml
  │   │   ├── index.js
  │   │   ├── index.json
  │   │   └── index.wxss
  │   │   └── index.wxs //同级的WXS文件(仅index页面使用,非必需)
  │   └── logs
  │       ├── logs.wxml
  │       └── logs.js
  ├── utils //通用工具目录
      └── format.wxs //通用WXS工具文件,非必需
2、全局配置,一个小程序主体由三个文件组成,必须放在项目的根目录
  (1)app.wxss,小程序全局样式表
  (2)app.json,小程序全局配置
    {
      //小程序所有页面路径(必填),第一个页面为默认首页
      "pages": ["pages/index/index", "pages/logs/index"],
      //页面窗口配置(导航栏、背景等)
      "window": {
        "navigationBarTitleText": "Demo", //导航栏标题文字
        "navigationBarBackgroundColor": "#ffffff", //导航栏背景色(默认白色)
        "navigationBarTextStyle": "black", //导航栏文字颜色(仅支持 black/white)
        "backgroundColor": "#f9f9f9" //页面下拉后露出的背景色
      },
      //底部tabBar配置(多tab页面必备)
      "tabBar": {
        "list": [ //tab列表(最少2个,最多5个)
          {
            "pagePath": "pages/index/index", //tab对应页面路径
            "text": "首页", //tab文字
            "iconPath": "images/tab/home.png", //未选中图标路径
            "selectedIconPath": "images/tab/home-active.png" //选中图标路径
          },
          {
            "pagePath": "pages/logs/logs",
            "text": "日志",
            "iconPath": "images/tab/log.png",
            "selectedIconPath": "images/tab/log-active.png"
          }
        ],
        "color": "#666666", //tab未选中文字颜色
        "selectedColor": "#2979ff", //tab选中文字颜色
        "backgroundColor": "#ffffff" //tabBar背景色
      },
      //网络请求超时配置(避免请求长时间无响应)
      "networkTimeout": {
        "request": 10000, //wx.request 超时时间(毫秒),默认60000
        "downloadFile": 10000 //wx.downloadFile 超时时间(毫秒)
      },
      //权限申请说明(调用隐私相关API必备)
      "permission": {
        "scope.userLocation": {
          "desc": "你的位置信息将用于展示附近的门店" //位置权限申请时的说明文字
        }
      },
      //开启debug模式,控制台打印更多调试信息(上线前需关闭)
      "debug": true
    }
  (3)app.js,小程序全局逻辑(整个小程序的入口文件)
    App({ // 注册小程序,接受一个 Object 参数,指定全局生命周期、全局数据、全局方法等
      // 全局共享数据(核心:所有页面/组件可通过 getApp() 访问)
      globalData: {
        userInfo: null,
        token: "",
        baseUrl: "https://api.example.com"
      },
      // 生命周期回调——监听小程序初始化(全局只触发1次,小程序启动时执行)
      onLaunch(options) {
        // options.query:获取小程序启动参数(如扫码/分享进入的参数)
        console.log("小程序初始化", options);
      },
      // 生命周期回调——监听小程序启动/从后台切到前台(每次切前台都会触发)
      onShow(options) {
        // 场景:用户从微信聊天页切回小程序、首次打开小程序
        console.log("小程序显示/启动", options.scene); // options.scene 可获取启动场景(如扫码、搜索)
      },
      // 生命周期回调——监听小程序从前台切到后台(如用户退到微信聊天页、锁屏)
      onHide() {
        console.log("小程序隐藏/切后台");
      },
      // 错误监听函数:小程序发生脚本错误/API调用失败时触发
      onError(errorMsg) {
        console.error("小程序出错:", errorMsg); // errorMsg 为错误信息,可用于上报
      },
      // 页面不存在监听函数:小程序打开不存在的页面时触发(可用于页面重定向)
      onPageNotFound(res) {
        // res.path:不存在的页面路径;res.query:页面参数
        wx.redirectTo({ url: "/pages/index/index" }); // 跳转到首页
      },
      // 未处理的 Promise 拒绝事件监听函数:全局捕获未处理的 Promise 错误
      onUnhandledRejection(res) {
        // res.reason:拒绝原因;res.promise:对应的 Promise 对象
        console.error("Promise 拒绝未处理:", res.reason);
      },
      // 监听系统主题变化(如用户切换浅色/深色模式)
      onThemeChange(res) {
        console.log("系统主题变化:", res.theme); // res.theme 为 "light" 或 "dark"
      },
      // 自定义全局方法(所有页面可通过 appInstance 调用)
      getToken() {
        return this.globalData.token;
      }
    });
    附、其他页面/组件中获取小程序实例,访问全局数据/方法
    //other.js(任意页面/组件的 js 文件)
    var appInstance = getApp(); //注意:不要在App({})内部调用getApp(),可在Page/Component中调用
    console.log(appInstance.globalData.baseUrl); //访问全局数据:https://api.example.com
    console.log(appInstance.getToken()); //调用全局方法
    //修改全局数据(建议通过全局方法修改,而非直接赋值)
    appInstance.globalData.userInfo = { name: "张三" };
3、页面配置,小程序页面由4个文件组成(Page 与 Component 需严格区分)
  (1)index.wxml:页面结构(模板),负责UI展示
  (2)index.wxss:页面样式表,仅作用于当前页面(可通过样式隔离配置修改)
  (3)index.json:页面配置(如导航栏标题、注册自定义组件等)
    {
      "navigationBarBackgroundColor": "#ffffff",
      "navigationBarTextStyle": "black",
      "navigationBarTitleText": "微信接口功能演示",
      "backgroundColor": "#eeeeee",
      "backgroundTextStyle": "light"
      "pageOrientation": "auto", //手机单页面启用屏幕旋转支持
    }
  (4)index.js:页面逻辑,通过Page()构造器定义,组件用Component()
    Page({
      //1. 页面初始数据(响应式,修改需用 this.setData())
      data: {
        name: "小程序页面",
        count: 0
      },
      //2. 页面生命周期函数(核心,按执行顺序排列)
      onLoad(options) {
        // 页面加载时触发(仅触发1次),options 可获取页面跳转传参
        console.log("页面加载", options);
      },
      onShow() {
        // 页面显示/切入前台时触发(每次切回都触发)
        console.log("页面显示");
      },
      onReady() {
        // 页面初次渲染完成时触发(仅触发1次),可操作节点
        console.log("页面渲染完成");
      },
      onHide() {
        // 页面隐藏/切入后台时触发(如跳转到其他页面)
        console.log("页面隐藏");
      },
      onUnload() {
        // 页面卸载时触发(如 navigateBack 关闭当前页)
        console.log("页面卸载");
      },
    });

六、微信小程序-WXML语法参考
1、WXML标签完整分类说明
  (1)基础容器/布局标签
    A、view,通用块级容器,类似 HTML 的 <div>,用于页面布局、包裹元素,是最基础的布局标签
    B、scroll-view,可滚动容器,支持横向/纵向滚动,用于实现局部滚动列表、长内容区域滚动
    C、swiper,轮播容器,配合 <swiper-item> 实现图片轮播、页面切换等轮播效果
    D、swiper-item,轮播子项,必须嵌套在 <swiper> 内,每个子项对应一个轮播页面
    E、movable-view,可移动容器,配合 <movable-area> 实现元素拖拽、滑动(如滑块验证)
    F、movable-area,可移动区域,限定 <movable-view> 的移动范围
    G、cover-view,原生覆盖层容器,可覆盖在 <map>/<video> 等原生组件上,解决层级问题
    H、cover-image,原生覆盖层图片,配合 <cover-view> 使用,支持覆盖在原生组件上显示图片
    I、page-container,页面容器,用于实现半屏弹窗、模态页面等效果,支持页面级的弹出/收起
  (2)文本/富文本标签
    A、text,行内文本标签,类似 HTML 的 <span>,支持长按复制、空格/换行保留,专用于文本展示
    B、rich-text,富文本标签,支持渲染 HTML 格式内容(如 <p>/<img>/<a> 等),用于展示带格式的文本
    C、progress,进度条标签,展示加载进度、完成度(如文件上传进度、任务完成百分比)
  (3)表单组件标签
    A、button,按钮标签,支持点击事件、自定义样式,可调用开放能力(如获取手机号、分享、支付)
    B、input,单行输入框,用于收集文本信息(如用户名、密码、验证码),支持多种输入类型
    C、textarea,多行文本输入框,支持换行、自动增高,用于留言、备注等长文本输入
    D、checkbox,复选框,配合 <checkbox-group> 实现多选(如兴趣标签、协议勾选)
    E、checkbox-group,复选框组,统一管理多个 <checkbox>,批量获取/设置选中状态
    F、radio,单选框,配合 <radio-group> 实现单选(如性别选择、选项卡切换)
    G、radio-group,单选框组,统一管理多个 <radio>,获取/设置唯一选中项
    H、picker,选择器标签,支持普通选择器、日期/时间选择器、省市区选择器等下拉选择场景
    I、picker-view,嵌入页面的滚动选择器,自定义多列选择(如自定义时间、地址选择)
    J、slider,滑动选择器,通过滑动调整数值(如音量调节、评分、价格区间选择)
    K、switch,开关选择器,实现开/关状态切换(如消息通知开关、功能启用/禁用)
    L、label,标签关联,绑定表单元素,点击 <label> 可触发对应 <input>/<checkbox> 等的交互
    M、form,表单容器,可通过 form-type="submit" 提交表单,统一收集所有表单组件数据
    N、editor,富文本编辑器,支持图文编辑(如发布文章、编辑笔记),可插入图片、格式化文本
    O、picker-view-column,<picker-view> 的子项,定义滚动选择器的每一列内容
  (4)媒体组件标签
    A、image,图片标签,小程序专用图片展示标签,支持懒加载、裁剪、缩放等,替代 HTML 的 <img>
    B、video,视频标签,支持播放、暂停、全屏、弹幕等,原生组件,层级较高
    C、audio,音频标签,支持音频播放、暂停、循环、进度控制等音频交互
    D、camera,相机组件,调用设备摄像头,实现拍照、录制视频功能
    E、live-player,直播播放组件,播放实时直播流(如小程序直播、第三方直播源)
    F、live-pusher,直播推流组件,推送实时直播流(如用户自主开播)
    G、map,地图组件,展示地理位置、标记点、路线规划,支持定位、导航等地图交互
    H、ad,广告组件,接入微信广告体系(如激励视频广告、插屏广告、Banner 广告)
    I、canvas,画布组件,用于绘制图形、生成海报、实现自定义动画等可视化需求
    J、aria-component,无障碍组件,为视障用户提供辅助交互,提升页面可访问性
  (5)导航/跳转标签
    A、navigator,导航标签,类似 HTML 的 <a>,实现小程序内页面跳转、跳转到其他小程序/外部链接
  (6)特殊功能/逻辑控制标签
    A、block,逻辑块标签,无实际渲染效果,仅用于包裹元素,只接受控制属性wx:for/wx:if,设置class、id不会生效!!!
    B、import,模板引入标签,引入 <template> 模板文件,仅引入不渲染,需配合 <template> 使用
    C、include,代码片段引入标签,直接嵌入目标 WXML 文件的代码,实现代码复用
    D、template,模板标签,定义可复用的页面结构,通过 is 属性渲染,需传递 data 数据
    E、wxs,WXS 脚本标签,在 WXML 中嵌入小程序脚本,实现页面内的简单逻辑处理
    F、slot,插槽标签,用于自定义组件中,定义组件的内容分发位置(如默认插槽、具名插槽)
  (7)小程序扩展/开放能力标签
    A、open-data,开放数据标签,无需授权即可展示用户微信信息(如昵称、头像、性别)
    B、web-view,网页容器,嵌入外部 HTML 页面,实现小程序与 H5 页面的交互
    C、functional-page-navigator,插件功能页导航标签,跳转到小程序插件的功能页面
    D、official-account,公众号关注组件,在小程序内展示公众号关注按钮,引导用户关注
2、wx:if
  (1)使用 wx:if="" 来判断是否需要渲染该代码块:
    <view wx:if="{{condition}}"> True </view>
  (2)用 wx:elif 和 wx:else 来添加一个 else 块:
    <view wx:if="{{length > 5}}"> 1 </view>
    <view wx:elif="{{length > 2}}"> 2 </view>
    <view wx:else> 3 </view>
  (3)用一个 <block/> 标签将多个组件包装起来,并在上边使用 wx:if 控制属性
    <block wx:if="{{true}}">
      <view> view1 </view>
      <view> view2 </view>
    </block>
  (4)if与hidden,wx:if有更高的切换消耗;hidden有更高的初始渲染消耗
    <view hidden="{{flag ? true : false}}"> Hidden </view>
3、wx:for
  (1)默认数组的当前项的下标变量名默认为index,数组当前项的变量名默认为item
    <view wx:for="{{array}}">
      {{index}}: {{item.message}}
    </view>
  (2)使用wx:for-item可以指定数组当前元素的变量名,使用wx:for-index可以指定数组当前下标的变量名:
    <view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName">
      {{idx}}: {{itemName.message}}
    </view>
  (3)wx:for也可以嵌套,下边是一个九九乘法表 
    <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> 
  (4)block wx:for,渲染一个包含多节点的结构块
    <block wx:for="{{[1, 2, 3]}}">
      <view> {{index}}: </view>
      <view> {{item}} </view>
    </block>
  (5)数据
    Page({
      data: {
        array: [{
          message: 'foo',
        }, {
          message: 'bar'
        }]
      }
    })
4、import,是小程序WXML中用于引入包含命名模板文件的标签,通过<template is="模板名">调用指定的命名模板
  (1)定义模板(新建 templates/moduleName.wxml)
    <!-- templates/moduleName.wxml -->
    <!-- 定义名称为 moduleName 的模板 -->
    <template name="moduleName">
      <view class="combine-card">
        <view>基础信息:</view>
        <view>姓名:{{name}}</view>
        <view>年龄:{{age}}</view>
        <view>扩展信息:</view>
        <view>职业:{{job}}</view>
        <view>薪资:{{salary}}k</view>
        <view>
          <button bindtap="handleTemplateTap" >
            模板内按钮
          </button>
        </view>
      </view>
    </template>
  (2)页面中引入并使用模板(pages/index/index.wxml)
    <!-- pages/index/index.wxml -->
    <!-- 1. 引入模板文件 -->
    <import src="/templates/moduleName.wxml" />
    <view class="title">1. 基础对象组合(键值对形式)</view>
    <!-- 2. 调用模板,传递基础对象组合 -->
    <template is="moduleName" data="{{name: '张三', age: 25, job: '前端开发', salary: 15}}" />
    <view class="title">2. 变量+固定值组合</view>
    <!-- 3. 结合页面 data 中的变量,混合固定值 -->
    <template is="moduleName" data="{{name: userName, age: userAge, job: '后端开发', salary: 20}}" />
    <view class="title">3. 对象展开+覆盖(重点)</view>
    <!-- 4. 展开多个对象,后面的属性覆盖前面的 -->
    <template is="moduleName" data="{{...baseInfo, ...extendInfo, age: 28}}" />
    <view class="title">4. 简写形式(键值同名)</view>
    <!-- 5. 键名和变量名相同时的简写 -->
    <template is="moduleName" data="{{name, age, job, salary}}" />
  (3)页面逻辑层定义数据(pages/index/index.js)
    //pages/index/index.js
    Page({
      data: {
        //基础变量
        userName: '李四',
        userAge: 30,
        baseInfo: {
          name: '赵六',
          age: 27,
          job: '测试开发'
        },
      },
      //处理模板内的点击事件
      handleTemplateTap(e) {
        //弹窗提示
        wx.showToast({
          title: `模板点击成功`,
          icon: "none"
        });
      },
    });
5、include,是小程序WXML中用于复用完整静态页面片段的标签,把一个文件的全部内容(除<template>/<wxs>外)复制到当前位置
  (1)定义被引用的静态文件
    <!-- 路径:/components/footer.wxml -->
    <view class="footer-container">
      <view class="footer-links">
        <navigator url="/pages/home/home">首页</navigator>
        <navigator url="/pages/my/my">我的</navigator>
        <navigator url="/pages/about/about">关于我们</navigator>
      </view>
      <view class="footer-copyright">
        <text>© 2026 小程序示例 版权所有</text>
        <button bindtap="handleIncludeTap">
          Include内按钮
        </button>
      </view>
    </view>
  (2)在页面中引入(使用 <include>)
    <!-- 路径:/pages/index/index.wxml -->
    <!-- 页面主体内容 -->
    <view class="page-content">
      <text>这是首页的主体内容</text>
    </view>
    <!-- 引入底部静态片段 -->
    <include src="/components/footer.wxml" />
  (3)页面逻辑层定义数据(pages/index/index.js)
    //pages/index/index.js
    Page({
      data: {},
      //include内按钮点击事件
      handleIncludeTap(e) {
        //弹窗提示
        wx.showToast({
          title: `模板点击成功`,
          icon: "none"
        });
      },
    });
6、wxs,小程序运行分为逻辑层(运行JS代码)和视图层(渲染WXML/WXSS),之间通信损耗性能,wxs运行在视图层,无需跨线程通信,
  附、不能使用wx.xxxx方法!!!
  (1)内联定义与使用
    //页面WXML(pages/index/index.wxml)
    <wxs module="wxsTools">
      var defaultTip = "暂无数据";
      var formatTime = function(timestamp) {
        if (typeof timestamp !== 'number') {
          return defaultTip;
        }
        var date = getDate(timestamp); //WXS内置getDate,替代new Date
        var year = date.getFullYear();
        var month = date.getMonth() + 1;
        var day = date.getDate();
        month = month < 10 ? '0' + month : month;
        day = day < 10 ? '0' + day : day;
        return year + '-' + month + '-' + day;
      };
      module.exports = {
        defaultTip: defaultTip,
        formatTime: formatTime,
      };
    </wxs>
    <view class="container">
      <view class="card">
        <text class="card-title">WXS 变量使用:</text>
        <view>{{wxsTools.defaultTip}}</view>
      </view>
      <view class="card">
        <text class="card-title">时间格式化:</text>
        <view>原始时间戳:1735689600000</view>
        <view>格式化后:{{wxsTools.formatTime(1735689600000)}}</view>
        <view>无效参数:{{wxsTools.formatTime('abc')}}</view>
      </view>
    </view>
  (1)外联定义与使用
    A、定义
      //utils/commonTools.wxs
      var formatPrice = function(price) {
        //WXS仅支持ES5,用var声明变量
        if (typeof price !== 'number') {
          price = parseFloat(price) || 0;
        }
        //补零处理,确保两位小数
        var fixedPrice = price.toFixed(2);
        return '¥' + fixedPrice;
      };
      //必须导出:暴露需要被外部调用的函数(核心)
      module.exports = {
        formatPrice: formatPrice,
      };
    B、使用
      //pages/index/index.wxml<!-- 核心:引入外联WXS文件(绝对路径) -->
      <wxs src="/utils/commonTools.wxs" module="tools" />
      <view class="container">
        <view class="card">
          <text class="card-title">价格格式化:</text>
          <view>原始值 99 → {{tools.formatPrice(99)}}</view>
          <view>原始值 128.5 → {{tools.formatPrice(128.5)}}</view>
          <view>无效值 'abc' → {{tools.formatPrice('abc')}}</view>
        </view>
      </view>
7、常用事件!!!
  <view>
    <view>
      <text>1. 触摸类事件</text>
      <!-- 1.1 点击事件(tap):轻触即触发,最基础 -->
      <button bindtap="handleTap" data-type="tap">点击事件(tap)</button>
      <!-- 1.2 长按事件(longpress):按住2秒触发 -->
      <button bindlongpress="handleLongPress" data-type="longpress">长按事件(longpress)</button>
      <!-- 1.3 触摸过程事件:start/move/end -->
      <view 
        bindtouchstart="handleTouchStart"
        bindtouchmove="handleTouchMove"
        bindtouchend="handleTouchEnd"
        data-type="touch"
      >
        触摸区域(滑动/点击):触发 touchstart/move/end
      </view>
      <!-- 1.4 事件冒泡 vs 阻止冒泡(bind/catch) -->
      <view bindtap="handleParentTap">
        父容器(bindtap,允许冒泡)
        <button bindtap="handleChildTap">子按钮(bindtap,冒泡)</button>
        <button catchtap="handleChildCatchTap">子按钮(catchtap,阻止冒泡)</button>
      </view>
    </view>
    <view>
      <text>2. 输入类事件</text>
      <!-- 2.1 输入框内容变化(input):实时触发 -->
      <input 
        bindinput="handleInput" 
        placeholder="输入内容触发input事件" 
        value="{{inputValue}}"
      />
      <view>当前输入:{{inputValue}}</view>
      <!-- 2.2 输入框确认(confirm):点击回车/完成触发 -->
      <input 
        bindconfirm="handleConfirm" 
        placeholder="输入后按回车触发confirm" 
      />
      <!-- 2.3 多行文本输入(textarea):同input,支持换行 -->
      <textarea 
        bindinput="handleTextareaInput" 
        placeholder="多行文本输入(textarea)" 
        value="{{textareaValue}}"
      />
    </view>
    <view>
      <text>3. 表单类事件</text>
      <!-- 3.1 复选框组(checkbox-group):选中状态变化触发 -->
      <checkbox-group bindchange="handleCheckboxChange">
        <view>
          <checkbox value="apple" />苹果
          <checkbox value="banana" />香蕉
          <checkbox value="orange" />橙子
        </view>
      </checkbox-group>
      <view>已选水果:{{checkboxValue.join(', ')}}</view>
      <!-- 3.2 单选框组(radio-group):选中变化触发 -->
      <radio-group bindchange="handleRadioChange">
        <view>
          <radio value="male" />男
          <radio value="female" />女
        </view>
      </radio-group>
      <view>选中性别:{{radioValue}}</view>
      <!-- 3.3 开关选择器(switch):开关状态变化触发 -->
      <switch bindchange="handleSwitchChange" />
      <view>开关状态:{{switchValue ? '开' : '关'}}</view>
      <!-- 3.4 滑动选择器(slider):滑动数值变化触发 -->
      <slider bindchange="handleSliderChange" min="0" max="100" />
      <view>滑块值:{{sliderValue}}</view>
      <!-- 3.5 选择器(picker):选择完成触发 -->
      <picker mode="selector" range="{{['北京','上海','广州']}}" bindchange="handlePickerChange">
        <button>城市选择器(picker)</button>
      </picker>
      <view>选中城市:{{pickerValue}}</view>
      <!-- 3.6 表单提交/重置 -->
      <form bindsubmit="handleFormSubmit" bindreset="handleFormReset">
        <button form-type="submit">提交表单</button>
        <button form-type="reset">重置表单</button>
      </form>
    </view>
    <view>
      <text>4. 页面交互类事件</text>
      <!-- 4.1 滚动视图(scroll-view):滚动触发 -->
      <scroll-view 
        scroll-y 
        style="height: 100rpx;" 
        bindscroll="handleScroll"
      >
        <view style="height: 200rpx;">滚动我触发scroll事件</view>
      </scroll-view>
      <!-- 4.2 轮播图(swiper):切换触发 -->
      <swiper bindchange="handleSwiperChange">
        <swiper-item>轮播1</swiper-item>
        <swiper-item>轮播2</swiper-item>
      </swiper>
      <view>当前轮播索引:{{swiperIndex}}</view>
    </view>
  </view>

七、微信小程序-自定义组件
1、整体目录结构
  ├── components //自定义组件目录(约定俗成)
  │   └── my-card //组件名(小写+横线,规范命名)
  │       ├── my-card.wxml //组件结构
  │       ├── my-card.js //组件逻辑
  │       ├── my-card.json //组件配置
  │       └── my-card.wxss //组件样式
  └── pages
      └── index //使用组件的页面
          ├── index.wxml //页面结构(引用组件)
          ├── index.js //页面逻辑
          ├── index.json //页面配置(注册组件)
          └── index.wxss //页面样式
2、自定义组件的定义(components/my-card/ 下的 4 个文件)
  (1)组件结构文件:my-card.wxml
    <!-- 组件内部结构 -->
    <view class="card-container">
      <!-- 接收父页面传递的属性 -->
      <view class="card-title">{{title}}</view>
      <view class="card-content">{{content}}</view> 
      <!-- 组件内部按钮,触发自定义事件传递给父页面 -->
      <button bindtap="handleCardClick" data-id="{{cardId}}">点击组件按钮</button>
    </view>
  (2)组件样式文件:my-card.wxss
    /* 组件样式,默认不会影响页面,页面样式也不会影响组件 */
    .card-container {
      padding: 20rpx;
      background: #f5f5f5;
      border-radius: 10rpx;
      margin: 10rpx 0;
    }
    .card-title {
      font-size: 32rpx;
      font-weight: bold;
      margin-bottom: 10rpx;
    }
    .card-content {
      font-size: 28rpx;
      color: #666;
      margin-bottom: 15rpx;
  (3)组件配置文件:my-card.json,声明当前文件是「自定义组件」
    {
      "component": true, //必选,标记为自定义组件
      "usingComponents": {} //组件内可引用其他自定义组件(此处为空)
    }
  (4)组件逻辑文件:my-card.js
    Component({ //页面用Page()
      //接收父页面传递的属性(必选,需声明类型/默认值)
      properties: {
        title: {
          type: String, //属性类型(String/Number/Boolean/Object等)
          value: "默认标题" //默认值
        },
        content: {
          type: String,
          value: "默认内容"
        },
        cardId: {
          type: Number,
          value: 0
        }
      },
      //组件内部数据(类似页面的data)
      data: {
        innerText: "组件内部私有数据"
      },
      //组件生命周期(仅组件特有)
      lifetimes: {
        attached() {
        //组件挂载到页面时触发(常用:初始化数据)
          console.log("my-card组件挂载完成");
        },
        detached() {
          //组件从页面移除时触发
          console.log("my-card组件被移除");
        }
      },
      //组件内部方法(处理事件)
      methods: {
        //组件内部点击事件,触发自定义事件给父页面
        handleCardClick(e) {
          const id = e.currentTarget.dataset.id;
          //触发自定义事件!!!,传递参数给父页面
          this.triggerEvent("mycardtap", { id: id, msg: "组件触发的事件" });
          //组件内部提示(仅组件内可见)
          wx.showToast({ title: "组件内部点击", icon: "none" });
        }
      }
    });
3、自定义组件的使用(pages/index/下的4个文件)
  (1)页面配置文件:index.json,注册要使用的自定义组件(必选)
    {
      "navigationBarTitleText": "自定义组件使用示例",
      "usingComponents": {
        //注册组件:组件标签名 → 组件路径(绝对路径/相对路径)
        "my-card": "/components/my-card/my-card"
      }
    }
  (2)页面结构文件:index.wxml
    <view class="page-container">
      <!-- 1. 使用自定义组件:传递属性 + 绑定自定义事件 -->
      <my-card 
        title="自定义组件标题" 
        content="这是父页面传递的内容" 
        cardId="1001"
        bind:mycardtap="handleCardEvent"  <!-- 绑定自定义事件!!! -->
      ></my-card>
      <!-- 2. 复用组件:传递不同属性 -->
      <my-card 
        title="第二个组件实例" 
        content="组件支持复用,属性独立" 
        cardId="1002"
        bind:mycardtap="handleCardEvent"
      ></my-card>
      <!-- 显示组件传递的参数 -->
      <view class="event-msg">组件传递的参数:{{eventMsg}}</view>
    </view>
  (3)页面逻辑文件:index.js
    Page({
      data: {
        eventMsg: "暂无事件"
      },
      //处理组件触发的自定义事件
      handleCardEvent(e) {
        //获取组件传递的参数
        const { id, msg } = e.detail;
        this.setData({
          eventMsg: `ID:${id},消息:${msg}`
        });
        //页面级提示
        wx.showToast({ title: `接收组件事件:ID=${id}`, icon: "none" });
      },
      onLoad() {
        console.log("页面加载,组件已注册并渲染");
      }
    });
  (4)页面样式文件:index.wxss
    .page-container {
      padding: 20rpx;
    }
    .event-msg {
      margin-top: 20rpx;
      font-size: 28rpx;
      color: #e64340;
    }      

八、微信小程序-API
附、不能用在wxs标签下!!!
1、基础交互类(用户反馈)
  (1)wx.showToast,显示轻提示(如操作成功/失败,自动消失)
  (2)wx.showModal,显示模态弹窗(含确认/取消按钮,用于关键操作确认)
  (3)wx.showLoading,显示加载提示(需手动调用 wx.hideLoading 关闭)
  (4)wx.hideLoading,关闭 wx.showLoading 触发的加载提示
  (5)wx.showActionSheet,显示底部操作菜单(多选项选择场景)
2、路由跳转类(页面导航)
  (1)wx.navigateTo,保留当前页,跳转到小程序内非 tabBar 页面
  (2)wx.redirectTo,关闭当前页,跳转到小程序内非 tabBar 页面
  (3)wx.switchTab,跳转到 tabBar 页面(必用,无法用其他跳转 API 替代)
  (4)wx.navigateBack,返回上一页/多级页面(可通过 delta 指定返回层级)
  (5)wx.reLaunch,关闭所有页面,跳转到小程序内任意页面
3、网络请求类(数据交互)
  (1)wx.request,发起 HTTPS 请求(获取/提交后端数据,需配置合法域名)
  (2)wx.uploadFile,上传文件(如图片、视频,支持多文件上传)
  (3)wx.downloadFile,下载文件(如图片、文档,可指定保存路径)
4、数据缓存类(本地存储)
  (1)wx.setStorageSync,同步存储本地数据(简单场景优先使用)
  (2)wx.getStorageSync,同步获取本地存储的指定数据
  (3)wx.removeStorageSync,同步删除本地存储的指定数据
  (4)wx.clearStorageSync,清空当前小程序所有本地存储数据
5、设备能力类(调用硬件/信息)
  (1)wx.getSystemInfoSync,同步获取设备信息(机型、系统版本、屏幕尺寸等)
  (2)wx.getLocation,获取用户地理位置(需用户授权,支持高德/腾讯坐标)
  (3)wx.chooseImage,让用户选择/拍摄图片(可指定张数、尺寸)
  (4)wx.previewImage,预览图片(支持多图滑动预览)
  (5)wx.makePhoneCall,调用系统拨打电话功能(需传入手机号)
6、媒体操作类(音视频/图片)
  (1)wx.playVoice,播放本地/临时语音文件
  (2)wx.pauseVoice,暂停正在播放的语音
  (3)wx.chooseVideo,让用户选择/拍摄视频(可指定时长、分辨率)
  (4)wx.saveImageToPhotosAlbum,保存图片到系统相册(需用户授权)
7、开放能力类(微信生态)
  (1)wx.login,获取微信登录凭证(code),用于换取用户openid
  (2)wx.getUserProfile,获取用户微信昵称、头像等信息(需用户主动授权)
  (3)wx.requestPayment,发起微信支付(需对接支付后台)
  (4)wx.shareAppMessage,触发小程序转发给好友的弹窗

九、uniapp跨端框架
1、DCloud(数字天堂)
  (1)2012年,成立,核心布局HTML5开发工具与跨端技术
  (2)2014年,推出HBuilder开发工具!!!
  (3)2015年,商用「流应用」小程序技术并推动行业标准
  (-)2017年1月,微信小程序正式发布,采用自有技术标准,仅能在微信生态运行
  (4)2018年8月,发布uni-app1.0,支持微信小程序、H5、iOS、Android
    A、定位为跨端框架,抹平各平台差异
    B、支持一套代码运行于多端(小程序/APP/H5等)
    C、开发工具为HBuilder
    D、基于Vue框架
  (5)2019年,发布uni-app2.0,新增对支付宝小程序的支持
  (6)2020年,发布uni-app3.0,新增对5个新平台的支持,如头条小程序、QQ小程序等
  (7)2021年,发布uni-app4.0,新增对Flutter Web平台的支持 
2、uni-app标签完整分类说明
  (1)基础布局类(页面结构核心)
    A、view,对应div,通用块级容器,用于布局、分组元素(页面结构的基础积木)
    B、scroll-view,对应div+overflow:scroll,可滚动容器,实现横向/纵向滚动(如长列表、横向滑动栏)
    C、swiper,无直接对应(需JS实现),轮播图容器,搭配swiper-item使用(如首页轮播、banner图)
    D、swiper-item,无直接对应,轮播图的每一项,嵌套在swiper内
    E、block,无(虚拟节点),仅逻辑包装,不渲染(用于v-for/v-if包裹元素,不产生实际DOM)
  (2)内容展示类(文本/图标/链接)
    A、text,对应span,行内文本容器(仅支持文本,不能嵌套块级元素)
    B、rich-text,对应div+innerHTML,渲染富文本(如包含HTML标签的内容,支持nodes属性传富文本数据)
    C、icon,对应i/字体图标,内置图标(如成功、失败、加载),也可自定义图标
    D、progress,对应progress,进度条(如加载进度、上传进度、任务完成度)
    E、navigator,对应a,页面跳转链接(替代a标签,支持uni-app路由规则)
  (3)表单交互类(用户输入/操作)
    A、button,对应button,按钮(支持开放能力如分享、获取用户信息,跨端样式统一)
    B、input,对应input,单行输入框(支持文本、密码、数字、手机号等类型)
    C、textarea,对应textarea,多行文本输入框(支持自动高度、字数限制、换行)
    D、picker,无直接对应,选择器(日期、时间、省市区、自定义列表选择)
    E、picker-view,无直接对应,内嵌式选择器(如页面内的日期选择面板,不弹出)
    F、checkbox,对应input type="checkbox",复选框(需搭配checkbox-group使用)
    G、radio,对应input type="radio",单选框(需搭配radio-group使用)
    H、switch,对应input type="checkbox"+样式,开关选择器(如开启/关闭功能)
    I、slider,对应input type="range",滑动选择器(如音量调节、评分、数值选择)
    J、form,对应form,表单容器,用于提交多个表单组件的值
  (4)媒体类(图片/音视频)
    A、image,对应img,图片展示(支持懒加载、裁剪、缩放,跨端适配性更强)
    B、video,对应video,视频播放(支持全屏、自动播放、控制栏自定义)
    C、audio,对应audio,音频播放(小程序/App端支持后台播放)
    D、camera,无直接对应,相机组件(调用设备摄像头,拍摄照片/视频)
  (5)导航与反馈类
    A、navigation-bar,对应header/自定义导航,自定义页面导航栏(替代默认导航栏)
    B、tabbar,无直接对应,自定义底部标签栏(替代pages.json配置的tabBar)
    C、toast,无(JS实现),轻提示(一般用uni.showToast()API,标签版需自定义)
    D、modal,无(JS实现),模态弹窗(一般用uni.showModal()API)
  (6)特殊场景类
    A、canvas,对应canvas,画布(绘制图形、生成海报、小游戏开发)
    B、map,无直接对应,地图组件(调用高德/腾讯地图,显示位置、标记点、路线)
    C、web-view,无直接对应,内嵌网页容器(在小程序/App中加载外部H5页面)
    D、ad,无直接对应,广告组件(接入各平台广告,如微信小程序广告、App开屏广告)
3、项目
  (1)HBuilderX操作步骤
    A、新建uni-app项目:选择「空白模板」,命名为simple-app
    B、创建页面:在pages目录下新建list、detail文件夹,分别创建list.vue、detail.vue
    C、替换代码:将下4代码分别复制到对应文件中
    D、运行项目:点击「运行」→选择「浏览器」/「微信小程序模拟器」即可
  (2)整体结构(HBuilderX中创建)
    simple-app //项目根目录
    ├── pages 
    │   ├── index //首页
    │   │   └── index.vue       
    │   ├── list //列表页
    │   │   └── list.vue        
    │   └── detail //详情页
    │       └── detail.vue      
    ├── static //静态资源(空目录即可)
    ├── App.vue //应用入口
    ├── main.js //应用初始化
    └── pages.json //页面路由配置
  (3)功能说明
    A、页面路由:pages.json配置3个页面,首页为默认启动页
    B、页面跳转
      a、组件方式:<navigator>标签跳转(替代HTML的<a>)
      b、API方式:uni.navigateTo跳转、uni.navigateBack返回
    C、数据传递:列表页通过URL拼接参数传递给详情页,详情页通过onLoad(options)接收
    D、数据渲染:列表页用v-for渲染模拟数据,详情页展示接收的参数
    E、基础布局:rpx单位(跨端适配)、flex布局
4、核心文件代码(直接复制使用)
  (1)pages.json(页面路由配置,核心:定义 3 个页面 + 导航栏)
    {
      "pages": [
        //首页(默认启动页)
        {
          "path": "pages/index/index",
          "style": {
            "navigationBarTitleText": "首页"
          }
        },
        //列表页
        {
          "path": "pages/list/list",
          "style": {
            "navigationBarTitleText": "列表页"
          }
        },
        //详情页
        {
          "path": "pages/detail/detail",
          "style": {
            "navigationBarTitleText": "详情页"
          }
        }
      ],
      "globalStyle": {
        "navigationBarTextStyle": "black",
        "backgroundColor": "#f5f5f5"
      }
    }
  (2)main.js(应用初始化)
    import Vue from 'vue'
    import App from './App.vue'
    Vue.config.productionTip = false
    new Vue({
      el: '#app',
      render: h => h(App)
    })
  (3)App.vue(应用入口)
    <template>
      <router-view></router-view>
    </template>
    <script>
      export default {
        onLaunch() {
          console.log('App启动')
        }
      }
    </script>
    <style>
      /* 全局基础样式 */
      page {
        padding: 20rpx;
      }
    </style>
  (4)pages/index/index.vue(首页:跳转到列表页)
    <template>
      <view class="index-container">
        <view class="title">首页</view>
        <!-- 按钮跳转列表页:方式1 - navigator组件 -->
        <navigator url="/pages/list/list" class="btn">
          跳转到列表页(组件方式)
        </navigator>
        <!-- 按钮跳转列表页:方式2 - API跳转 -->
        <button @click="toListPage" class="btn">
          跳转到列表页(API方式)
        </button>
      </view>
    </template>
    <script>
      export default {
        methods: {
          //API方式跳转列表页
          toListPage() {
            uni.navigateTo({
              url: '/pages/list/list'
            })
          }
        }
      }
    </script>
    <style scoped>
      /* 仅保留布局样式 */
      .index-container {
        display: flex;
        flex-direction: column;
        gap: 20rpx;
      }
      .title {
        font-size: 32rpx;
        margin-bottom: 20rpx;
      }
      .btn {
        padding: 15rpx;
        border: 1px solid #ccc;
        text-align: center;
        text-decoration: none;
        color: #000;
      }
    </style>
  (5)pages/list/list.vue(列表页:展示数据+跳转到详情页并传参)
    <template>
      <view class="list-container">
        <view class="title">列表页</view>
        <!-- 列表数据渲染 -->
        <view class="list-item" v-for="(item, index) in listData" :key="index" @click="toDetailPage(item)">
          {{ item.name }} - {{ item.id }}
        </view>
        <!-- 返回首页 -->
        <button @click="backHome" class="btn">返回首页</button>
      </view>
    </template>
    <script>
      export default {
        data() {
          return {
            //模拟列表数据
            listData: [
              { id: 1, name: '商品1', desc: '这是商品1的详情' },
              { id: 2, name: '商品2', desc: '这是商品2的详情' },
              { id: 3, name: '商品3', desc: '这是商品3的详情' }
            ]
          }
        },
        methods: {
          //跳转到详情页并传递数据
          toDetailPage(item) {
            uni.navigateTo({
              //传递参数(拼接在url后)
              url: `/pages/detail/detail?id=${item.id}&name=${item.name}&desc=${item.desc}`
            })
          },
          //返回首页
          backHome() {
            uni.navigateBack({
              delta: 1 //返回上一级页面(首页)
            })
          }
        }
      }
    </script>
    <style scoped>
      /* 仅保留布局样式 */
      .list-container {
        display: flex;
        flex-direction: column;
        gap: 15rpx;
      }
      .title {
        font-size: 32rpx;
        margin-bottom: 20rpx;
      }
      .list-item {
        padding: 15rpx;
        border: 1px solid #ccc;
      }
      .btn {
        padding: 15rpx;
        border: 1px solid #ccc;
        margin-top: 20rpx;
      }
    </style>
  (6)pages/detail/detail.vue(详情页:接收列表页传递的参数)
    <template>
      <view class="detail-container">
        <view class="title">详情页</view>
        <!-- 展示接收的参数 -->
        <view class="detail-item">ID:{{ detailData.id }}</view>
        <view class="detail-item">名称:{{ detailData.name }}</view>
        <view class="detail-item">描述:{{ detailData.desc }}</view>
        <!-- 返回列表页 -->
        <button @click="backList" class="btn">返回列表页</button>
      </view>
    </template>
    <script>
      export default {
        data() {
          return {
            detailData: {
              id: '',
              name: '',
              desc: ''
            }
          }
        },
        //页面加载时接收参数
        onLoad(options) {
          //options 是跳转时传递的参数对象
          this.detailData = {
            id: options.id,
            name: options.name,
            desc: options.desc
          }
        },
        methods: {
          //返回列表页
          backList() {
            uni.navigateBack({
              delta: 1 //返回上一级页面(列表页)
            })
          }
        }
      }
    </script>
    <style scoped>
      /* 仅保留布局样式 */
      .detail-container {
        display: flex;
        flex-direction: column;
        gap: 15rpx;
      }
      .title {
        font-size: 32rpx;
        margin-bottom: 20rpx;
      }
      .detail-item {
        padding: 10rpx 0;
        border-bottom: 1px solid #eee;
      }
      .btn {
        padding: 15rpx;
        border: 1px solid #ccc;
        margin-top: 20rpx;
      }
    </style>
  

  

posted @ 2020-10-27 00:25  WEB前端工程师_钱成  阅读(6944)  评论(0)    收藏  举报