14、电脑相关、移动端基础(术语|长度单位|设备像素|倍图)、vant-ui相关、微信公众平台、微信小程序-目录说明|WXML语法|WXS语法|事件系统|组件|自定义组件|API、uniapp跨端框架-简介|教程|组件|全局文件、postcss.config.js(2750行)

附、电脑相关
  (1)查看命令行:win+r; cmd; 确定
  (2)查看电脑配置:win+r; msinfo32; 确定
  (3)windows10系统输入法切换的快捷键设置步骤:至少有2种输入法同时备用
    A、开始-齿轮-时间和语言-语言-中文(简体中国)-选项-(添加键盘-微软拼音-)微软拼音-选项-按键-模式切换
  (4)搜狗输入法的快捷键界面:S图标-更多设置-属性设置-按键
    A、中英切换
    B、系统功能快捷键-系统功能快捷键设置
  (5)广告屏保的位置与删除
    A、重启
    B、此电脑-(上方中间的)查看-显示-隐藏的项目
    C、打开,C:\Users\制造商(NINGMEI)\AppData\Local\Temp
    D、删除该位置下的所有文件
  (6)谷歌截全屏的步骤
    A、F12
    B、ctrl+shift+p
    C、输入full
    D、点击Capture full size screenshot
    另,免费在线网页转图片,https://www.url2pic.com/url2pic/index.html
  (7)postcss-pxtorem,px转rem

一、移动端基础
1、移动端的常用术语
  (1)Uni,统一的,读you ni
  (2)IDE,集成开发环境(Integrated Development Environment),如vscode
  (3)SDK,软件开发工具包(Software Development Kit),软件开发时,开发工具的集合,通常由编译器、调试器和应用编程接口组成 
  (4)uniCloud,基于serverless的云开发平台,为开发者提供免费服务器,由DCloud(数字天堂)、阿里云、腾讯云三者联合实现
2、移动端的长度单位(vw、vh、vmin、vmax、%、em、rem、dp、pt、rpx、dot、dpi、ppi、Retina)
   附、px,通用长度单位,像素,pixel,/ˈpɪksl/
  (1)通用
    A、vw,viewpoint width,视窗宽度,1vw等于视窗宽度的1%,如width: calc(100vw - 260px);font-size: 5vw;
    B、vh,viewpoint height,视窗高度,1vh等于视窗高度的1%,如height: calc(100vh - 260px);font-size: 5vh;
    C、vmin,vw和vh中较小的那个,font-size: vw,文字在横、竖屏下,大小不一致
    D、vmax,vw和vh中较大的那个,font-size: vmax,文字在横、竖屏下,大小一致
    E、%,相对于父元素的尺寸
    F、em,相对于父字体大小
    G、rem,相对于根字体大小
  (2)专用
    A、dp,Android长度单位,'ppi/160'px;sp,Android字体大小单位
    B、pt,IOS长度单位,'ppi/163'px;自然界的长度单位,1/72英寸,0.35毫米
    C、rpx,微信长度单位,1rpx=1/750的屏宽
  (3)其它
    A、dot,点,印刷品的最小单位
    B、dpi,点密度,每英寸屏幕所包含的点数,Dots per inch
    C、ppi,像素密度,每英寸屏幕所包含的像素数,Pixels per inch
    D、retina display技术,视网膜显示技术,就是像素密度大一些而已
      iPhone6将一个像素点分拆为四个像素进行显示,像素密度提高4倍,达到326ppi,超过人眼能区分的最大像素密度300ppi
      //简单说就是,一个物理像素占位面积小一点,单位面积物理像素多一点;用pxtorem后,字体占位面积不变,但因包含像素多,因而更清晰=====文字、图片=====
   附、rem,示例
    <style>
      //根字体定义一
      html { font-size: 20px; }
      //根字体定义二
      :root { font-size: 20px; }
    </style>
    <script>
      //根字体定义三
      var designWidth = 1000 ;
      document.documentElement.style.fontSize = document.documentElement.clientWidth/designWidth+"px";
      //代码尺寸为1rem,对应设计稿尺寸为1px
    </script>
    //postcss.config.js里的相关配置
    require('postcss-pxtorem')({//px转rem
      rootValue: 37.5, //对应设计图宽度375px
      propList: ['*'], //将哪些属性的px值转换
    })
3、物理像素比 
  (1)像素,显示屏图像或CSS图像的最小单位,单位是px,包含
    A、物理像素
    B、逻辑像素
  (2)物理像素,也叫设备像素,显示屏的最小可控制单元
    附、分辨率,纵横方向的物理像素点数 
      A、1K显示屏(分辨率,1920*1080)
      B、2K显示屏(分辨率,2560*1440)
      C、4K显示屏(分辨率,3840*2160)
  (3)逻辑像素,也叫CSS像素,CSS的最小可控制单元,正常情况下,1个物理像素显示1个逻辑像素
  (4)物理像素比,也叫设备像素比(window.devicePixelRatio),物理像素/逻辑像素,含义是几个物理像素显示1个逻辑像素
    A、公司4K、21.5寸屏幕,1个物理像素小,缩放设为200%,2个物理像素显示1个逻辑像素;媒体查询2k,左300,右970,中间剩余像素
    B、住处4K、43.0寸屏幕,1个物理像素大,缩放设为100%,1个物理像素显示1个逻辑像素;媒体查询4k,左200,右485,中间剩余像素
    C、综合分辨率、尺寸、缩放后,上面两者字体大小一样
    D、console.log(window.devicePixelRatio)
4、倍图(是正常像素密度的几倍,就用几倍图)
  (1)正常情况下的对应关系
    A、一倍图:设计稿1,宽度750*1px;分辨率1,x*y
    B、二倍图:设计稿2,宽度750*2px;分辨率2,2x*2y
    C、三倍图:设计稿3,宽度750*3px;分辨率3,3x*3y
    D、四倍图:设计稿4,宽度750*4px;分辨率4,4x*4y,如iPhone6,其物理像素比为1,
  (2)真实项目:一张设计稿3,适配分辨率1、分辨率2、分辨率3、的显示屏,
    A、处理方案1,给1种分辨率写1套代码,先判断屏幕分辨率,再导入代码
      分辨率1显示屏的div宽高用设计稿尺寸的1/3,背景图片用设计稿原图片尺寸的100%填充
      分辨率2显示屏的div宽高用设计稿尺寸的2/3,背景图片用设计稿原图片尺寸的100%填充
      分辨率3显示屏的div宽高用设计稿尺寸的3/3,背景图片用设计稿原图片尺寸的100%填充
    B、处理方案2,以px为单位,用postcss-pxtorem把px转换成rem,使各种分辨率,如安卓、IOS的屏幕,显示相同效果
      div宽高用设计稿尺寸的1/3,背景图片用设计稿原图片尺寸的100%填充
    附、代码,背景图片用设计稿原图片尺寸的100%填充,//=====文字、图片=====
      //下面,设计稿1的图片放在分辨率1的显示屏上,效果是1个逻辑像素被放到1个物理像素里显示;像素密度不变,正常显示
      //下面,设计稿2的图片放在分辨率1的显示屏上,效果是4个逻辑像素被压缩到1个物理像素里显示;像素密度不变,正常显示
      //下面,设计稿2的图片放在分辨率2的显示屏上,效果是1个逻辑像素被放到1个物理像素里显示;像素密度变大,高清显示
      background-image: url(example@2x.png) no-repeat;
      background-size: 100% auto;
5、特别注意
  (1)移动端项目
    A、各个页面的跳转关系
    B、数据临时存储与清除
    C、静态数据的来源(设计稿或后台)
  (2)存储临时数据,以备后退时使用
    A、确定时,用localStorage存储数据
    B、后退时,用localStorage获取数据
    C、提交后,用localStorage删除数据
    D、也可以用vuex存储、获取、删除数据 
  (3)iPhone12pro max,跳到新网页,新网页的位置没到顶
    A、原因:跳转前的网页没到顶,浏览器把前网页的位置用在后网页上
    B、解决:document.body.scrollTop=0; document.documentElement.scrollTop=0;

二、vant-ui相关
1、<input type="value">
  (1)button,定义可点击按钮(多数情况下,用于通过 JavaScript 启动脚本)
  (2)checkbox,定义复选框
  (3)file,定义输入字段和 "浏览"按钮,供文件上传
  (4)hidden,定义隐藏的输入字段,发送表单的时候,隐藏域的信息也被一起发送到服务器,
    https://blog.csdn.net/weixin_38098192/article/details/90265302
  (5)image,定义图像形式的提交按钮
  (6)password,定义密码字段,该字段中的字符被掩码
  (7)radio,定义单选按钮
  (8)reset,定义重置按钮,重置按钮会清除表单中的所有数据
  (9)submit,定义提交按钮,提交按钮会把表单数据发送到服务器
  (10)text,定义单行的输入字段,用户可在其中输入文本,默认宽度为20个字符
2、深度选择器
  当<style scoped>只作用于当前组件中的元素,可采用下列方式影响到子组件
  附、全局样式
    <style>
      .wrap .child {
        color: red;
      }
    </style>
  (1)本页样式 >>> ,原生css支持,sass/less可能无法识别
    <style scoped>
      .wrap >>> .child {
        color: red;
      }
    </style>
  (2)本页样式 /deep/ ,sass/less可识别,在vue 3.0会报错
    <style scoped>
      .wrap /deep/ .child {
        color: red;
      }
    </style>
  (3)本页样式 ::v-deep ,vue 3.0支持,编译速度快 
    <style scoped>
      .wrap ::v-deep .child {
        color: red;
      }
    </style>
3、vant-ui动态内容
  (1)notify 消息提示,没有遮罩,页面顶部显示,有样式变化,3秒后自动消失
  (2)toast 轻提示,没有遮罩,页面居中显示,无样式变化,3秒后自动消失
  (3)NoticeBar 通知栏,没有遮罩,固定位置显示,有样式变化,不消失
  (4)Popover 气泡弹出框,没有遮罩,点击处显示,会基于reference插槽的内容进行定位,常用于下拉选项,
  (5)overlay 遮罩层,全屏罩住
  (6)popup 弹出层,有遮罩,常用触底显示,确认后消失,常用于省市县、日期选择
  (7)dialog 弹出框,有遮罩,常用居中显示,确认后消失
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)required,是否为必选字段,boolean
  (2)message,错误提示文案
  (3)trigger,本项规则的触发时机,可选值为onChange、onBlur
  (4)formatter,格式化函数,将表单项的值转换后,再用“pattern”或“validator”进行校验
  (5)pattern,通过正则表达式进行校验,返回值为false时,红色的message出现在输入框的下方
  (6)validator,通过函数进行校验,返回值为false时,机制让红色的message出现在输入框的下方;
    返回值为promise实例时,机制向其注入resolve、reject,在reject里让红色的message出现在输入框的下方
    validator:function(rule, val, callback) {
      return new Promise(function(resolve, reject) {
        setTimeout(function() {
          const dataNum = Date.now()
          if (dataNum % 2 === 0) {
            resolve('成功')
          } else {
            reject('失败')
          }
        }, 2000)
      })
    }
5、插槽input示例
(1)html部分
  <van-form @submit="beforeSubmit" ref="form">
    <template v-for="(item,idx) in formList">
      <div class="sign-form" :key="idx" v-if="item.inputType == 0">
        <van-field name="name" :rules="[{ validator: valiFormData, message: '请输入正确内容',index:idx }]" show-word-limit
              :label="item.topicName" v-model="formData[idx]" :placeholder="'请输入'+item.topicName" :maxlength="item.numLimit" />
      </div>
      <div class="sign-form" :key="idx" v-if="item.inputType == 1">
        <van-field rows="4" :rules="[{ validator: valiFormData, message: '请输入正确内容',index:idx }]" autosize
              v-model="formData[idx]" :label="item.topicName" type="textarea" show-word-limit />
      </div>
      <div class="sign-form" :key="idx" v-if="item.inputType == 2">
        <van-field :label="item.topicName" v-model="formData[idx]" right-icon="arrow-down" readonly placeholder="请选择"
              :rules="[{ validator: valiFormData, message: '请输入正确内容',index:idx }]" @click="changeCol(idx)" />
      </div>
      <div class="sign-form" :key="idx" v-if="item.inputType == 3 && item.isCheckbox == 0">
        <van-field :label="item.topicName" :rules="[{ validator: valiFormData, message: '请输入正确内容',index:idx }]">
          <template #input>
            <van-radio-group v-model="formData[idx]" direction="horizontal" class="hor-style">
              <van-radio v-for="(v,k) in JSON.parse(item.optionInfo)" :name="v.option" :key="k">{{v.option}}</van-radio>
            </van-radio-group>
          </template>
        </van-field>
      </div>
      <div class="sign-form" :key="idx" v-if="item.inputType == 3 && item.isCheckbox == 1">
        <van-field :label="item.topicName" :rules="[{ validator: valiFormData, message: '请输入正确内容',index:idx }]">
          <template #input>
            <van-checkbox-group v-model="formData[idx]" :max="item.selectLimitMax ? item.selectLimitMax : 0" direction="horizontal">
              <van-checkbox v-for="(value,key) in JSON.parse(item.optionInfo)" :name="value.option" shape="square" :key="key">{{value.option}}</van-checkbox>
            </van-checkbox-group>
          </template>
        </van-field>
      </div>
      <div class="sign-form" :key="idx" v-if="item.inputType == 4">
        <div class="van-form_card">
          <div class="field__label">{{item.topicName}}</div>
          <div class="field__desc">支持“图片”扩展名:png、gif、jpeg、pcx、psd、tiff</div>
        </div>
        <van-field name="name" type="hidden" :rules="[{ validator: valiFormData, message: '请输入正确内容',index:idx }]" v-model="formData[idx]">
          <template #input>
            <div class="upload-preview">
              <van-image v-if="formData[idx]" width="4rem" height="3rem" fit="contain" :src="formData[idx]" />
              <van-uploader :before-read="uploadFile" accept="image/png,image/gif,image/jpeg,image/pcx,image/psd,image/tiff" :name="idx">
                <van-icon name="plus" />
              </van-uploader>
            </div>
          </template>
        </van-field>
      </div>
      <div class="sign-form" :key="idx" v-if="item.inputType == 5">
        <div class="van-form_card">
          <div class="field__label">{{item.topicName}}</div>
          <div class="field__desc">支持“视频”扩展名:avi、MP4、rmvb</div>
        </div>
        <van-field name="name" type="hidden" :rules="[{ validator: valiFormData, message: '请输入正确内容',index:idx }]" v-model="formData[idx]">
          <template #input>
            <div class="flex-col">
              <div class="video-upload" v-if="showUpload">
                <span>视频上传中...</span>
                <van-progress :show-pivot="false" :percentage="videoUploadPercent" />
              </div>
              <span class="link" v-if="formData[idx]" @click="href(idx)">{{videoName[idx]}}</span>
              <van-uploader :before-read="uploadVideo" accept="*" v-if="!showUpload" :name="idx">
                <van-button icon="plus" type="primary">上传视频</van-button>
              </van-uploader>
            </div>
          </template>
        </van-field>
      </div>
      <div class="sign-form" :key="idx" v-if="item.inputType == 6">
        <div class="van-form_card">
          <div class="field__label">{{item.topicName}}</div>
          <div class="field__desc">支持“文件”扩展名:doc、docx、txt、pdf、pptx、ppt、xlsx、xls</div>
        </div>
        <van-field name="name" type="hidden" :rules="[{ validator: valiFormData, message: '请选择',index:idx }]" v-model="formData[idx]">
          <template #input>
            <div class="flex-col">
              <span class="link" v-if="formData[idx]" @click="href(idx)">{{formData[idx]}}</span>
              <van-uploader :before-read="uploadFile" accept=".doc, .docx, .txt, .pdf, .pptx, .ppt, .xlsx, .xls" :name="idx">
                <van-button icon="plus" type="primary">上传文档</van-button>
              </van-uploader>
            </div>
          </template>
        </van-field>
      </div>
      <div class="sign-form" :key="idx" v-if="item.inputType == 7">
        <van-field readonly @click="clickDatePicker(idx)" name="name" :rules="[{ validator: valiFormData, message: '请选择日期',index:idx }]"
              :label="item.topicName" v-model="formData[idx]" :placeholder="'请选择'+item.topicName" />
        <van-popup v-model="showDatePicker" position="bottom">
          <van-picker
                show-toolbar
                title="选择日期"
                :columns="dateCol"
                @cancel="showDatePicker = false"
                @confirm="dateConfirm" />
        </van-popup>
        <!-- van-popup默认在兄级加蒙层van-overlay,若没有出现,可能有人在项目的全局给清除了 -->
      </div>
    </template>
    <div class="vt-foot ">
      <van-button :loading="loading" loading-text="保存中..." native-type="submit" block color="#fdb235">提交</van-button>
      <!-- native-type,原生button标签的type属性,表单内点击此按钮,自动触发表单的onsubmit事件 -->
      <!-- loading,设置按钮为加载状态,加载状态下默认会隐藏按钮文字 -->
      <!-- loading-text,设置加载状态下的文字 -->
    </div>
  </van-form>
(2)js部分
  A、上传图片
    uploadFile(file, detail) {
      let formData = new FormData();
      formData.append('file', file);
      axios.post(this.$upload, formData, {
        'Content-Type': 'multipart/form-data'
      })
      .then(res => {
        if (res.data && res.data.code === 10000) {
          this.formData[detail.name] = res.data.data;
          let temp = res.data.data;
          this.formData.splice(detail.name, 1, temp);
        } else {
          this.$dialog.alert({
            title: '提示',
            message: '上传文件失败',
            theme: 'round-button',
          })
          .then(() => {
            //on close
          });
        }
      })
    },
  B、上传视频
  来源,https://help.aliyun.com/document_detail/383952.html
    import OSS from "ali-oss";
    //开放存储服务(OpenStorageService,简称OSS),是阿里云对外提供的海量,安全,低成本,高可靠的云存储服务。
    //用户可以通过简单的API(REST方式的接口),在任何时间、任何地点、任何互联网设备上进行数据上传和下载。 
    <van-uploader accept="*" v-if="!showUpload"  :name="idx"  :before-read="uploadVideo">
      <van-button icon="plus" type="primary">上传视频</van-button>
    </van-uploader>
    uploadVideo(file, detail) {
      let type = file.name.substring(file.name.lastIndexOf(".") + 1)
        .toLowerCase()
      if (this.videoType.indexOf(type) < 0 || file.type.indexOf("video") < 0) {
        this.$dialog.alert({
          title: '提示',
          message: '仅支持 .avi, .mp4, .rmvb, .mov 格式的视频',
          theme: 'round-button',
        });
        return;
      }
      let max = 1024 * 1024 * 1024;
      if (file.size > max) {
        this.$dialog.alert({
          title: '提示',
          message: '上传视频大小不能超过 1G!',
          theme: 'round-button',
        })
        .then(() => {});
        return;
      }
      myRequest({
          tokenName: "ios",
        })
        .then(data => {
          let client = new OSS({
            region: "oss-cn-beijing",
            accessKeyId: data.data.data.accessKeyId,
            accessKeySecret: data.data.data.accessKeySecret,
            bucket: data.data.data.bucketName,
            stsToken: data.data.data.securityToken,
          });
          const suffix = file.name.substr(file.name.indexOf("."));
          let fileUrl = `test/${new Date().getTime()}${suffix}`;
          client
            .multipartUpload(fileUrl, file, {
              progress: (p) => {
                this.videoUploadPercent = Math.round(p * 100);
                this.showUpload = true;
              },
              partSize: 102400,
            })
            .then((res) => {
              this.showUpload = false;
              this.videoName[detail.name] = res.name;
              let url = res.res.requestUrls[0];
              this.formData[detail.name] = url.substring(0, url.indexOf("?"));
              let temp = this.formData[detail.name];
              this.formData.splice(detail.name, 1, temp);

            })
            .catch((err) => {
              this.showUpload = false;
              console.log(err);
              this.$dialog.alert({
                title: '提示',
                message: '上传失败',
                theme: 'round-button',
              })
            });
        })
    }

三、微信公众平台账号
 附、简称
  A、“微信账号”简称“微信号”
  B、“微信公众平台账号”简称“平台号”
1、重要网址
  (1)开发
    A、开发文档,https://developers.weixin.qq.com/miniprogram/dev/framework/
    B、开发者工具,https://developers.weixin.qq.com/miniprogram/dev/devtools/devtools.html
    C、开通微信开发者.代码管理,https://developers.weixin.qq.com/miniprogram/dev/devtools/wechatvcs.html
  (2)注册、登录、git仓库
    A、注册网址,https://mp.weixin.qq.com/
      微信十种产品,https://developers.weixin.qq.com/doc/
      四种微信公众号,https://mp.weixin.qq.com/cgi-bin/registermidpage?action=index&lang=zh_CN,
      小程序发布流程,https://mp.weixin.qq.com/wxamp/home/guide?token=1509394140
    B、登录网址,https://mp.weixin.qq.com/
      管理后台,https://mp.weixin.qq.com/wxamp/home/guide
      开发版本,https://mp.weixin.qq.com/wxamp/wacodepage/getcodepage
    C、git仓库网址,https://git.weixin.qq.com/
      四种微信公众号的任意1种账号注册成功,都会生成该仓库网址,该仓库与微信号关联,不会随公众号注销而注销
2、四种微信公众号
   附、四种微信公众号网址,https://mp.weixin.qq.com/cgi-bin/registermidpage?action=index&lang=zh_CN,
  (1)订阅号
  (2)服务号
  (3)小程序(微信小程序-后面详细介绍)
  (4)企业微信(原企业号)
3、微信公众号账号注册
   附、注册网址,https://mp.weixin.qq.com/ 
  (1)点击“立即注册”
  (2)点击“4种类型中的1种”
  (3)如果点击的是“小程序”,那么还需要在跳转后的页面点击“前往注册”
  (4)填写邮箱、密码、验证码、勾选同意、点击注册,
    A、每个邮箱仅能申请一个小程序==========非常重要===========
    B、作为登录账号,请填写未被微信公众平台注册,未被微信开放平台注册,未被个人微信号绑定的邮箱
  (5)点击登录邮箱、登录邮箱、点击邮箱里的链接
    A、注册国家/地区:中国大陆;主体类型:个人;
    B、身份证姓名、身份证号码、管理员手机号码、短信验证码、管理员身份验证(微信扫一扫)、继续,其中微信扫一扫
      把微信号与微信小程序号关联起来
      1个微信号能关联5个公众号==========非常重要===========
    C、请确认以下提交的主体信息、确定
    D、信息提交成功,前往小程序(管理后台),见7
4、小程序账号注销
   附、登录网址,https://mp.weixin.qq.com/ 
  (1)登录小程序的管理员账号
  (2)如果提示该账号已冻结,则根据提示进行解冻
  (3)如果尚无AppID(小程序ID),则需要先进行“AppID生成”
  (4)管理后台-点击(左下方)“设置”-点击(页面中间)“账号信息”里的“账号注销”按钮,(微信号的)公众平台安全助手-收到注销信息
  (5)0-6*24小时内,可以电脑登录,取消注销
  (6)6*24--14*24小时之间,可以电脑登录,取消注销或确认注销,逾期不确认账号将恢复正常,
  (7)如果不取消注销或确认注销,那么从
    7*24小时开始,每隔24小时,在-微信号的公众平台安全助手,都会收到注销确认信息,直到取消注销或确认注销或达到7次
  (8)确认注销后,微信扫一扫登录,不再出现该账号
5、小程序账号的作用
  (1)生成(小程序)管理后台
    A、管理项目版本,管理开发者
    B、1个小程序账号,其管理后台只能存储1个小程序项目的3个版本,供发布
  (2)生成存储仓库
    A、存储项目代码
    B、1个小程序账号,其git仓库能存储多个小程序项目的代码,供开发
6、小程序开发者工具的作用
  (1)把小程序体验版-存储到管理后台
  (2)把小程序代码-存储到git仓库
   附、开发小程序
    A、搜索,点击放大镜图标或者ctrl+shift+f
    B、编辑,点击文件图标
7、小程序管理后台-目录
   附、登录网址,https://mp.weixin.qq.com/ 
   附、管理后台网址,https://mp.weixin.qq.com/wxamp/home/guide
  (1)小程序账号登录,下面两种登录任选一种
    A、使用账号登录,邮箱/微信号
    B、微信扫一扫登录,扫后会出现该微信号关联的所有公众号,点击其中一个(登录)
  (2)登录成功,前往小程序(管理后台),其导航如下
  (3)首页
    A、小程序信息
      未填写//1/3,此处可生成AppID(小程序ID)
      补充小程序的基本信息,如名称、图标、描述等
    B、小程序类目
      未补充
      补充小程序的服务类目,设置主营类目
    C、小程序备案
      未备案
      需先填写小程序信息和类目
      补充小程序的备案信息,检测是否满足备案条件
    D、微信认证
      未完善
      完成微信认证后,账号可获得“被搜索”和“被分享”能力。未完成微信认证不影响后续版本发布
    E、小程序开发与管理
      自己开发
        开发工具
        添加开发者==========非常重要===========
      找服务商开发
        立即前往(按钮)
  (4)管理
    A、版本管理
      线上版本:尚未提交线上版本
      审核版本:你暂无提交审核的版本或者版本已发布上线
      开发版本:你尚未上传任何开发版本,可前往开发者工具上传代码。查看介绍,
      开发版本:版本号;版本信息;提交审核,下拉(选为体验版本,删除);点击“提交审核/选为体验版本/删除”
    B、成员管理==========非常重要===========  
  (5)开发
    A、开发管理 
      开发设置
        开发者ID
          开发者ID,操作
          AppID(小程序ID),wxd9d363f25a//2/3,此处可生成AppID(小程序ID)	
          AppSecret(小程序密钥),生成
        小程序代码上传,开发者可基于配置信息调用微信开发者工具提供的代码上传模块。查看详情
          配置信息,操作
          小程序代码上传密钥,生成
          IP白名单,暂无IP白名单,编辑
        服务器域名(以下略)
      接口设置  
    B、开发工具
  (6)设置
    A、基本设置
      基本信息
      账号信息
        AppID(小程序ID),wxd9d363f25a//3/3,此处可生成AppID(小程序ID)
        登录邮箱
    B、第三方设置
8、小程序管理后台-小程序项目-从创建到保存
  //以下操作位置:微信开发者工具
  (1)创建
    A、首次创建,点击(左上方)项目-扫描二维码-确认登录
    B、再次创建,点击(左上方)项目-新建项目/导入项目
  (2)填写AppID,
    附、以下是AppID生成与获取步骤,任选其一
      A、小程序管理后台-首页-小程序信息
      B、小程序管理后台-开发-开发管理-开发设置-开发者ID
      C、小程序管理后台-设置-基本设置-账号信息  
  (3)勾选用户协议
  (4)其它默认
  (5)确定
  (6)编辑文件
  (7)保存(ctrl+s)
9、小程序管理后台-小程序项目-生成版本
  //以下操作位置:微信开发者工具
  (1)上传项目
    A、首次,点击(右上方)上传按钮。上传成功后,需要联系管理员在小程序管理后台将本次上传“设置为体验版本”。确定
    B、再次,点击(右上方)上传按钮。上次提交已被选为体验版,本次上传将会覆盖体验版,是否继续?确定
  (2)填写版本号、项目备注
  (3)点击上传
  (4)上传成功、确定
  //以下操作位置:管理后台。管理-管理版本-开发版本
   附、管理后台网址,https://mp.weixin.qq.com/wxamp/home/guide
  (5)设置为体验版本
    A、左,版本号
    B、中,版本信息
    C、右,提交审核,选为体验版本、删除
    D、点击选为体验版本,体验版设置,点击提交,(点击下载二维码)扫描二维码体验体验版,前往体验,手动关闭弹窗
10、存储仓库-目录
  附、git仓库网址,https://git.weixin.qq.com/
  (1)项目
    A、您的项目
    B、关注的项目
    C、标星的项目
    D、受邀请项目
  (2)动态
  (3)项目组
  (4)里程碑
  (5)缺陷
  (6)合并请求
  (7)代码评审
  (8)个人设置
11、存储仓库-存储小程序代码
  附、git仓库网址,https://git.weixin.qq.com/
  //以下操作位置:代码仓库
  (1)进入git仓库
  (2)点击创建项目,填写信息,点击创建项目
  //以下操作位置:微信开发者工具/本地磁盘的文件夹
  (3)配置-Git全局设置。首次创建项目,需执行下列命令。以后创建项目,也会出现下列提示,且配置都相同,但无需执行
    git config --global user.name "Z_码农_钱成"
    git config --global user.email "oncw7ZtkhVxE@git.weixin.qq.com" 
  (4)拉取-别人正在开发的项目代码,协助别人开发。创建一个新的版本库
    git clone https://git.weixin.qq.com/13718/xiangmuzu1.git
    cd xiangmuzu1
    touch README.md
    git add README.md
    git commit -m "add README"
    git push -u origin master
  (5)推送-自己正在开发的项目代码,让别人协助开发。现有的文件夹或Git版本库
    cd existing_folder
    git init
    git remote add origin https://git.weixin.qq.com/13718/xiangmuzu1.git
    git add .
    git commit -m'自定义'
    git push -u origin master  
  //以下操作位置:微信开发者工具
  (6)推送-拉取别人后推送/再次推送自己
    A、点击(顶部中间左侧)V形符号
    B、点击(顶部中间右侧)...符号
    C、点击commit
    D、点击push
12、存储仓库-删除小程序代码
  附、git仓库网址,https://git.weixin.qq.com/
  //以下操作位置:代码仓库
  (1)进入git仓库
  (2)点击“您的项目/关注的项目/标星的项目/受邀请项目”
  (3)点击某一项目
  (4)点击(左下方)设置
  (5)点击(右中间)去更改可见性级别
  (6)下拉(至最下方),点击删除项目
  (7)输入url,点击确定

四、微信小程序-目录说明
 来源,https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html
 来源,https://developers.weixin.qq.com/miniprogram/dev/framework/structure.html
附、目录结构
  ├── app.js
  ├── app.json
  ├── app.wxss
  ├── pages
  │   │── index
  │   │   ├── index.wxml
  │   │   ├── index.js
  │   │   ├── index.json
  │   │   └── index.wxss
  │   └── logs
  │       ├── logs.wxml
  │       └── logs.js
  └── utils
1、 全局配置,一个小程序主体由三个文件组成,必须放在项目的根目录
  (1)app.js,小程序全局逻辑
    App({ //注册小程序。接受一个 Object 参数,其指定小程序的生命周期回调等
      onLaunch: function () {},//生命周期回调——监听小程序初始化
      onShow: function () {},//生命周期回调——监听小程序启动或切前台
      onHide: function () {},//生命周期回调——监听小程序切后台。
      onError: function () {},//错误监听函数。
      onPageNotFound: function () {},//页面不存在监听函数。
      onUnhandledRejection: function () {},//未处理的 Promise 拒绝事件监听函数。
      onThemeChange: function () {},//监听系统主题变化
      其他: 任意类型,开发者可以添加任意的函数或数据变量到参数中,用this可以访问
    })
    附、其它页面,获取实例
    // other.js
      var appInstance = getApp()
      console.log(appInstance.globalData) // I am global data
  (2)app.json,小程序全局配置
    {
      "pages": ["pages/index/index", "pages/logs/index"], //小程序的所有页面
      "requiredBackgroundModes": ["audio", "location"],
      "requiredPrivateInfos": [ 
        "getLocation",
        "onLocationChange",
        "startLocationUpdateBackground"
        "chooseAddress"
      ],
      "permission": {
        "scope.userLocation": {
          "desc": "你的位置信息将用于小程序位置接口的效果展示" //高速公路行驶持续后台定位
        }
      },
      "window": {
        "navigationBarTitleText": "Demo"
      },
      "tabBar": {
        "height": "50px",
        "fontSize": "10px",
        "list": [
          {
            "pagePath": "pages/index/index",
            "text": "首页"
          },
          {
            "pagePath": "pages/logs/logs",
            "text": "日志"
          }
        ]
      },
      "networkTimeout": {
        "request": 10000,
        "downloadFile": 10000
      },
      "plugins": { //在app.json中声明需要使用的插件
        "myPlugin": {
          "version": "1.0.0",
          "provider": "wxidxxxxxxxxxxxxxxxx"
        }
      },
      "debug": true,
      "resizable": true, //iPad上启用屏幕旋转支持
    }
  (3)app.wxss,小程序全局样式表
2、页面配置,一个小程序页面由四个文件组成
  (1)index.js,页面逻辑
    page({//组件逻辑用Component({})
      data: {},
      options: {},
      behaviors: String/Array,类似于mixins和traits的组件间代码复用机制,
      onLoad: function () {},
      onShow: function () {},
      onReady: function () {},
      onHide: function () {},
      onUnload: function () {},
      onRouteDone: function () {},
      onPullDownRefresh: function () {},
      onReachBottom: function () {},
      onShareAppMessage: function () {},
      onShareTimeline: function () {},
      onAddToFavorites: function () {},
      onPageScroll: function () {},
      onResize(res) { //屏幕旋转事件
        res.size.windowWidth //新的显示区域宽度
        res.size.windowHeight //新的显示区域高度
      },
      onTabItemTap: function () {},
      onSaweexitState: function () {},
      onShow: function () {},
      //其他: 任意类型,开发者可以添加任意的函数或数据变量到参数中,
      //在页面的函数中用this可以访问,这部分属性会在页面实例创建时进行一次深拷贝
      tapName: function(event) {
        console.log(event)
      }
    })
    附、getCurrentPages,获取当前页面栈,数组中第一个元素为首页,最后一个元素为当前页面
    附、Router,页面路由器对象,可以通过this.pageRouter或this.router获得当前页面或自定义组件的路由器对象
  (2)index.json,页面配置
    {
      "navigationBarBackgroundColor": "#ffffff",
      "navigationBarTextStyle": "black",
      "navigationBarTitleText": "微信接口功能演示",
      "backgroundColor": "#eeeeee",
      "backgroundTextStyle": "light"
      "pageOrientation": "auto", //手机单页面启用屏幕旋转支持
    }
  (3)index.wxss,页面样式表
  (4)index.wxml,页面结构

五、微信小程序-WXML语法参考
 附、是一套标签语言,结合基础组件、事件系统,可以构建出页面的结构
1、数据绑定,使用Mustache语法(双大括号)将变量包起来
  (1)简单绑定
    <view> {{ message }} </view>
  (2)组件属性
    <view id="item-{{id}}"> </view>
  (3)控制属性
    <view wx:if="{{condition}}"> </view>
  (4)关键字
    <checkbox checked="{{false}}"> </checkbox>
  (5)三元运算
    <view hidden="{{flag ? true : false}}"> Hidden </view>
  (6)算数运算
    <view> {{a + b}} + {{c}} + d </view>
  (7)逻辑判断
    <view wx:if="{{length > 5}}"> </view> 
  (8)字符串运算
    <view>{{"hello" + name}}</view>
  (9)数据路径运算
    <view>{{object.key}} {{array[0]}}</view>
  (10)组合数组
    <view wx:for="{{[zero, 1, 2, 3, 4]}}"> {{item}} </view>
  (11)组合对象
    <template is="objectCombine" data="{{for: a, bar: b}}"></template>
  (12)组合对象,后面覆盖前面
    <template is="objectCombine" data="{{...obj1, ...obj2, a: 5}}"></template>
  (13)组合对象
    <template is="objectCombine" data="{{foo, bar}}"></template>
  (14)花括号和引号之间如果有空格,将最终被解析成为字符串
    <view wx:for="{{[1,2,3]}} ">
      {{item}}
    </view> //等同于
    <view wx:for="{{[1,2,3] + ' '}}">
      {{item}}
    </view>
  (15)当wx:for的值为字符串时,会将字符串解析成字符串数组
    <view wx:for="array">
      {{item}}
    </view> //等同于
    <view wx:for="{{['a','r','r','a','y']}}">
      {{item}}
    </view>
  (16)data
    Page({
      data: {
        message: 'Hello MINA!',
        id: 0,
        condition: true,
        a: 1,
        b: 2,
        c: 3,
        name: 'MINA',
        object: {
          key: 'Hello '
        },
        array: ['MINA'],
        zero: 0,
        obj1: {
          a: 1,
          b: 2
        },
        obj2: {
          c: 3,
          d: 4
        },
        foo: 'my-foo',
        bar: 'my-bar',
      }
    })
2、列表渲染,
  (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'
        }]
      }
    })
  (6)wx:key的值以两种形式提供
    A、字符串,代表在for循环的array中item的某个property,该property的值需要是列表中唯一的字符串或数字,且不能动态改变
    B、保留关键字*this,代表在for循环中的item本身,这种表示需要item本身是一个唯一的字符串或者数字
      <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>
      <switch wx:for="{{numberArray}}" wx:key="*this" style="display: block;"> {{item}} </switch>
      <button bindtap="addNumberToFront"> Add to the front </button>
      Page({
        data: {
          objectArray: [
            {id: 5, unique: 'unique_5'},
            {id: 4, unique: 'unique_4'},
            {id: 3, unique: 'unique_3'},
            {id: 2, unique: 'unique_2'},
            {id: 1, unique: 'unique_1'},
            {id: 0, unique: 'unique_0'},
          ],
          numberArray: [1, 2, 3, 4]
        },
        switch: function(e) {
          const length = this.data.objectArray.length
          for (let i = 0; i < length; ++i) {
            const x = Math.floor(Math.random() * length)
            const y = Math.floor(Math.random() * length)
            const temp = this.data.objectArray[x]
            this.data.objectArray[x] = this.data.objectArray[y]
            this.data.objectArray[y] = temp
          }
          this.setData({
            objectArray: this.data.objectArray
          })
        },
        addToFront: function(e) {
          const length = this.data.objectArray.length
          this.data.objectArray = [{id: length, unique: 'unique_' + length}].concat(this.data.objectArray)
          this.setData({
            objectArray: this.data.objectArray
          })
        },
        addNumberToFront: function(e){
          this.data.numberArray = [ this.data.numberArray.length + 1 ].concat(this.data.numberArray)
          this.setData({
            numberArray: this.data.numberArray
          })
        }
      })
3、条件渲染
  (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>
    <block/> 并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性
  (4)if与hidden,wx:if有更高的切换消耗;hidden有更高的初始渲染消耗
4、模板,
  WXML提供模板(template),可以在模板中定义代码片段,然后在不同的地方调用
(1)定义模板
  使用name属性,作为模板的名字。然后在<template/>内定义代码片段,如:
    <!--
      index: int
      msg: string
      time: string
    -->
    <template name="msgItem">
      <view>
        <text> {{index}}: {{msg}} </text>
        <text> Time: {{time}} </text>
      </view>
    </template>
(2)使用模板
  使用is属性,声明需要的使用的模板,然后将模板所需要的data传入
    <template is="msgItem" data="{{...item}}"/>
    Page({
      data: {
        item: {
          index: 0,
          msg: 'this is a template',
          time: '2016-09-15'
        }
      }
    })
(3)is属性可以使用Mustache语法,来动态决定具体需要渲染哪个模板
  <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>
(4)模板的作用域
  模板拥有自己的作用域,只能使用 data 传入的数据以及模板定义文件中定义的<wxs/>模块
5、引用
  WXML提供两种文件引用方式import和include
  (1)在 item.wxml 中定义了一个叫item的template
    <template name="item">
      <text>{{text}}</text>
    </template>
  (2)在 index.wxml 中引用了 item.wxml,就可以使用item模板
    <import src="item.wxml"/>
    <template is="item" data="{{text: 'forbar'}}"/>
  (3)import的作用域
    import有作用域的概念,只会import目标文件中定义的template,而不会import目标文件import的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"/>
  (4)include
    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>

六、微信小程序-WXS语法参考
1、说明
  (1)WXS是小程序的一套脚本语言,与JavaScript是不同的语言,有自己的语法
  (2)WXS代码可以编写在wxml文件中的<wxs>标签内,或以.wxs为后缀名的文件内
  (3)变量、注释、运算符、语句、数据类型、基础类库,与js类似
2、模块
  (1)每一个.wxs文件和<wxs>标签都是一个单独的模块
  (2)每个模块都有自己独立的作用域,即在一个模块里面定义的变量与函数,默认为私有的,对其他模块不可见
  (3)一个模块要想对外暴露其内部的私有变量与函数,只能通过module.exports实现
  (4)在微信开发者工具里面,右键可以直接创建.wxs文件,在其中直接编写WXS脚本
3、.wxs文件
  (1)module模块
    A、module对象,每个wxs模块均有一个内置的module对象
    B、exports属性,通过该属性,可以对外共享本模块的私有变量与函数
    /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>
    页面输出
      some msg
      'hello world' from tools.wxs
  (2)require函数
    在.wxs模块中引用其他wxs文件模块,可以使用require函数,引用的时候,要注意如下几点
    A、只能引用.wxs文件模块,且必须使用相对路径
    B、wxs模块均为单例,wxs模块在第一次被引用时,会自动初始化为单例对象;多个页面,多个地方,多次引用,使用的都是同一个wxs模块对象
    C、如果一个wxs模块在定义之后,一直没有被引用,则该模块不会被解析与运行
      /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" />
  (3)<wxs>标签的属性
    A、module属性,是当前<wxs>标签的模块名,   
    B、src属性,可以用来引用其他的wxs文件模块,引用的时候,要注意如下几点
      只能引用.wxs文件模块,且必须使用相对路径
      wxs模块均为单例,wxs模块在第一次被引用时,会自动初始化为单例对象;多个页面,多个地方,多次引用,使用的都是同一个wxs模块对象
      /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>
      页面输出:
        'hello world' from comm.wxs
        'hello wrold' from js
      上述例子在文件/page/index/index.wxml中通过<wxs>标签引用了/page/comm.wxs 模块
  (4)注意事项
    A、<wxs>模块只能在定义模块的WXML文件中被访问到,使用<include>或<import>时,<wxs>模块不会被引入到对应的WXML文件中
    B、<template>标签中,只能使用定义该<template>的WXML文件中定义的<wxs>模块
4、引入插件
  var myPluginInterface = requirePlugin('myPlugin');
  myPluginInterface.hello();

七、微信小程序-事件系统
  来源,https://developers.weixin.qq.com/miniprogram/dev/framework/view/wxml/event.html
1、什么是事件
  (1)事件是视图层到逻辑层的通讯方式,(由用户决定执行逻辑和执行时机)
  (2)事件可以将用户的行为反馈到逻辑层进行处理
  (3)事件可以绑定在组件上,当达到触发事件,就会执行逻辑层中对应的事件处理函数
  (4)事件对象可以携带额外信息,如id,dataset,touches
2、事件的使用方式,在组件中绑定一个事件处理函数
  (1)JS绑定
    以下,在index.wxml中,触发点击事件
      <view id="tapTest" data-hi="Weixin" bindtap="tapName"> Click me! </view>
    以下,在index.js中,定义点击函数
      Page({
        tapName: function(event) {
          console.log(event)
        }
      })
  (2)WXS绑定
    以下,在index.wxml中,引入test.wxs脚本,触发点击事件
      <wxs module="wxs" src="./test.wxs"></wxs>
      <view id="tapTest" data-hi="Weixin" bindtap="{{wxs.tapName}}">绑定的WXS函数必须用{{Mustache语法,Mustache胡子}}括起来</view>
    以下,在test.wxs中,定义点击函数
      function tapName(event, ownerInstance) {
        console.log('tap Weixin', JSON.stringify(event))
      }
      module.exports = {
        tapName: tapName
      }
3、事件详解
  (1)冒泡从里向外,先捕获后冒泡
    bind,绑定事件,向上冒泡,后可以紧跟一个冒号,其含义不变,如bind:tap
    mut-bind,绑定事件,向上冒泡,与上级mut-bind“互斥”的,上级mut-bind不会被触发,上级的其它绑定依然会触发
    catch,绑定事件,阻止向上冒泡
  (2)冒泡与阻止冒泡,bindtap与catchtap,点击“inner view”会先后调用handleTap3和handleTap2
    <view id="outer" bindtap="handleTap1">
      “outer view”
      <view id="middle" catchtap="handleTap2">
        “middle view”
        <view id="inner" bindtap="handleTap3">
          “inner view”
        </view>
      </view>
    </view>
  (3)互斥事件,mut-bind,点击“inner view”会先后调用handleTap3和handleTap2,点击“middle view”会调用handleTap2和handleTap1
    <view id="outer" mut-bind:tap="handleTap1">
      “outer view”
      <view id="middle" bindtap="handleTap2">
        “middle view”
        <view id="inner" mut-bind:tap="handleTap3">
          “inner view”
        </view>
      </view>
    </view>
  (4)捕获从外向里,先捕获后冒泡
    capture-bind,捕获
    capture-catch,中断捕获、取消冒泡
  (5)事件的捕获阶段,点击“inner view”会先后调用handleTap2、handleTap4、handleTap3、handleTap1
    <view id="outer" bind:touchstart="handleTap1" capture-bind:touchstart="handleTap2">
      “outer view”
      <view id="inner" bind:touchstart="handleTap3" capture-bind:touchstart="handleTap4">
        “inner view”
      </view>
    </view>
    如果将上面代码中的第一个capture-bind改为capture-catch,将只触发handleTap2
  (6)事件对象,如无特殊说明,当组件触发事件时,逻辑层绑定该事件的处理函数会收到一个事件对象
    A、BaseEvent 基础事件对象属性列表
      type,代表事件的类型
      timeStamp,页面打开到触发事件所经过的毫秒数
      target,触发事件的源组件
        id,事件源组件的id
        dataset,事件源组件上由data-开头的自定义属性组成的集合
      currentTarget,事件绑定的当前组件
        id,当前组件的id
        dataset,当前组件上由data-开头的自定义属性组成的集合
      mark,识别具体触发事件的target节点,承载一些自定义数据,类似于dataset
        <view mark:myMark="last" bindtap="bindViewTap">
          <button mark:anotherMark="leaf" bindtap="bindButtonTap">按钮</button>
        </view>
        在上述WXML中,如果按钮被点击,将触发bindViewTap和bindButtonTap两个事件,事件携带的event.mark将包含myMark和anotherMark两项
        Page({
          bindViewTap: function(e) {
            e.mark.myMark === "last" //true
            e.mark.anotherMark === "leaf" //true
          }
        })
      //mark,会包含从触发事件的节点到根节点上所有的mark属性值
      //dataset,仅包含一个节点的data-属性值
    B、CustomEvent 自定义事件对象属性列表(继承 BaseEvent)
      detail,额外的信息
    C、TouchEvent 触摸事件对象属性列表(继承 BaseEvent)
      touches,触摸事件,当前停留在屏幕中的触摸点信息的数组,每个元素为一个Touch对象,表示当前停留在屏幕上的触摸点
        identifier,触摸点的标识符
        pageX/pageY,距离文档左上角的距离,文档的左上角为原点 ,横向为X轴,纵向为Y轴
        clientX/clientY,距离页面可显示区域(屏幕除去导航条)左上角距离,横向为X轴,纵向为Y轴
      changedTouches,触摸事件,当前变化的触摸点信息的数组
4、WXS响应事件
  (1)以下test.wxml
    <wxs module="test" src="./test.wxs"></wxs>
    <view bindtouchmove="{{test.touchmove}}" change:prop="{{test.propObserver}}" prop="{{propValue}}" class="movable"></view>
    //以上,WXS函数必须用{{}}括起来
    //以上,change:prop(标签上的监听--自悟),属性前面带“change:”前缀,是在prop属性被设置的时候触发WXS函数,类似Component定义的properties里面的observer属性
    //以上,在setData({propValue: newValue})调用之后会触发,而不只是值发生改变,所以在页面初始化的时候会调用一次WxsPropObserver的函数
    //以上,在JS里,可以自动调用WXS,因page()而执行
  (2)以下test.wxs
    module.exports = {
      touchmove: function(event, ownerInstance) {
        //event.instance,表示触发事件的组件的ComponentDescriptor实例
        //ownerInstance,表示的是触发事件的组件所在的组件的ComponentDescriptor实例,如果触发事件的组件是在页面内的,ownerInstance表示的是页面实例
      },
      propObserver: function(newValue, oldValue, ownerInstance, instance) {  
        //ownerInstance,表示的是触发事件的组件所在的组件的ComponentDescriptor实例,如果触发事件的组件是在页面内的,ownerInstance表示的是页面实例
        //instance,表示触发事件的组件的ComponentDescriptor实例
      }
    }
    //以上,instance.callMethod(funcName:string, args:object),WXS调用当前-组件-在逻辑层(App Service)定义的函数
    //以上,ownerInstance.callMethod(funcName:string, args:object),WXS调用当前-页面-在逻辑层(App Service)定义的函数
    //以上,在WXS里,可以手动调用JS

八、微信小程序-组件,基础组件
 来源,https://developers.weixin.qq.com/miniprogram/dev/component/
 附、<block><block/>,不是组件,只是一个包装元素,不会在页面中做任何的渲染,它能够设置if、for这些控制属性,设置class、id不会生效
1、视图容器
(1)cover-view,覆盖在原生组件之上的文本视图
  <view class="page-section page-section-gap">
    <map
      style="width: 100%; height: 300px;"
      latitude="{{latitude}}"
      longitude="{{longitude}}"
    >
      <cover-view class="cover-view">
        <cover-view class="container">
          <cover-view class="flex-wrp" style="flex-direction:row;">
            <cover-view class="flex-item demo-text-1"></cover-view>
            <cover-view class="flex-item demo-text-2"></cover-view>
            <cover-view class="flex-item demo-text-3"></cover-view>
          </cover-view>
        </cover-view>
      </cover-view>
    </map>
  </view>
(2)match-media,匹配检测节点
  <match-media min-width="300" max-width="600">
    <view>当页面宽度在 300 ~ 500 px 之间时展示这里</view>
  </match-media>
(3)movable-area,可移动的视图容器,在页面中可以拖拽滑动
  <movable-area>
    <movable-view x="{{x}}" y="{{y}}" direction="all">text</movable-view>
  </movable-area>
(4)scroll-view,可滚动视图区域。类似于轮播图,像素级滑动
  <scroll-view scroll-y="true" style="height: 300rpx;" bindscrolltoupper="upper" bindscrolltolower="lower" 
    bindscroll="scroll" scroll-into-view="{{toView}}" scroll-top="{{scrollTop}}">
    <view id="demo1" class="scroll-view-item demo-text-1"></view>
    <view id="demo2"  class="scroll-view-item demo-text-2"></view>
    <view id="demo3" class="scroll-view-item demo-text-3"></view>
  </scroll-view>
(5)swiper,滑块视图容器,swiper-item,仅可放置在swiper组件中,宽高自动设置为100%。类似于轮播图,块级滑动
  <swiper indicator-dots="{{indicatorDots}}"  autoplay="{{autoplay}}" interval="{{interval}}" duration="{{duration}}">
    <block wx:for="{{background}}" wx:key="*this">
      <swiper-item>
        <view class="swiper-item {{item}}"></view>
      </swiper-item>
    </block>
  </swiper>
(6)view,视图容器
  <view class="container">
    <view class="page-body">
      <view class="page-section">
        <view class="page-section-title">
          <text>flex-direction: row\n横向布局</text>
        </view>
        <view class="page-section-spacing">
          <view class="flex-wrp" style="flex-direction:row;">
            <view class="flex-item demo-text-1"></view>
            <view class="flex-item demo-text-2"></view>
            <view class="flex-item demo-text-3"></view>
          </view>
        </view>
      </view>
      <view class="page-section">
        <view class="page-section-title">
          <text>flex-direction: column\n纵向布局</text>
        </view>
        <view class="flex-wrp" style="flex-direction:column;">
          <view class="flex-item flex-item-V demo-text-1"></view>
          <view class="flex-item flex-item-V demo-text-2"></view>
          <view class="flex-item flex-item-V demo-text-3"></view>
        </view>
      </view>
    </view>
  </view>
2、基础内容
(1)icon,图标组件
  <view class="icon-box">
    <icon class="icon-box-img" type="success" size="93"></icon>
    <view class="icon-box-ctn">
      <view class="icon-box-title">成功</view>
      <view class="icon-box-desc">用于表示操作顺利完成</view>
    </view>
  </view>
(2)progress,进度条
  <view class="progress-box">
    <progress percent="20" show-info stroke-width="3"/>
  </view>
(3)rich-text,富文本
  <block wx:if="{{renderedByHtml}}">
    <rich-text nodes="{{htmlSnip}}"></rich-text>
  </block>
  const htmlSnip =
    `<div class="div_class">
      <h1>Title</h1>
      <p class="p">
        Life is <i>like</i> a box of
        <b> chocolates</b>.
      </p>
    </div>
    `
(4)text,文本
  <view class="page-section page-section-spacing">
    <view class="text-box" scroll-y="true" scroll-top="{{scrollTop}}">
      <text>{{text}}</text>
    </view>
    <button disabled="{{!canAdd}}" bindtap="add">add line</button>
    <button disabled="{{!canRemove}}" bindtap="remove">remove line</button>
  </view>
  const texts = [
    '2011年1月,微信1.0发布',
    '同年5月,微信2.0语音对讲发布',
    '10月,微信3.0新增摇一摇功能',
    '2012年3月,微信用户突破1亿',
    '4月份,微信4.0朋友圈发布',
    '同年7月,微信4.2发布公众平台',
    '2013年8月,微信5.0发布微信支付',
    '2014年9月,企业号发布',
    '同月,发布微信卡包',
    '2015年1月,微信第一条朋友圈广告',
    '2016年1月,企业微信发布',
    '2017年1月,小程序发布',
    '......'
  ]
3、表单组件
(1)button,按钮
  <view class="button-sp-area">
    <button type="primary" plain="true">按钮</button>
    <button type="primary" disabled="true" plain="true">不可点击的按钮</button>
  </view>
(2)checkbox,多选项目
  <label class="checkbox">
    <checkbox value="cb" />未选中
  </label>
  <checkbox-group bindchange="checkboxChange">
    <label class="weui-cell weui-check__label" wx:for="{{items}}" wx:key="{{item.value}}">
      <view class="weui-cell__hd">
        <checkbox value="{{item.value}}" checked="{{item.checked}}"/>
      </view>
      <view class="weui-cell__bd">{{item.name}}</view>
    </label>
  </checkbox-group>
(3)checkbox-group,多项选择器,内部由多个checkbox组成,示例见(2)
(4)editor,富文本编辑器,可以对图片、文字进行编辑
  <editor id="editor" read-only="{{false}}" /> //自写
(5)form,表单
  <form catchsubmit="formSubmit" catchreset="formReset">
    <view class="page-section page-section-gap">
      <view class="page-section-title">switch</view>
      <switch name="switch"/>
    </view>
    <view class="btn-area">
      <button style="margin: 30rpx 0" type="primary" formType="submit">Submit</button>
      <button style="margin: 30rpx 0" formType="reset">Reset</button>
    </view>
  </form>
(6)input,输入框
  <view class="weui-cell weui-cell_input">
    <input class="weui-input" auto-focus placeholder="将会获取焦点"/>
  </view>
(7)keyboard-accessory,设置input/textarea聚焦时,键盘上方cover-view/cover-image工具栏视图
  <textarea hold-keyboard="{{true}}">
    <keyboard-accessory class="container" style="height: 50px;">
      <cover-view bindtap="tap" style="flex: 1; background: green;">1</cover-view>
      <cover-view bindtap="tap" style="flex: 1; background: red;">2</cover-view>
    </keyboard-accessory>
  </textarea>
(8)label,用来改进表单组件的可用性
  <checkbox-group class="group" bindchange="checkboxChange">
    <view class="label-1" wx:for="{{checkboxItems}}">
      <label>
        <checkbox value="{{item.name}}" checked="{{item.checked}}"></checkbox>
        <text class="label-1-text">{{item.value}}</text>
      </label>
    </view>
  </checkbox-group>
(9)picker,从底部弹起的滚动选择器
  <picker mode="multiSelector" bindchange="bindMultiPickerChange" bindcolumnchange="bindMultiPickerColumnChange" value="{{multiIndex}}" range="{{multiArray}}">
    <view class="picker">
      当前选择:{{multiArray[0][multiIndex[0]]}},{{multiArray[1][multiIndex[1]]}},{{multiArray[2][multiIndex[2]]}}
    </view>
  </picker>
(10)picker-view,嵌入页面的滚动选择器
  <picker-view indicator-style="height: 50px;" style="width: 100%; height: 300px;" value="{{value}}" bindchange="bindChange">
    <picker-view-column>
      <view wx:for="{{years}}" wx:key="{{years}}" style="line-height: 50px; text-align: center;">{{item}}年</view>
    </picker-view-column>
    <picker-view-column>
      <view wx:for="{{months}}" wx:key="{{months}}" style="line-height: 50px; text-align: center;">{{item}}月</view>
    </picker-view-column>
  </picker-view>
(11)picker-view-column,滚动选择器子项
(12)radio,单选项目
  <radio-group bindchange="radioChange">
    <label class="weui-cell weui-check__label" wx:for="{{items}}" wx:key="{{item.value}}">
      <view class="weui-cell__hd">
        <radio value="{{item.value}}" checked="true"/>
      </view>
      <view class="weui-cell__bd">{{item.name}}</view>
    </label>
  </radio-group>
(13)radio-group,单项选择器,内部由多个radio组成,示例见(12)
(14)slider,滑动选择器
  <view class="body-view">
    <slider bindchange="slider1change" left-icon="cancel" right-icon="success_no_circle"/>
  </view>
(15)switch,开关选择器
  <view class="body-view">
    <switch checked="{{switch1Checked}}" bindchange="switch1Change"/>
  </view>
(16)textarea,多行输入框
  <view class="section">
    <textarea bindblur="bindTextAreaBlur" auto-height placeholder="自动变高" />
  </view>
4、导航
(1)functional-page-navigator,仅在插件中有效,用于跳转到插件功能页
  <functional-page-navigator name="loginAndGetUserInfo" bind:success="loginSuccess">
    <button>登录到插件</button>
  </functional-page-navigator>
(2)navigator,页面链接
  <view class="btn-area">
    <navigator url="/page/navigate/navigate?title=navigate" hover-class="navigator-hover">跳转到新页面</navigator>
    <navigator url="../../redirect/redirect/redirect?title=redirect" open-type="redirect" hover-class="other-navigator-hover">在当前页打开</navigator>
    <navigator url="/page/index/index" open-type="switchTab" hover-class="other-navigator-hover">切换 Tab</navigator>
    <navigator target="miniProgram" open-type="navigate" app-id="" path="" extra-data="" version="release">打开绑定的小程序</navigator>
  </view>
5、媒体组件
(1)camera,系统相机。点击相机图标,调出下面页面。出现人像-拍照人像-预览人像-存储人像
  <camera device-position="back" flash="off" binderror="error" style="width: 100%; height: 300px;"></camera>
  <button type="primary" bindtap="takePhoto">拍照</button>
  <view>预览</view>
  <image mode="widthFix" src="{{src}}"></image>
  Page({
    takePhoto() {
      const ctx = wx.createCameraContext()
      ctx.takePhoto({
        quality: 'high',
        success: (res) => {
          this.setData({
            src: res.tempImagePath
          })
        }
      })
    },
    error(e) {
      console.log(e.detail)
    }
  })
(2)image,图片。mode,图片裁剪、缩放的模式
  <view class="section section_gap" wx:for="{{array}}" wx:for-item="item">
    <view class="section__title">{{item.text}}</view>
    <view class="section__ctn">
      <image style="width: 200px; height: 200px; background-color: #eeeeee;" mode="{{item.mode}}" src="{{src}}"></image>
    </view>
  </view>
(3)live-player,实时音视频播放
  <live-player src="https://domain/pull_stream" mode="RTC" autoplay bindstatechange="statechange" binderror="error" style="width: 300px; height: 225px;" />
(4)live-pusher,实时音视频录制
  <live-pusher url="https://domain/push_stream" mode="RTC" autopush bindstatechange="statechange" style="width: 300px; height: 225px;" />
(5)video,视频
  <video 
    id="myVideo" 
    src="http://wxsnsdy.tc.qq.com/105/20210/snsdyvideodownload?filekey=30280201010421301f0201690402534804102ca905ce620b1241b726bc41dcff44e00204012882540400&bizid=1023&hy=SH&fileparam=302c020101042530230204136ffd93020457e3c4ff02024ef202031e8d7f02030f42400204045a320a0201000400" 
    binderror="videoErrorCallback" 
    danmu-list="{{danmuList}}" 
    enable-danmu 
    danmu-btn 
    show-center-play-btn='{{false}}' 
    show-play-btn="{{true}}" 
    controls
    picture-in-picture-mode="{{['push', 'pop']}}"
    bindenterpictureinpicture='bindVideoEnterPictureInPicture'
    bindleavepictureinpicture='bindVideoLeavePictureInPicture'
  ></video>
(6)voip-room,多人音视频对话
  <block wx:for="{{openIdList}}" wx:key="*this">
    <voip-room
      openid="{{item}}"
      mode="{{selfOpenId === item ? 'camera' : 'video'}}">
    </voip-room>
  </block>
6、地图,https://developers.weixin.qq.com/miniprogram/dev/component/map.html

九、微信小程序-自定义组件
  来源,开发-指南-自定义组件
  来源,https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/
1、一个小程序自定义组件由四个文件组成,类似于页面Page
(1).js,自定义组件逻辑
  // page-common-behavior.js
  // module.exports = Behavior({ //https://developers.weixin.qq.com/miniprogram/dev/reference/api/Behavior.html
  //   properties: {}, //组件的对外属性
  //   data: {}, //组件的内部数据
  // })
  var pageCommonBehavior = require('./page-common-behavior')
  Component({
    //来源,https://developers.weixin.qq.com/miniprogram/dev/reference/api/Component.html
    //properties,组件的对外属性,是属性名到属性设置的映射表
    properties: { //properties,组件的对外属性,是属性名到属性设置的映射表
      innerText: {
        type: String,
        value: 'default value',
      }
    },
    //data,组件的内部数据,和properties一同用于组件的模板渲染
    data: { 
      someData: {}
    },
    //observers,组件数据字段监听器,用于监听properties和data的变化
    observers: { //组件数据字段监听器,用于监听properties和data的变化;普通监听
      'numberA, numberB': function(numberA, numberB) {//在 numberA或者numberB被设置时,执行这个函数
        this.setData({
          sum: numberA + numberB
        })
      }
    },
    observers: { //监听子数据字段
      'some.subfield': function(subfield) {
        //使用 setData 设置 this.data.some.subfield 时触发
        //(除此以外,使用 setData 设置 this.data.some 也会触发)
        subfield === this.data.some.subfield
      },
      'arr[12]': function(arr12) {
        //使用 setData 设置 this.data.arr[12] 时触发
        //(除此以外,使用 setData 设置 this.data.arr 也会触发)
        arr12 === this.data.arr[12]
      },
    },
    observers: { //监听所有子数据字段的变化,可以使用通配符 **
      'some.field.**': function(field) {
        //使用 setData 设置 this.data.some.field 本身或其下任何子数据字段时触发
        //(除此以外,使用 setData 设置 this.data.some 也会触发)
        field === this.data.some.field
      },
    },
    observers: { //仅使用通配符 ** 可以监听全部 setData
      '**': function() {
        //每次 setData 都触发
      },
    },
    //methods,组件的方法,包括事件响应函数和任意的自定义方法
    methods: { 
      customMethod: function(){
        this.setData({ //设置data并执行视图层渲染
          s: false
        })
        this.hasBehavior() //检查组件是否具有behavior(检查时会递归检查被直接或间接引入的所有behavior)
        this.triggerEvent() //触发事件
      }
    },
    //behaviors,组件间可共享的部分,组件间代码复用机制,类似于mixins和traits
    //behaviors,组件引用它时,它的properties、data、method会被合并到组件对应的配置中,生命周期函数也会在对应时机被调用
    behaviors: [pageCommonBehavior], 
    behaviors: ['wx://form-field'], //它使得这个自定义组件有类似于表单控件的行为
    //lifetimes,组件生命周期-声明对象,里面的生命周期可以写到外面,但写在这里优先级更高
    lifetimes: {//生命周期函数,可以为函数,或一个在methods段中定义的方法名
      //created,在组件实例刚刚被创建时执行,此时不能调用setData
      created: function() {},
      //attached,在组件实例进入页面节点树时执行,声明的字段会被lifetimes声明的字段覆盖
      attached: function() { 
        this.setData({
          numberA: 1,
          numberB: 2,
        })
        this.setData({ //这样会触发上面的 observer
          'some.field': { /* ... */ }
        })
        this.setData({ //这样也会触发上面的 observer
          'some.field.xxx': { /* ... */ }
        })
        this.setData({ //这样还是会触发上面的 observer
          'some': { /* ... */ }
        })
      },
      //ready,组件布局完成后执行
      ready: function() { },
      //moved,组件实例被移动到节点树另一个位置时执行
      moved: function() { },
      //detached,组件实例被从页面节点树移除时执行
      detached: function() { },
    },
    pageLifetimes: {// 组件所在页面的生命周期函数
      show: function () { }, //组件所在的页面被展示时执行
      hide: function () { }, //组件所在的页面被隐藏时执行
      resize(res) { //屏幕旋转事件
        res.size.windowWidth //新的显示区域宽度
        res.size.windowHeight //新的显示区域高度
      }
      routeDone: function () { }, //组件所在页面路由动画完成时执行
    },
    // 组件实例的属性和方法可以在组件的方法、生命周期函数和属性observer中通过this访问
    // 属性名
    //   is,组件的文件路径
    //   id,节点id
    //   dataset,节点dataset
    //   data,组件数据,包括内部数据和属性值
    //   properties,组件数据,包括内部数据和属性值(与data一致)
    //   router,相对于当前自定义组件的Router对象
    //   pageRouter,相对于当前自定义组件所在页面的Router对象
    //   renderer,渲染当前组件的渲染后端
    // 方法名
    //   setData,设置data并执行视图层渲染	
    //   hasBehavior,检查组件是否具有behavior(检查时会递归检查被直接或间接引入的所有behavior)	
    //   triggerEvent,触发事件,参见,组件间通信与事件,
    //     https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/events.html
  })
(2).json,自定义组件配置
  {
    "component": true//这一组文件为自定义组件
  }
(3).wxss,自定义组件样式表
  .inner {
    color: red;
  }
(4).wxml,自定义组件结构
  <view class="inner">
    <view>这里是组件的内部节点</view>
    <slot></slot>
  </view>
(5)自定义组件使用
  以下,在页面的.json文件中声明引用
    {
      "usingComponents": {
        "component-tag-name": "path/to/the/custom/component"
      }
    }
  以下,在页面的.wxml文件中使用
    <view>
      <component-tag-name inner-text="Some text">这是插槽内容</component-tag-name>
    </view>
(6)自定义组件扩展
  //提供了修改自定义组件定义段的能力,下面例子就是修改了自定义组件中的data定义段里的内容
  //behavior.js
  module.exports = Behavior({
    definitionFilter(defFields) {
      defFields.data.from = 'behavior'
    },
  })
  //component.js
  Component({
    data: {
      from: 'component'
    },
    behaviors: [require('behavior.js')],
    ready() {
      console.log(this.data.from) //此处会发现输出 behavior 而不是 component
    }
  })
(7)简易双向绑定,自定义组件将自身的myValue属性双向绑定到了组件内输入框的value属性上
  custom-component定义,<input model:value="{{myValue}}" />
  custom-component使用,<custom-component model:my-value="{{pageValue}}" />  
2、抽象节点,
  有默认渲染内容,使用者决定渲染内容,与插槽相似
(1)自定义组件
  <!-- selectable-group.json -->
  {
    "componentGenerics": {//generic,通用
      "selectable": true
    }
  }
  {
    "componentGenerics": {
      "selectable": {  /* 默认抽象节点 */
        "default": "path/to/default/component"
      }
    }
  }
  <!-- selectable-group.wxml 渲染抽象节点 -->
  <view wx:for="{{labels}}">
    <label>
      <selectable disabled="{{false}}"></selectable>
      {{item}}
    </label>
  </view>
(2)父组件
  <!-- parent.json 定义抽象节点 -->
  {
    "usingComponents": {
      "custom-radio": "path/to/custom/radio",
      "custom-checkbox": "path/to/custom/checkbox"
    }
  }
  <!-- parent.wxml 选择抽象节点 -->
  <selectable-group generic:selectable="custom-radio" />
3、组件间通信与事件
(1)父级
  <!-- 当自定义组件触发“myevent”事件时,调用“onMyEvent”方法 -->
  <component-tag-name bindmyevent="onMyEvent" />
  <!-- 或者可以写成 -->
  <component-tag-name bind:myevent="onMyEvent" />
  Page({
    onMyEvent: function(e){
      e.detail //自定义组件触发事件时提供的detail对象
    }
  })
(2)自身
  <button bindtap="onTap">点击这个按钮将触发“myevent”事件</button>
  Component({
    properties: {},
    methods: {
      onTap: function(){
        var myEventDetail = {} //detail对象,提供给事件监听函数
        var myEventOption = {} //触发事件的选项
        this.triggerEvent('myevent', myEventDetail, myEventOption) //trigger,触发
      }
    }
  })

十、微信小程序-API
1、基础
(1)系统
  A、wx.getWindowInfo() //获取窗口信息
  B、wx.getSystemInfo(Object object) // 获取系统信息。是异步的调用格式,但是是同步返回
  C、wx.getDeviceInfo() //获取设备基础信息
  D、wx.getAppBaseInfo() //获取微信APP基础信息
(2)更新
  A、wx.updateWeChatApp(Object object) //更新客户端版本
  B、wx.getUpdateManager() //获取全局唯一的版本更新管理器,用于管理小程序更新
(3)小程序 
  A、wx.getApiCategory() //获取当前API类别
  B、wx.onThemeChange(function listener) //监听系统主题改变事件。该事件与App.onThemeChange的回调时机一致
  C、wx.onAppShow(function listener) //监听小程序切前台事件。该事件与App.onShow的回调参数一致
(4)调试
  A、console.log() //向调试面板中打印log日志
  B、console.warn() //向调试面板中打印warn日志
(5)性能
  A、wx.preloadWebview(Object object) //预加载下个页面的WebView
  B、wx.getPerformance() //获取当前小程序性能相关的信息
  C、wx.preloadAssets(Object object) //为视图层预加载媒体资源文件
2、路由
  (1)wx.switchTab(Object object) //跳转到tabBar页面,并关闭其他所有非tabBar页面
  (2)wx.reLaunch(Object object) //关闭所有页面,打开到应用内的某个页面
  (3)wx.redirectTo(Object object) //关闭当前页面,跳转到应用内的某个页面,但是不允许跳转到tabbar页面
  (4)wx.navigateTo(Object object) //保留当前页面,跳转到应用内的某个页面,但是不能跳到tabbar页面,使用wx.navigateBack可以返回到原页面
  (5)wx.navigateBack(Object object) //关闭当前页面,返回上一页面或多级页面。可通过getCurrentPages获取当前的页面栈,决定需要返回几层。
  (6)自定义路由
    A、wx.router //获取router对象
    B、router.addRouteBuilder(string routeType, function routeBuilder) //添加自定义路由配置
      wx.router.addRouteBuilder('slide', slideRouteBuilder) //路由类型,路由动画定义函数
    C、router.getRouteContext(Object this) //获取页面对应的自定义路由上下文对象
    D、router.removeRouteBuilder(string routeType) //移除自定义路由配置
      wx.router.removeRouteBuilder('slide')
3、跳转
  (1)wx.restartMiniProgram(Object object) //重启当前小程序
  (2)wx.openEmbeddedMiniProgram(Object object) //打开半屏小程序
  (3)wx.navigateToMiniProgram(Object object) //打开另一个小程序
  (4)wx.exitMiniProgram(Object object) //退出当前小程序。必须有点击行为才能调用成功
4、转发
  (1)wx.updateShareMenu(Object object) //更新转发属性
  (2)wx.showShareMenu(Object object) //显示当前页面的转发按钮
  (3)wx.shareVideoMessage(Object object) //转发视频到聊天
  (4)wx.shareFileMessage(Object object) //转发文件到聊天
5、界面
(1)交互
  A、wx.showToast(Object object) //显示消息提示框
  B、wx.showModal(Object object) //显示模态对话框
  C、wx.showLoading(Object object) //显示loading提示框。需主动调用wx.hideLoading才能关闭提示框
  D、wx.showActionSheet(Object object) //显示操作菜单
  E、wx.hideToast(Object object) //隐藏消息提示框
  F、wx.hideLoading(Object object) //隐藏loading提示框
(2)导航栏
  A、wx.showNavigationBarLoading(Object object) //在当前页面显示导航条加载动画
  B、wx.setNavigationBarTitle(Object object) //动态设置当前页面的标题
  C、wx.setNavigationBarColor(Object object) //设置页面导航条颜色
  D、wx.hideNavigationBarLoading(Object object) //在当前页面隐藏导航条加载动画
  E、wx.hideHomeButton(Object object) //隐藏返回首页按钮
(3)背景
  A、wx.setBackgroundTextStyle(Object object) //动态设置下拉背景字体、loading图的样式
  B、wx.setBackgroundColor(Object object) //动态设置窗口的背景色
(4)Tab Bar,位于小程序底部的导航栏菜单
  A、wx.showTabBarRedDot(Object object) //显示tabBar某一项的右上角的红点
  B、wx.showTabBar(Object object) //显示tabBar
  C、wx.setTabBarStyle(Object object) //动态设置tabBar的整体样式
  D、wx.setTabBarItem(Object object) //动态设置tabBar某一项的内容
  E、wx.setTabBarBadge(Object object) //为tabBar某一项的右上角添加文本
  F、wx.removeTabBarBadge(Object object) //移除tabBar某一项右上角的文本
  G、wx.hideTabBarRedDot(Object object) //隐藏tabBar某一项的右上角的红点
  H、wx.hideTabBar(Object object) //隐藏tabBar
(5)字体
  A、wx.loadFontFace(Object object) //动态加载网络字体,文件地址需为下载类型。需在app.js中调用
(6)下拉刷新
  A、wx.stopPullDownRefresh(Object object) //停止当前页面下拉刷新
  B、wx.startPullDownRefresh(Object object) //开始下拉刷新。调用后触发下拉刷新动画,效果与用户手动下拉刷新一致。
(7)滚动
  A、wx.pageScrollTo(Object object) //将页面滚动到目标位置,支持选择器和滚动距离两种方式定位
(8)动画
  A、wx.createAnimation(Object object) //创建一个动画实例animation
(9)置顶
  A、wx.setTopBarText(Object object) //动态设置置顶栏文字内容
(10)自定义组件
  A、wx.nextTick(Object object) //延迟一部分操作到下一个时间片再执行。(类似于setTimeout)
(11)菜单
  A、wx.getMenuButtonBoundingClientRect(Object object) //获取菜单按钮(右上角胶囊按钮)的布局位置信息。坐标信息以屏幕左上角为原点。
(12)窗口
  A、wx.setWindowSize(Object object) //设置窗口大小,该接口仅适用于PC平台
  B、wx.onWindowResize(Object object) //窗口尺寸变化事件的监听函数
  C、wx.offWindowResize(Object object) //移除窗口尺寸变化事件的监听函数
  D、wx.checkIsPictureInPictureActive(Object object) //返回当前是否存在小窗播放(小窗在video/live-player/live-pusher下可用)
(13)worklet 动画
  A、wx.worklet(Object object) //获取worklet对象
6、网络
(1)发起请求,wx.request(Object object) //发起HTTPS网络请求
  wx.request({
    url: 'example.php', 
    data: {
      x: '',
      y: ''
    },
    header: {
      'content-type': 'application/json' // 默认值
    },
    timeout: 60000, //默认值
    method: 'get', //默认值
    dataType: 'text', //默认值。返回的数据格式,即res.data,返回的数据为JSON时,返回后会对返回的数据进行一次 JSON.parse
    responseType: 'text', //默认值。响应的数据类型,即res,
    enableProfil: true, //是否开启profile,默认开启
    success (res) {
      console.log(res.profile) //网络连接过程中关键时间点的耗时信息
    },
    false (res) {
      console.log(res.errMsg)
    }
  })
(2)wx.downloadFile(Object object) //下载文件资源到本地
  const DownloadTask = wx.downloadFile({
    url: 'https://example.com/audio/123', 
    filePath: '指定文件下载后存储的路径(本地路径)',
    enableProfil: true, //是否开启profile,默认开启
    success (res) {
      //只要服务器有响应数据,就会把响应内容写入文件并进入success回调,业务需要自行判断是否下载到了想要的内容
      console.log(res.profile) //网络连接过程中关键时间点的耗时信息
      if(res.statusCode === 200) {
        wx.playVoice({
          filePath: res.tempFilePath
        })
      }
    },
  })
  //DownloadTask.onProgressUpdate(function listener),监听下载进度变化事件
(3)wx.uploadFile(Object object) //将本地资源上传到服务器
  wx.chooseImage({
    success (res) {
      const tempFilePaths = res.tempFilePaths
      const UploadTask = wx.uploadFile({
        url: 'https://example.weixin.qq.com/upload', //仅为示例,非真实的接口地址
        filePath: tempFilePaths[0],
        name: 'file',
        formData: {
          'user': 'test'
        },
        enableProfil: true, //是否开启profile,默认开启
        success (res){
          const data = res.data
          //do something
        }
      })
      //UploadTask.onProgressUpdate(function listener),监听上传进度变化事件
    }
  })
(4)WebSocket //通过WebSocket连接发送数据
  let socketOpen = false
  let socketMsgQueue = []
  wx.connectSocket({
    url: 'test.php'
  })
  wx.onSocketOpen(function(res) {
    socketOpen = true
    for (let i = 0; i < socketMsgQueue.length; i++){
      sendSocketMessage(socketMsgQueue[i])
    }
    socketMsgQueue = []
  })
  function sendSocketMessage(msg) {
    if (socketOpen) {
      wx.sendSocketMessage({
        data:msg
      })
    } else {
      socketMsgQueue.push(msg)
    }
  }
7、支付
  (1)wx.requestVirtualPayment(Object object),发起米大师虚拟支付
  (2)wx.requestPluginPayment(Object object),插件中发起支付
  (3)wx.requestPayment(Object object),发起微信支付
  (4)wx.requestMerchantTransfer(Object object),商家转账用户确认模式下,在微信客户端通过小程序拉起页面请求用户确认收款
    //调用前需在微信支付商户平台/合作伙伴平台-产品中心,申请开通商家转账
  (5)wx.requestCommonPayment(Object object),发起通用支付
8、数据缓存
  (1)wx.setStorageSync(string key, any data) //将数据存储在本地缓存中指定的key中,数据都一直可用
    wx.setStorageSync('key', 'value')
  (2)wx.setStorage(Object object) //将数据存储在本地缓存中指定的key中,数据都一直可用
    wx.setStorage({
      key:"key",
      data:"value"
    })
    wx.setStorage({ //开启加密存储
      key: "key",
      data: "value",
      encrypt: true, //若开启加密存储,setStorage和getStorage需要同时声明encrypt的值为true
      success() {
        wx.getStorage({
          key: "key",
          encrypt: true, //若开启加密存储,setStorage和getStorage需要同时声明encrypt的值为true
          success(res) {
            console.log(res.data)
          }
        })
      }
    })
  (3)wx.getStorageSync(string key) //从本地缓存中同步获取指定key的内容
  (4)wx.getStorage(Object object) //从本地缓存中异步获取指定key的内容
9、数据分析
10、XR-FRAME
11、画布
12、媒体
  (1)地图
    A、wx.createMapContext(string mapId, Object this) //创建map上下文MapContext对象。
      //建议使用“wx.createSelectorQuery”-1,获取context对象。
  (2)图片
    A、wx.saveImageToPhotosAlbum(Object object) //保存图片到系统相册
    B、wx.previewMedia(Object object) //预览图片和视频
    C、wx.previewImage(Object object) //在新页面中全屏预览图片。预览的过程中用户可以进行保存图片、发送给朋友等操作
    D、wx.getImageInfo(Object object) //获取图片信息。网络图片需先配置download域名才能生效
    E、wx.editImage(Object object) //编辑图片接口
    F、wx.cropImage(Object object) //裁剪图片接口
    G、wx.compressImage(Object object) //压缩图片接口,可选压缩质量
    H、wx.chooseMessageFile(Object object) //从客户端会话选择文件
    I、wx.chooseImage(Object object) //从本地相册选择图片或使用相机拍照,请使用wx.chooseMedia代替
  (3)视频
    A、wx.saveVideoToPhotosAlbum(Object object) //保存视频到系统相册。支持mp4视频格式
    B、wx.openVideoEditor(Object object) //打开视频编辑器
    C、wx.getVideoInfo(Object object) //获取视频详细信息
    D、wx.createVideoContext(string id, Object this) //创建video上下文VideoContext对象。
      //建议使用“wx.createSelectorQuery”-1,获取context对象。
    E、wx.compressVideo(Object object) //压缩视频接口
    F、wx.chooseVideo(Object object) //拍摄视频或从手机相册中选视频,请使用wx.chooseMedia代替
    G、wx.chooseMedia(Object object) //拍摄或从手机相册中选择图片或视频
  (4)音频
    A、wx.stopVoice(Object object) //结束播放语音,请使用wx.createInnerAudioContext代替
    B、wx.setInnerAudioOption(Object object) //设置InnerAudioContext的播放选项。设置之后对当前小程序全局生效。
    C、wx.playVoice(Object object) //开始播放语音,请使用wx.createInnerAudioContext代替
    D、wx.pauseVoice(Object object) //暂停正在播放的语音,请使用wx.createInnerAudioContext代替
    E、wx.getAvailableAudioSources(Object object) //获取当前支持的音频输入源
    F、wx.createWebAudioContext() //创建WebAudio上下文
    G、wx.createMediaAudioPlayer() //创建媒体音频播放器对象MediaAudioPlayer对象,可用于播放视频解码器VideoDecoder输出的音频
    H、wx.createInnerAudioContext(Object object) //创建内部audio上下文InnerAudioContext对象
    I、wx.createAudioContext(string id, Object this) //创建audio上下文AudioContext对象,请使用wx.createInnerAudioContext代替
  (5)背景音频
    A、wx.stopBackgroundAudio(Object object) //停止播放音乐,请使用wx.getBackgroundAudioManager代替
    B、wx.seekBackgroundAudio(Object object) //控制音乐播放进度,请使用wx.getBackgroundAudioManager代替
    C、wx.playBackgroundAudio(Object object) //使用后台播放器播放音乐,请使用wx.getBackgroundAudioManager代替
    D、wx.pauseBackgroundAudio(Object object) //暂停播放音乐,请使用wx.getBackgroundAudioManager代替
    E、wx.onBackgroundAudioStop(function listener) //监听音乐停止事件,请使用wx.getBackgroundAudioManager代替
    F、wx.onBackgroundAudioPlay(function listener) //监听音乐播放事件,请使用wx.getBackgroundAudioManager代替
    G、wx.onBackgroundAudioPause(function listener) //监听音乐暂停事件,请使用wx.getBackgroundAudioManager代替
    H、wx.getBackgroundAudioPlayerState(Object object) //获取后台音乐播放状态,请使用wx.getBackgroundAudioManager代替
    I、wx.getBackgroundAudioManager() //获取全局唯一的背景音频管理器
  (6)实时音视频
    A、wx.createLivePusherContext() //创建live-pusher上下文LivePusherContext对象
    B、wx.createLivePlayerContext(string id, Object this) //创建live-player上下文LivePlayerContext对象
      //建议使用“wx.createSelectorQuery”-1,获取context对象
  (7)录音
    A、wx.stopRecord(Object object) //停止录音,请使用wx.getRecorderManager代替
    B、wx.startRecord(Object object) //开始录音,请使用wx.getRecorderManager代替
    C、wx.getRecorderManager() //获取全局唯一的录音管理器RecorderManager
  (8)相机
    A、wx.createCameraContext() //创建camera上下文CameraContext对象
  (9)富文本
      <editor id="editor" /> //自写
      const EditorContext = wx.createSelectorQuery()
      EditorContext.select('#editor')
    A、EditorContext.blur(Object object) //编辑器失焦,同时收起键盘
    B、EditorContext.clear(Object object) //清空编辑器内容
    C、EditorContext.format(string name, string value) //修改样式
    D、EditorContext.getContents(Object object) //获取编辑器内容
    E、EditorContext.getSelectionText(Object object) //获取编辑器已选区域内的纯文本内容
    F、EditorContext.insertDivider(Object object) //插入分割线
    G、EditorContext.insertImage(Object object) //插入图片
    H、EditorContext.insertText(Object object) //覆盖当前选区,设置一段文本
    I、EditorContext.redo(Object object) //恢复
    J、EditorContext.removeFormat(Object object) //清除当前选区的样式
    K、EditorContext.scrollIntoView() //使得编辑器光标处滚动到窗口可视区域内
    L、EditorContext.setContents(Object object) //初始化编辑器内容,html和delta同时存在时仅delta生效
    M、EditorContext.undo(Object object) //撤销
    N、
  (10)音视频合成
    A、wx.createMediaContainer() //创建音视频处理容器,最终可将容器中的轨道合成一个视频
  (11)实时语音,下面接口不完整
    A、wx.updateVoIPChatMuteConfig(Object object) //更新实时语音静音设置
    B、wx.subscribeVoIPVideoMembers(Object object) //订阅视频画面成员
  (12)画面录制器
    A、wx.createMediaRecorder(Object canvas, Object options) //创建WebGL画面录制器,可逐帧录制在WebGL上渲染的画面并导出视频文件
  (13)视频解码器
    A、wx.createVideoDecoder() //创建视频解码器,可逐帧获取解码后的数据
13、位置,下面接口不完整
  (1)wx.stopLocationUpdate(Object object) //关闭监听实时位置变化,前后台都停止消息接收
  (2)wx.startLocationUpdate(Object object) //开启小程序进入前台时接收位置消息
  (3)wx.openLocation(Object object) //使用微信内置地图查看位置
  (4)wx.getLocation(Object object) //获取当前的地理位置、速度
14、文件
  (1)wx.saveFileToDisk(Object object) //保存文件系统的文件到用户磁盘,仅在PC端支持
  (2)wx.openDocument(Object object) //新开页面打开文档
  (3)wx.getFileSystemManager() //获取全局唯一的文件管理器
15、开放接口
  (1)登录
    A、wx.pluginLogin(Object args) //该接口仅在小程序插件中可调用,调用接口获得插件用户标志凭证(code)
    B、wx.login(Object object) //调用接口获取登录凭证(code)
    C、wx.checkSession(Object object) //检查登录态是否过期
  (2)账号信息
    A、wx.getAccountInfoSync() //获取当前账号信息
  (3)用户信息
    A、wx.getUserProfile(Object object) //获取用户信息
    B、wx.getUserInfo(Object object) //获取用户信息
  (4)授权
    A、wx.authorizeForMiniProgram //仅小程序插件中能调用该接口,用法同wx.authorize。目前仅支持三种scope
      wx.authorizeForMiniProgram({
        scope: 'scope.record', //scope.record、scope.writePhotosAlbum、scope.camera
        success () {
          //用户已经同意小程序使用录音功能,后续调用 wx.startRecord 接口不会弹窗询问
          wx.startRecord()
        }
      })
    B、wx.authorize //提前向用户发起授权请求
      //可以通过 wx.getSetting 先查询一下用户是否授权了 "scope.record" 这个 scope
      wx.getSetting({
        success(res) {
          if (!res.authSetting['scope.record']) {
            wx.authorize({
              scope: 'scope.record',
              success () {
                // 用户已经同意小程序使用录音功能,后续调用 wx.startRecord 接口不会弹窗询问
                wx.startRecord()
              }
            })
          }
        }
      })
  (5)设置
    A、wx.openSetting //功能描述,调起客户端小程序设置界面,返回用户设置的操作结果
      wx.openSetting({
        success (res) {
          console.log(res.authSetting)
          // res.authSetting = {
          //   "scope.userInfo": true,
          //   "scope.userLocation": true
          // }
        }
      })
    B、wx.getSetting //获取用户的当前设置
  (6)收货地址
    A、wx.chooseAddress(Object object) //获取用户收货地址
  (7)卡券
    A、wx.openCard(Object object) //查看微信卡包中的卡券
    B、wx.addCard(Object object) //
  (8)发票
    A、wx.chooseInvoiceTitle(Object object) //选择用户的发票抬头
    B、wx.chooseInvoice(Object object) //选择用户已有的发票
  (9)生物认证
    A、wx.startSoterAuthentication(Object object) //开始SOTER生物认证
    B、wx.checkIsSupportSoterAuthentication(Object object) //获取本机支持的SOTER生物认证方式
    C、wx.checkIsSoterEnrolledInDevice(Object object) //获取设备内是否录入如指纹等生物信息的接口
  (10)微信运动
    A、wx.shareToWeRun(Object object) //分享数据到微信运动
    B、wx.getWeRunData(Object object) //获取用户过去三十一天微信运动步数
  (11)订阅消息
    A、wx.requestSubscribeMessage(Object object) //调起客户端小程序订阅消息界面,返回用户订阅消息的操作结果
    B、wx.requestSubscribeDeviceMessage(Object object) //订阅设备消息接口,调用后弹出授权框,用户同意后会允许开发者给用户发送订阅模版消息
  (12)微信红包
    A、wx.showRedPackage(Object object) //拉取h5领取红包封面页
  (13)收藏
    A、wx.addVideoToFavorites(Object object) //收藏视频
    B、wx.addFileToFavorites(Object object) //收藏文件
  (14)我的小程序
    A、wx.checkIsAddedToMyMiniProgram(Object object) //检查小程序是否被添加至 「我的小程序」
  (15)车牌
    A、wx.chooseLicensePlate(Object object) //选择车牌号
  (16)视频号
    A、wx.reserveChannelsLive(Object object) //预约视频号直播
    B、wx.openChannelsUserProfile(Object object) //打开视频号主页
    C、wx.openChannelsLive(Object object) //打开视频号直播
    D、wx.openChannelsEvent(Object object) //打开视频号活动页
    E、wx.openChannelsActivity(Object object) //打开视频号视频
    F、wx.getChannelsShareKey(Object object) //获取视频号直播卡片/视频卡片的分享来源
    G、wx.getChannelsLiveNoticeInfo(Object object) //获取视频号直播预告信息
    H、wx.getChannelsLiveInfo(Object object) //获取视频号直播信息
  (17)音视频通话
    A、wx.requestDeviceVoIP(Object object) //请求用户授权与设备(组)间进行音视频通话
    B、wx.getDeviceVoIPList(Object object) //查询当前用户授权的音视频通话设备(组)信息
  (18)微信群
    A、wx.getGroupEnterInfo(Object object) //获取微信群聊场景下的小程序启动信息
  (19)隐私信息授权
    A、wx.requirePrivacyAuthorize(Object object) //模拟隐私接口调用,并触发隐私弹窗逻辑
    B、wx.openPrivacyContract(Object object) //跳转至隐私协议页面
    C、wx.onNeedPrivacyAuthorization(function listener) //监听隐私接口需要用户授权事件
    D、wx.getPrivacySetting(Object object) //查询隐私授权情况
  (20)微信客服
    A、wx.openCustomerServiceChat(Object object) //打开微信客服,页面产生点击事件(例如 button 上 bindtap 的回调中)后才可调用
  (21)微信表情
    A、wx.openStickerSetView(Object object) //打开表情专辑
    B、wx.openStickerIPView(Object object) //打开表情IP合辑
    C、wx.openSingleStickerView(Object object) //打开单个表情
16、设备
  (1)蓝牙-通用 
  (2)蓝牙-低功耗中心设备
  (3)蓝牙-低功耗外围设备
  (4)蓝牙-信标(Beacon) 
  (5)NFC读写
    A、wx.getNFCAdapter() //获取NFC实例
  (6)Wi-Fi(wifi),无线保真(Wireless Fidelity),下面接口不完整
    A、wx.stopWifi(Object object) //关闭wifi模块
    B、wx.startWifi(Object object) //初始化wifi模块
    C、wx.setWifiList(Object object) //设置wifiList中 AP 的相关信息,iOS特有接口
    D、wx.getWifiList(Object object) //请求获取wifi列表
    E、wx.getConnectedWifi(Object object) //获取已连接中的wifi信息
  (7)日历
  (8)联系人
    A、wx.chooseContact(Object object) //拉起手机通讯录,选择联系人
    B、wx.addPhoneContact(Object object) //添加手机通讯录联系人
  (9)无障碍
    A、wx.checkIsOpenAccessibility(Object object) //检测是否开启视觉无障碍功能
  (10)电量
    A、wx.getBatteryInfoSync() //同步获取设备电量
    B、wx.getBatteryInfo(Object object) //获取设备电量
  (11)剪贴板
    A、wx.setClipboardData(Object object) //设置系统剪贴板的内容
    B、wx.getClipboardData(Object object) //获取系统剪贴板的内容
  (12)NFC主机卡模拟
  (13)网络 
    A、wx.onNetworkWeakChange(function listener) //监听弱网状态变化事件
    B、wx.onNetworkStatusChange(function listener) //监听网络状态变化事件
    C、wx.offNetworkWeakChange(function listener) //移除弱网状态变化事件的监听函数
    D、wx.offNetworkStatusChange(function listener) //移除网络状态变化事件的监听函数
    E、wx.getNetworkType(Object object) //获取网络类型
    F、wx.getLocalIPAddress(Object object) //
  (14)加密 
    A、wx.getRandomValues(Object object) //获取密码学安全随机数
  (15)屏幕
    A、wx.setVisualEffectOnCapture(Object object) //wx.setVisualEffectOnCapture(Object object)
    B、wx.setScreenBrightness(Object object) //设置屏幕亮度
    C、wx.setKeepScreenOn(Object object) //设置是否保持常亮状态
    D、wx.onUserCaptureScreen(function listener) //监听用户主动截屏事件
    E、wx.onScreenRecordingStateChanged(function listener) //监听用户录屏事件
    F、wx.offUserCaptureScreen(function callback) //取消监听用户主动截屏事件
    G、wx.offScreenRecordingStateChanged(function listener) //移除用户录屏事件的监听函数
    H、wx.getScreenRecordingState(Object object) //查询用户是否在录屏
    I、wx.getScreenBrightness(Object object) //获取屏幕亮度
  (16)键盘 
    A、wx.onKeyboardHeightChange(function listener) //监听键盘高度变化事件
    B、wx.offKeyboardHeightChange(function listener) //移除键盘高度变化事件的监听函数
    C、wx.hideKeyboard(Object object) //在input、textarea等focus拉起键盘之后,手动调用此接口收起键盘
    D、wx.getSelectedTextRange(Object object) //在input、textarea等focus之后,获取输入框的光标位置
  (17)电话 
    A、wx.makePhoneCall(Object object) //拨打电话
  (18)加速计,例如摇一摇
    A、wx.stopAccelerometer(Object object) //停止监听加速度数据
    B、wx.startAccelerometer(Object object) //开始监听加速度数据
    C、wx.onAccelerometerChange(function listener) //监听加速度数据事件
    D、wx.offAccelerometerChange(function listener) //移除加速度数据事件的监听函数
  (19)罗盘
    A、wx.stopCompass(Object object) //停止监听罗盘数据
    B、wx.startCompass(Object object) //开始监听罗盘数据
    C、wx.onCompassChange(function listener) //罗盘数据变化事件的监听函数
    D、wx.offCompassChange(function listener) //移除罗盘数据变化事件的监听函数
  (20)设备方向 
    A、wx.stopDeviceMotionListening(Object object) //停止监听设备方向的变化
    B、wx.startDeviceMotionListening(Object object) //开始监听设备方向的变化
    C、wx.onDeviceMotionChange(function listener) //监听设备方向变化事件
    D、wx.offDeviceMotionChange(function listener) //移除设备方向变化事件的监听函数
  (21)陀螺仪,测量偏转、倾斜时的转动角速度 
    A、wx.stopGyroscope(Object object) //停止监听陀螺仪数据
    B、wx.startGyroscope(Object object) //开始监听陀螺仪数据 
    C、wx.onGyroscopeChange(function listener) //监听陀螺仪数据变化事件
    D、wx.offGyroscopeChange(function listener) //移除陀螺仪数据变化事件的监听函数
  (22)内存 
    A、wx.onMemoryWarning(function listener) //监听内存不足告警事件
    B、wx.offMemoryWarning(function listener) //移除内存不足告警事件的监听函数
  (23)扫码 
    A、wx.scanCode(Object object) //调起客户端扫码界面进行扫码
  (24)短信
    A、wx.sendSms(Object object) //拉起手机发送短信界面
  (25)振动
    A、wx.vibrateShort(Object object) //使手机发生较短时间的振动(15 ms)
    B、wx.vibrateLong(Object object) //使手机发生较长时间的振动(400 ms)
17、AI
  (1)AI推理 
    A、wx.getInferenceEnvInfo(Object object) //获取通用AI推理引擎版本
    B、wx.createInferenceSession(Object object) //创建AI推理Session
  (2)视觉算法
    A、wx.isVKSupport(string version) //判断支持版本
    B、wx.createVKSession(Object object) //创建vision kit会话对象
  (3)人脸检测 
    A、wx.stopFaceDetect(Object object) //停止人脸检测。本接口不再维护,请使用wx.createVKSession接口代替
    B、wx.initFaceDetect(Object object) //初始化人脸检测。本接口不再维护,请使用wx.createVKSession接口代替
    C、wx.faceDetect(Object object) //人脸检测。本接口不再维护,请使用wx.createVKSession接口代替
18、Worker
  function createNewWorker() {
    const worker = wx.createWorker('workers/index.js', { //创建一个Worker线程
      useExperimentalWorker: true
    })
    //监听worker被系统回收事件
    worker.onProcessKilled(() => {
      //重新创建一个worker
      createNewWorker()
    })
  }
  //创建实验worker
  createNewWorker()
19、WXML
  const query = wx.createSelectorQuery() 
    //返回一个SelectorQuery对象实例。在自定义组件或包含自定义组件的页面中,应使用this.createSelectorQuery()来代替
  query.select('#the-id').boundingClientRect()
  query.selectViewport().scrollOffset()
  query.exec(function(res){
    res[0].top //#the-id节点的上边界坐标
    res[1].scrollTop //显示区域的竖直滚动位置
  })
20、第三方平台
21、广告
22、Skyline

十一、uniapp跨端框架-简介 
来源,https://gitee.com/dcloud/uni-app/tags?page=60
来源,https://uniapp.dcloud.net.cn/history.html
来源,https://uniapp.dcloud.net.cn/tutorial/
1、uni-app的产生背景
  注、Dcloud一般指数字天堂(北京)网络技术有限公司,2012年04月登记成立,法定代表人王安;来源,百度百科“Dcloud”
  (1)2011年1月,微信1.0发布
  (2)2012年,DCloud开始研发小程序技术,推出了HBuilder开发工具
  (3)2015年,DCloud商用了小程序技术,命名“流应用”,并将该技术标准捐给工信部,同时推进各家流量巨头接入该标准,
    众多开发者用该标准为“流应用”平台提供应用,供用户下载
  (4)2015年9月,DCloud推进微信团队开展小程序业务
  (5)2016年初,微信团队决定上线微信小程序业务,订制了自己的标准,随后包括手机厂商在内的各大流量巨头,
    陆续上线类似微信小程序的业务
  (6)2017年1月,微信小程序发布,微信开发工具开发的微信小程序只能在微信上运行,
    来源,https://developers.weixin.qq.com/miniprogram/dev/component/text.html
  (7)2018年8月,DCloud发布uni-app1.0,为开发者抹平各平台的差异,让一套代码在各APP(应用)上运行,
    开发工具为HBuilder,js框架为vue,DCloud由标准的提供者转为标准的汇总者
2、uni-app的版本发布
  (1)2018年8月,uni-app1.0.0 版本发布,
  (2)2021年9月,uni-app2.0.0 版本发布,
  (3)2023年1月,uni-app3.0.0 版本发布,
3、uni-app与weex[wi:ks]、mpvue功能类似,通过单一代码库构建iOS、Android、Web(H5)和小程序等多个平台的应用
  (1)2016年4月,阿里巴巴发布跨平台移动开发工具weex,开发者将Weex的SDK嵌入自己的APP,解决了频繁发版和多端研发两大问题
  (2)uni-app的vue页面,用“WebKit的”webview渲染,WebKit是一个开源的浏览器引擎
  (3)uni-app的nvue页面,用“基于weex改进的”原生渲染引擎渲染,nvue是“native vue”的缩写,意为“原生vue”
  (4)原生渲染引擎,不是封装别人现成的渲染引擎,而是自己开发的渲染引擎
  (5)自悟,浏览器与APP,前者可以浏览所有网站,后者只能浏览一个网站
4、Hybrid,混合开发
  (1)Native App,一般指原生应用,是一个完整的应用,依托于操作系统,交互性强,拓展性强,需要用户下载安装使用
  (2)Web App,一般指H5应用,使用Web技术(如HTML、CSS和JavaScript)来创建应用程序的用户界面
  (3)Hybrid App,一般是指混合型App,带有原生应用外壳的Web应用,是最多的移动端开发方式
    A、底层依赖于Native提供的容器(WebView),上层使用html&css&JS做业务开发
    B、既有前者良好用户体验的优势,又有后者使用HTML5跨平台开发低成本的优势
5、uni-app与hybrid的区别
  (1)uni-app,用于移动端,后出现,负责-前后端分离-的前端
  (2)hybrid,用于移动端,先出现,负责-前后端混合-的全部

十二、uniapp跨端框架-教程 
1、uni-app的开发规范
  (1)页面文件遵循Vue单文件组件(SFC)规范,即每个页面是一个.vue文件
  (2)组件标签靠近小程序规范,
  (3)接口能力靠近小程序规范,但需将前缀wx、my等替换为uni
  (4)数据绑定及事件处理同Vue.js规范,同时补充了应用生命周期及页面的生命周期
  (5)如需兼容app-nvue平台,建议使用flex布局进行开发
  (6)uni-app分编译器和运行时(runtime),都内置在HBuilderX中,编译器在开发环境编译代码并生成输出物,
    在各终端上,各运行时(runtime)解析各输出物
2、uni-app的编译器
  (1)编译器,运行在电脑开发环境
  (2)开发者按uni-app规范编写代码,由编译器将开发者的统一代码编译生成每个平台支持的特有代码
    在web平台,将.vue文件编译为js代码
    在微信小程序平台,编译器将.vue文件拆分生成wxml、wxss、js等代码
    在app平台,将.vue文件编译为js代码
    在Android平台,将.uts文件编译为kotlin代码
    在iOS平台,将.uts文件编译为swift代码
  (3)uni-app项目根据所依赖的Vue版本不同,编译器的实现也不同
    vue2版,基于webpack实现
    vue3版,基于Vite实现,性能更快
  (4)支持条件编译
  (5)编译到任意平台时,
    static目录下满足编译条件的文件,会直接复制到最终的打包目录
    非static目录下的文件(vue、js、css等)只有被引用时,才会被打包编译
  (6).uts,意为统一类型脚本,全称为“uni type script”
3、uni-app的运行时(runtime)
  (1)runtime,运行在终端上,动态处理数据绑定、事件代理,保证Vue和平台宿主数据的一致性,这是一个比较庞大的工程
    在小程序端,uni-app的runtime,主要是一个小程序版的vue runtime,页面路由、组件、api等方面基本都是转义
    在web端,uni-app的runtime相比普通的vue项目,多了一套ui库、页面路由框架、和uni对象(即常见API封装)
    在App端,uni-app的runtime更复杂,DCloud也有一套小程序引擎,打包app时将开发者的代码和DCloud的小程序打包成了apk或ipa
  (2)uni-app的runtime包括3部分,基础框架、组件、API
4、uni-app处理各终端的逻辑层和视图层分离
  (1)在web平台,逻辑层(js)和视图层(html、css),都运行在统一的webview里
  (2)在小程序和app端,逻辑层和视图层被分离了,原因为基于webview的app因js运算和界面渲染抢资源导致卡顿而性能不佳
    逻辑层都独立成单独的js引擎,不支持浏览器专用的window、dom等API,
    视图层仍然是webview,能视图层操作window、dom
5、uni-app的工程,一个uni-app工程,就是一个“Vue项目”(非常重要),可以通过HBuilderX或cli快速创建  
6、页面
  (1)一个页面就是一个符合Vue SFC规范的.vue文件或.nvue文件
  (2)页面保存在工程根目录下的pages目录下
  (3)每次新建页面,均需在工程根目录下的pages.json中配置pages列表
  (4)删除页面时,需删除.vue文件或.nvue文件,删除pages.json中pages列表项中的配置
  (5)uni-app会将pages.json中pages配置项中的第一个页面,作为当前工程的首页(启动页)
  (6)uni-app页面除支持Vue组件生命周期外还支持页面生命周期函数onInit、onLoad、onShow、onReady、onHide、onUnload、onResize、.........
  (7)uni-app组件支持的生命周期,与vue标准组件的生命周期相同beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy、destroyed
  (8)页面调用接口
    getApp,函数用于获取当前应用实例,一般用于获取全局数据
      const app = getApp()
      console.log(app.globalData)
    getCurrentPages,函数用于获取当前页面栈的实例,以数组形式按栈的顺序给出,第一个元素为首页,最后一个元素为当前页面
      const page = getCurrentPages()
      page.$getAppWebview(),获取当前页面的webview对象实例
      page.route,获取当前页面的路由	
    $getAppWebview(),在getCurrentPages()获得的页面里内置了一个方法$getAppWebview(),获取当前页面的webview对象实例
      var pages = getCurrentPages();
      var page = pages[pages.length - 1];
      var currentWebview = page.$getAppWebview();
      console.log(currentWebview.id);//获得当前webview的id
      console.log(currentWebview.isVisible());//查询当前webview是否可见
  (9)页面通讯
    uni.$emit(eventName,OBJECT),触发全局的自定义事件,附加参数都会传给监听器回调
    uni.$on(eventName,callback),监听全局的自定义事件,事件可以由 uni.$emit 触发,回调函数会接收所有传入事件触发函数的额外参数
    uni.$once(eventName,callback),监听全局的自定义事件,事件可以由 uni.$emit 触发,但是只触发一次,在第一次触发之后移除监听器
    uni.$off([eventName,callback]),移除全局自定义事件监听器
  (10)uni-app框架统一管理页面路由,开发者需要在pages.json里配置每个路由页面的路径及页面样式,使用navigator组件跳转、调用API跳转
  (11)框架以栈的形式管理当前所有页面
  (12)支持在template模板中嵌套<template/>和<block/>
  (13)nvue开发与vue开发的常见区别
7、组件 
  (1)uni-app组件
    视图容器 
    基础内容 
    表单组件 
    路由与页面跳转 
    媒体组件 
  (2)Vue组件
  (3)NVUE组件
  (4)小程序组件
  (5)扩展组件(uni-ui)
8、引用组件
  (1)传统vue项目开发,引用组件需要导入-注册-使用三个步骤,如下:
    <template>
      <view>
        <!-- 3.使用组件 -->
        <uni-rate text="1"></uni-rate>
      </view>
    </template>
    <script>
      //1. 导入组件
      import uniRate from '@/components/uni-rate/uni-rate.vue';
      export default {
        components: { uniRate } //2. 注册组件
      }
    </script>
  (2)Vue 3.x增加了script setup特性,将三步优化为两步,无需注册步骤,更为简洁:
    <template>
      <view>
        <!-- 2.使用组件 -->
        <uni-rate text="1"></uni-rate>
      </view>
    </template>
    <script setup>
      //1. 导入组件
      import uniRate from '@/components/uni-rate/uni-rate.vue';
    </script>
  (3)uni-app的easycom机制,将组件引用进一步优化,开发者只管使用,无需考虑导入和注册,更为高效:
    在 uni-app 项目中,页面引用组件和组件引用组件的方式都是一样的(可以理解为:页面是一种特殊的组件),均支持通过 easycom 方式直接引用。
    <template>
      <view>
        <!-- 1.使用组件 -->
        <uni-rate text="1"></uni-rate>
      </view>
    </template>
    <script>
    </script>
9、引用JS
  (1)绝对路径,@指向项目根目录,在cli项目中@指向src目录
    import add from '@/common/add.js';
  (2)相对路径
    import add from '../../common/add.js';
  (3)js中引入npm包
    import package from 'packageName'
    const package = require('packageName') 
10、引用CSS
  <style>
    @import "../../common/uni.css";
    .uni-card {
        box-shadow: none;
    }
  </style>  
11、引用静态资源,https://uniapp.dcloud.net.cn/tutorial/page-static-assets.html
  (1)#模板内引入静态资源
    template内引入静态资源,如image、video等标签的src属性时,可以使用相对路径或者绝对路径
    <!-- 绝对路径,/static指根目录下的static目录,在cli项目中/static指src目录下的static目录 -->
    <image class="logo" src="/static/logo.png"></image>
    <image class="logo" src="@/static/logo.png"></image>
    <!-- 相对路径 -->
    <image class="logo" src="../../static/logo.png"></image>
  (2)css 引入静态资源
    css文件或style标签内引入css文件时(scss、less 文件同理),可以使用相对路径或绝对路径
    /* 绝对路径 */
    @import url('/common/uni.css');
    @import url('@/common/uni.css');
    /* 相对路径 */
    @import url('../../common/uni.css');
12、JS语法
  (1)uni-app的js API由标准ES的js API和uni扩展API这两部分组成
    标准ECMAScript的js仅是最基础的js
    浏览器扩展了window、document、navigator等对象
    小程序扩展了各种wx.xx、my.xx、swan.xx的API
    node扩展了fs等模块
    uni-app扩展了uni对象,并且API命名与小程序保持兼容
  (2)标准js和浏览器js的区别
    h5端,JS运行于浏览器中
    非h5端(包含小程序和App),Android平台JS运行在v8引擎中,iOS平台JS运行在iOS自带的jscore引擎中,都没有运行在浏览器或webview里
    非H5端,虽然不支持window、document、navigator等浏览器的js API,但也支持标准ECMAScript
  (3)支持绝大部分ES6 API的同时,也支持了ES7的 await/async
13、CSS语法
  (1)uni-app的css与web的css基本一致
  (2)nvue页面里的样式比web页面里的样式限制更多
  (3)支持的通用css单位包括px、rpx
14、vue语法,仅以“组合式API”为例
  (1)目前uni-app基于Vue2.6,组合式API由@vue/composition-api支持,setup由unplugin-vue2-script-setup支持
  (2)在main.js或main.ts文件内增加安装@vue/composition-api插件
  (3)在每个nvue页面安装@vue/composition-api插件
15、vue3组合式API(Composition API),按照逻辑关注点,对部分代码进行分组
    注,来自于文章10,https://www.cnblogs.com/gushixianqiancheng/p/13392540.html
  (1)vue2中,通过配置项(data、computed、methods、watch)将相关逻辑拆散,不便于组件阅读和维护
  (2)vue3中,通过组合式API(setup、ref、reactive、watchEffect、watch、computed、toRefs、生命周期的hooks),将相关逻辑写在一起,便于组件阅读和维护
  (3)setup函数接受两个参数:(props、context)
    props参数是响应式数据,解构props的操作必须通过toRefs完成,toRefs将对象的多个属性变成响应式数据,如var {title} = toRefs(props)
    context参数不是响应式数据,可以直接解构,包含attrs、slots、emit,其中attrs是组件的props配置中没有声明的属性
  (4)setup执行时,组件实例尚未被创建,this修改成undefined
  (5)setup之ref和reactive的区别
    ref定义基本类型数据,使用Object.defineProperty实现数据代理,使用refData.value.name获取数据(template模板中不需要.value)
    reactive定义引用类型数据,使用Proxy实现数据代理,使用reactData.username获取数据
  (6)setup通过ref、reactive、computed生成组件所需值;通过方法,改变组件值、全局值
    以下,组合式API之computed,来源,https://blog.csdn.net/ct5211314/article/details/125874348
    <template>
      <div>
        <div>姓:<input type="text" v-model="per.surname"></div>
        <div>名:<input type="text" v-model="per.name"></div>
        <div>姓名:<input type="text" v-model="per.fullName"></div>
      </div>
    </template>
    <script>
    import { computed, reactive } from 'vue'
    export default {
      setup(){
        let per = reactive({
          surname:'勇敢',
          name:'小陈'
        })
        per.fullName = computed(()=>{
          return per.surname+'~'+per.name
        })
        return{
          per
        }
      }
    }
    </script>
    以下,组合式API之watchEffect,来源,https://blog.csdn.net/ZYS10000/article/details/124535467
    watchEffect,是一个帧听器,是一个副作用函数,它会监听引用数据类型的所有属性,不需要具体到某个属性,一旦运行就会立即监听,组件卸载的时候会停止监听。
    import { reactive, watchEffect } from 'vue';
    export default {
      setup(){
        let obj = reactive({
          name:'zs'
        });
        watchEffect(() => {
          console.log('name:',obj.name)
        })
        return {
          obj
        }
      }
    }
16、ts语法
  <script lang="ts">
    //这里编写ts代码
    let s:string = "123"
    console.log(s)
  </script>
17、uts语法
  (1)uts,全称uni type script,是一门跨平台的、高性能的、强类型的现代编程语言,
  (2)uts采用了与ts基本一致的语法规范,支持绝大部分ES6 API
  (3)uts可以被编译为不同平台的编程语言
    web平台,编译为JavaScript
    Android平台,编译为Kotlin
    iOS平台,编译Swift

十三、uniapp跨端框架-全局文件 
1、pages.json 页面路由,对uni-app进行全局配置,决定页面文件的路径、窗口样式、原生的导航栏、底部的原生tabbar 等
  {
    "pages": [{
      "path": "pages/component/index",
      "style": {
        "navigationBarTitleText": "组件"
      }
    }, {
      "path": "pages/API/index",
      "style": {
        "navigationBarTitleText": "接口"
      }
    }, {
      "path": "pages/component/view/index",
      "style": {
        "navigationBarTitleText": "view"
      }
    }],
    "condition": { //模式配置,仅开发期间生效
      "current": 0, //当前激活的模式(list 的索引项)
      "list": [{
        "name": "test", //模式名称
        "path": "pages/component/view/index" //启动页面,必选
      }]
    },
    "globalStyle": {
      "navigationBarTextStyle": "black",
      "navigationBarTitleText": "演示",
      "navigationBarBackgroundColor": "#F8F8F8",
      "backgroundColor": "#F8F8F8",
      "usingComponents":{
        "collapse-tree-item":"/components/collapse-tree-item"
      },
      "renderingMode": "seperated", //仅微信小程序,webrtc 无法正常时尝试强制关闭同层渲染
      "pageOrientation": "portrait", //横屏配置,全局屏幕旋转设置(仅 APP/微信/QQ小程序),支持 auto / portrait / landscape
      "rpxCalcMaxDeviceWidth": 960,
      "rpxCalcBaseDeviceWidth": 375,
      "rpxCalcIncludeWidth": 750
    },
    "tabBar": {
      "color": "#7A7E83",
      "selectedColor": "#3cc51f",
      "borderStyle": "black",
      "backgroundColor": "#ffffff",
      "height": "50px",
      "fontSize": "10px",
      "iconWidth": "24px",
      "spacing": "3px",
        "iconfontSrc":"static/iconfont.ttf", //app tabbar 字体.ttf文件路径 app 3.4.4+
      "list": [{
        "pagePath": "pages/component/index",
        "iconPath": "static/image/icon_component.png",
        "selectedIconPath": "static/image/icon_component_HL.png",
        "text": "组件",
            "iconfont": { //优先级高于 iconPath,该属性依赖 tabbar 根节点的 iconfontSrc
              "text": "\ue102",
              "selectedText": "\ue103",
              "fontSize": "17px",
              "color": "#000000",
              "selectedColor": "#0000ff"
            }
      }, {
        "pagePath": "pages/API/index",
        "iconPath": "static/image/icon_API.png",
        "selectedIconPath": "static/image/icon_API_HL.png",
        "text": "接口"
      }],
      "midButton": {
        "width": "80px",
        "height": "50px",
        "text": "文字",
        "iconPath": "static/image/midButton_iconPath.png",
        "iconWidth": "24px",
        "backgroundImage": "static/image/midButton_backgroundImage.png"
      }
    },
    "easycom": {
      "autoscan": true, //是否自动扫描组件
      "custom": {//自定义扫描规则
        "^uni-(.*)": "@/components/uni-$1.vue"
      }
    },
    "topWindow": {
      "path": "responsive/top-window.vue",
      "style": {
        "height": "44px"
      }
    },
    "leftWindow": {
      "path": "responsive/left-window.vue",
      "style": {
        "width": "300px"
      }
    },
    "rightWindow": {
      "path": "responsive/right-window.vue",
      "style": {
        "width": "300px"
      },
      "matchMedia": {
        "minWidth": 768
      }
    }
  }
2、manifest.json配置,文件是应用的配置文件,用于指定应用的名称、图标、权限等
  {
    "quickapp-webview": {//快应用通用配置
      "icon": "/static/logo.png",
      "package": "com.example.demo",
      "versionName": "1.0.0",
      "versionCode": 100
    },
    "quickapp-webview-union": {//快应用联盟,目前仅支持 vivo、oppo
      "minPlatformVersion": 1063 //最小平台支持
    },
    "quickapp-webview-huawei": {//快应用华为
      "minPlatformVersion": 1070 //最小平台支持
    }
  }
3、package.json扩展配置
  {
    /**
     * package.json其它原有配置 
     * 拷贝代码后请去掉注释!
     */
    "uni-app": {//扩展配置
      "scripts": {
        "custom-platform": { //自定义编译平台配置,可通过cli方式调用
          "title":"自定义扩展名称", //在HBuilderX中会显示在 运行/发行 菜单中
          "browser":"",  //运行到的目标浏览器,仅当UNI_PLATFORM为h5时有效
          "env": {//环境变量
            "UNI_PLATFORM": "",  //基准平台
            "MY_TEST": "", //... 其他自定义环境变量
          },
          "define": { //自定义条件编译
            "CUSTOM-CONST": true //自定义条件编译常量,建议为大写
          }
        }
      }    
    }
  }
4、vue.config.js,是一个可选的配置文件,如果项目的根目录中存在这个文件,那么它会被自动加载,一般用于配置webpack等编译选项
  const path = require('path')
  const webpack = require('webpack')
  const CopyWebpackPlugin = require('copy-webpack-plugin') //最新版本copy-webpack-plugin插件暂不兼容,推荐v5.0.0
  module.exports = {
    configureWebpack: {
      plugins: [
        new CopyWebpackPlugin([
          {
            from: path.join(__dirname, 'src/images'),
            to: path.join(__dirname, 'dist', process.env.NODE_ENV === 'production' ? 'build' : 'dev', process.env.UNI_PLATFORM, 'images')
          }
        ])
      ]
    },
    chainWebpack: config => {
      config
        .plugin('define')
        .tap(args => {
          args[0]['process.env'].VUE_APP_TEST = '"test"'
          return args
        })
    }
  }
5、vite.config.js,是一个可选的配置文件,如果项目的根目录中存在这个文件,那么它会被自动加载,一般用于配置vite的编译选项,
  必须引用 '@dcloudio/vite-plugin-uni' 并且添加到 plugins 中
  示例一、自定义静态资源目录
  import path from 'path';
  import fs from 'fs-extra';
  import { defineConfig } from 'vite';
  import uni from '@dcloudio/vite-plugin-uni';
  function copyFile() {
    return {
      enforce: 'post',
      async writeBundle() {
        await fs.copy(
          path.resolve(__dirname, 'images'),
          path.join(
            __dirname,
            'unpackage/dist',
            process.env.NODE_ENV === 'production' ? 'build' : 'dev',
            process.env.UNI_PLATFORM,
            'images'
          )
        );
      },
    };
  }
  export default defineConfig({
    plugins: [uni(), copyFile()],
  });
  示例二、注入全局依赖
  //示例从插件市场下载 mp-storage
  import path from 'path';
  import { defineConfig } from 'vite';
  import uni from '@dcloudio/vite-plugin-uni';
  import inject from '@rollup/plugin-inject';
  const mpStoragePath = path.resolve(__dirname, './js_sdk/mp-storage/mp-storage');
  export default defineConfig({
    plugins: [
      uni(),
      inject({
        localStorage: [mpStoragePath, 'localStorage'],
        'window.localStorage': [mpStoragePath, 'localStorage'],
      }),
    ],
    define: {
      'process.env.VUE_APP_TEST': JSON.stringify('test'),
    },
  });
  示例三、配置环境变量
  import { defineConfig } from 'vite';
  import uni from '@dcloudio/vite-plugin-uni';
  export default defineConfig({
    plugins: [uni()],
    define: {
      'process.env.VUE_APP_TEST': JSON.stringify('test'),
    },
  });
6、uni.scss文件的用途是为了方便整体控制应用的风格。比如按钮颜色、边框风格,uni.scss文件里预置了一批scss变量预置 
  <style lang="scss">
  </style>
  以下是uni.scss的相关变量
  $uni-color-primary: #007aff;
  $uni-color-success: #4cd964;
  $uni-color-warning: #f0ad4e;
  $uni-color-error: #dd524d;
7、App.vue是uni-app的主组件,所有页面都是在App.vue下进行切换的,是页面的入口文件
  (1)App.vue本身不是页面,这里不能编写视图元素,也就是没有<template>
  (2)这个文件的作用包括:调用应用生命周期函数、配置全局样式、配置全局的存储globalData
  (3)应用生命周期仅可在App.vue中监听,在页面监听无效
  (4)js中操作globalData的方式如下:getApp().globalData.text = 'test'
  (5)示例代码
    <script>
      //只能在App.vue里监听应用的生命周期
      export default {
        globalData: {  
          text: 'text'  
        }
        onLaunch: function() {
          console.log('App Launch')
        },
        onShow: function() {
          console.log('App Show')
        },
        onHide: function() {
          console.log('App Hide')
        }
      }
    </script>
8、main.js是uni-app的入口文件,主要作用是初始化vue实例、定义全局组件、使用需要的插件如vuex
  (1)vue2代码示例
    import Vue from 'vue'
    import App from './App'
    import pageHead from './components/page-head.vue' //全局引用 page-head 组件
    Vue.config.productionTip = false
    Vue.component('page-head', pageHead) //全局注册 page-head 组件,每个页面将可以直接使用该组件
    App.mpType = 'app'
    const app = new Vue({
      ...App
    })
    app.$mount() //挂载 Vue 实例
  (2)vue3代码示例
    import App from './App'
    import { createSSRApp } from 'vue'
    export function createApp() {
      const app = createSSRApp(App)
      return {
        app
      }
    }

十四、postcss.config.js
来源,https://www.fke6.com/html/110797.html
来源,https://blog.csdn.net/Jensen_Yao/article/details/103203490
注、通过gulp、webpack、grunt等构建工具来使用,用于配置PostCSS的插件和选项,处理CSS
1、示例一,插件排序与插件参数
  module.exports = {
    plugins: [//插件排序
      require('postcss-import'),
      require('postcss-url')({//插件参数
        url: 'inline'
      }),
      require('precss'),
      require('autoprefixer')({//插件参数
        browsers: ['last 2 versions']
      })
    ]
  }
2、示例二,px转rem,rootValue*10=设计稿的宽
  module.exports = () => ({
    plugins: [
      require('autoprefixer')(),
      //require('postcss-px2rem')({ remUnit: 75 })
      require('postcss-pxtorem')({
        rootValue: 37.5, //对应设计图宽度375px
        propList: ['*'], //将哪些属性的px值转换,['*']将所有属性的px值转换,['*', '!border*']含border的属性的px值不转换,其余的都转换
      })
    ]
  });
3、示例三,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
      }
    }
  }
  

  

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