Skip to content
索引

弹窗提示

js
 uni.showToast({
          title: "点击了遮罩"
        })
 uni.showToast({
          title: "点击了遮罩"
        })

获取dom

js
   const dateEditor = uni.createSelectorQuery().in(this).select(".uni-date-editor")
      dateEditor
        .boundingClientRect(rect => {
          if (this.windowWidth - rect.left < this.datePopupWidth) {
            this.popover.right = 0
          }
        })
        .exec()
   const dateEditor = uni.createSelectorQuery().in(this).select(".uni-date-editor")
      dateEditor
        .boundingClientRect(rect => {
          if (this.windowWidth - rect.left < this.datePopupWidth) {
            this.popover.right = 0
          }
        })
        .exec()

获取平台信息

js
platform() {
  const systemInfo = uni.getSystemInfoSync()
  this.windowWidth = systemInfo.windowWidth
},
platform() {
  const systemInfo = uni.getSystemInfoSync()
  this.windowWidth = systemInfo.windowWidth
},

切换页面更改顶部背景色

js
uni.setNavigationBarColor({
          frontColor: "#ffffff",
          backgroundColor: "#6739b6"
        })
uni.setNavigationBarColor({
          frontColor: "#ffffff",
          backgroundColor: "#6739b6"
        })

自定义顶部-实现背景色渐变

1.pages.json中设置 "navigationStyle": "custom"

json
{
  "pages": [
    ...
    // 需要设置渐变背景色的页面
    {
      "path": "pages/todo/todo",
      "style": {
        ...
        // 自定义背景样式
        "navigationStyle": "custom"
      }
    }
  ],
{
  "pages": [
    ...
    // 需要设置渐变背景色的页面
    {
      "path": "pages/todo/todo",
      "style": {
        ...
        // 自定义背景样式
        "navigationStyle": "custom"
      }
    }
  ],

2.然后页面中使用css

css
background-image: linear-gradient(#ee9d39, #fbd978);
background-image: linear-gradient(#ee9d39, #fbd978);

预览图片

js
  // 回调返回,图片保存路径
            uni.previewImage({
              urls: [res.tempFilePath],
              longPressActions: {
                itemList: ["发送给朋友", "保存图片", "收藏"],
                success: function(data) {
                  console.log(
                    "选中了第" + (data.tapIndex + 1) + "个按钮,第" + (data.index + 1) + "张图片"
                  )
                },
                fail: function(err) {
                  console.log("eee", err.errMsg)
                }
              }
            })
  // 回调返回,图片保存路径
            uni.previewImage({
              urls: [res.tempFilePath],
              longPressActions: {
                itemList: ["发送给朋友", "保存图片", "收藏"],
                success: function(data) {
                  console.log(
                    "选中了第" + (data.tapIndex + 1) + "个按钮,第" + (data.index + 1) + "张图片"
                  )
                },
                fail: function(err) {
                  console.log("eee", err.errMsg)
                }
              }
            })

单行文本和多行文本超出隐藏

css
.name{
  width:400px;
  white-space:nowarp;/*强制在一行显示*/
  over-flow:hidden;/*溢出隐藏*/
  text-overflow:ellipsip;/*溢出显示省略号*/
}

.name{
  width:400px;
  white-space:nowarp;/*强制在一行显示*/
  over-flow:hidden;/*溢出隐藏*/
  text-overflow:ellipsip;/*溢出显示省略号*/
}

css
  .name {
    height: 80px;
    display: -webkit-box; /*弹性伸缩盒子模型显示*/
    -webkit-box-orient: vertical; /*排列方式*/ 
    -webkit-line-clamp: 2;/*显示文本行数*/
    overflow: hidden;/*溢出隐藏*/
  }
  .name {
    height: 80px;
    display: -webkit-box; /*弹性伸缩盒子模型显示*/
    -webkit-box-orient: vertical; /*排列方式*/ 
    -webkit-line-clamp: 2;/*显示文本行数*/
    overflow: hidden;/*溢出隐藏*/
  }

导出excel

js
 tableToExcel() {
      const jsonData = [
        {
          name: '测试数据',
          phone: '123456',
          email: '123@456.com'
        }
      ]
      // 列标题
      let worksheet = 'sheet1'
      let str = '<tr><td>姓名</td><td>电话</td><td>邮箱</td></tr>'
      // 循环遍历,每行加入tr标签,每个单元格加th标签
      for (let i = 0; i < jsonData.length; i++) {
        str += '<tr>'
        for (let item in jsonData[i]) {
          // 增加\t为了不让表格显示科学计数法或者其他格式
          str += `<th>${jsonData[i][item] + '\t'}</th>`
        }
        str += '</tr>'
      }
      // 下载的表格模板数据
      let template = `<html xmlns:o="urn:schemas-microsoft-com:office:office"
                xmlns:x="urn:schemas-microsoft-com:office:excel"
                xmlns="http://www.w3.org/TR/REC-html40">
                <head><!--[if gte mso 9]><xml encoding="UTF-8"><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet>
                <x:Name>${worksheet}</x:Name>
                <x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet>
                </x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]-->
                </head><body><table>${str}</table></body></html>`
      this.exportFile(template)
    },
    exportFile(fileData, documentName = '项目Excel文件') {
      plus.io.requestFileSystem(plus.io.PUBLIC_DOCUMENTS, fs => {
        let rootObj = fs.root
        let fullPath = rootObj.fullPath
        console.log('开始导出数据********')
        // 创建文件夹
        rootObj.getDirectory(documentName, { create: true }, dirEntry => {
          // 获取当前的年月继续创建文件夹
          let date = new Date()
          let year = date.getFullYear()
          let month = date.getMonth() + 1
          dirEntry.getDirectory(`${year}${month}月`, { create: true }, dirEntry2 => {
            let fileName = 'excel'
            dirEntry2.getFile(`${fileName}.xlsx`, { create: true }, fileEntry => {
              fileEntry.createWriter(writer => {
                //  /storage/emulated/0指的就是系统路径
                let pathStr = fullPath.replace('/storage/emulated/0', '')
                writer.onwrite = e => {
                  // 成功导出数据;
                  uni.hideLoading()
                    this.excelPath = `${pathStr}/${documentName}/${year}${month}月`
                    console.log(this.excelPath)
                    uni.showToast({
                      title: `成功导出,文件位置:${pathStr}/${documentName}/${year}${month}月`,
                      icon: 'success'
                    })
                }
                writer.write(fileData)  // 写入内容
              })
            })
          })
        })
      })
    },
    openExcel() {
      const path = '/storage/emulated/0' + this.excelPath + '/excel.xlsx'
      uni.openDocument({
        filePath: path,
        showMenu: true,
        success: function(res) {
          console.log('打开文档成功')
        },
        fail: function(res) {
          console.log(res)
        }
      })
    }
 tableToExcel() {
      const jsonData = [
        {
          name: '测试数据',
          phone: '123456',
          email: '123@456.com'
        }
      ]
      // 列标题
      let worksheet = 'sheet1'
      let str = '<tr><td>姓名</td><td>电话</td><td>邮箱</td></tr>'
      // 循环遍历,每行加入tr标签,每个单元格加th标签
      for (let i = 0; i < jsonData.length; i++) {
        str += '<tr>'
        for (let item in jsonData[i]) {
          // 增加\t为了不让表格显示科学计数法或者其他格式
          str += `<th>${jsonData[i][item] + '\t'}</th>`
        }
        str += '</tr>'
      }
      // 下载的表格模板数据
      let template = `<html xmlns:o="urn:schemas-microsoft-com:office:office"
                xmlns:x="urn:schemas-microsoft-com:office:excel"
                xmlns="http://www.w3.org/TR/REC-html40">
                <head><!--[if gte mso 9]><xml encoding="UTF-8"><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet>
                <x:Name>${worksheet}</x:Name>
                <x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet>
                </x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]-->
                </head><body><table>${str}</table></body></html>`
      this.exportFile(template)
    },
    exportFile(fileData, documentName = '项目Excel文件') {
      plus.io.requestFileSystem(plus.io.PUBLIC_DOCUMENTS, fs => {
        let rootObj = fs.root
        let fullPath = rootObj.fullPath
        console.log('开始导出数据********')
        // 创建文件夹
        rootObj.getDirectory(documentName, { create: true }, dirEntry => {
          // 获取当前的年月继续创建文件夹
          let date = new Date()
          let year = date.getFullYear()
          let month = date.getMonth() + 1
          dirEntry.getDirectory(`${year}${month}月`, { create: true }, dirEntry2 => {
            let fileName = 'excel'
            dirEntry2.getFile(`${fileName}.xlsx`, { create: true }, fileEntry => {
              fileEntry.createWriter(writer => {
                //  /storage/emulated/0指的就是系统路径
                let pathStr = fullPath.replace('/storage/emulated/0', '')
                writer.onwrite = e => {
                  // 成功导出数据;
                  uni.hideLoading()
                    this.excelPath = `${pathStr}/${documentName}/${year}${month}月`
                    console.log(this.excelPath)
                    uni.showToast({
                      title: `成功导出,文件位置:${pathStr}/${documentName}/${year}${month}月`,
                      icon: 'success'
                    })
                }
                writer.write(fileData)  // 写入内容
              })
            })
          })
        })
      })
    },
    openExcel() {
      const path = '/storage/emulated/0' + this.excelPath + '/excel.xlsx'
      uni.openDocument({
        filePath: path,
        showMenu: true,
        success: function(res) {
          console.log('打开文档成功')
        },
        fail: function(res) {
          console.log(res)
        }
      })
    }

设置excel样式

占据两行

html
<th rowspan="2">供地面积</th>
<th rowspan="2">供地面积</th>

占据两列

html
<th colspan="2">用地单位</th>
<th colspan="2">用地单位</th>

占据两行两列

html
<th colspan="2" rowspan="2">用地单位</th>
<th colspan="2" rowspan="2">用地单位</th>

XML格式Excel

html
<html
  xmlns:v="urn:schemas-microsoft-com:vml"
  xmlns:o="urn:schemas-microsoft-com:office:office"
  xmlns:x="urn:schemas-microsoft-com:office:excel"
  xmlns="http://www.w3.org/TR/REC-html40"
>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <!--[if gte mso 9]>
      <xml>
        <x:ExcelWorkbook>
          <x:ExcelWorksheets>
            <x:ExcelWorksheet>
              <x:Name></x:Name>
              <x:WorksheetOptions><x:Selected /></x:WorksheetOptions>
            </x:ExcelWorksheet>
          </x:ExcelWorksheets>
        </x:ExcelWorkbook>
      </xml>
    <![endif]-->
    <style type="text/css">
      .td {
        width: 84px;
      }
      .gdtjContainer .tb tr {
        text-align: center;
        vertical-align: middle;
      }
      .gdtjContainer .tb th {
        border-left: 0.5pt solid #000;
        border-bottom: 0.5pt solid #000;
        text-align: center;
        font-weight: normal;
        font-size: 10pt;
        height: 30px;
      }
      .gdtjContainer .header th {
        font-size: 12pt;
      }
      .gdtjContainer .tb tr th.noleftborder {
        border-left: none;
      }
      .gdtjContainer .tb tr th.rightborder {
        border-right: 0.5pt solid #000;
      }
    </style>
  </head>
  <body>
    <div class="gdtjContainer">
      <table class="tb" cellspacing="0" cellpadding="0" border="0" width="2184px">
        <colgroup>
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
        </colgroup>
        <tr style="height: 40px">
          <th style="font-size: 20pt; font-family: 宋体; border: none" colspan="26">
            2011年增城市单位土地使用权出让情况登记表(统计时间从2011-06-29至2011-06-30)
          </th>
        </tr>
        <tr>
          <th colspan="23" style="border-left: none"> </th>
          <th style="text-align: left; font-size: 12pt; border-left: none" colspan="3">
            单位:万元、平方米
          </th>
        </tr>
        <tr class="header">
          <th rowspan="2">合同编号</th>
          <th colspan="2" rowspan="2">用地单位</th>
          <th colspan="2" rowspan="2">土地座落</th>
          <th rowspan="2">供地面积</th>
          <th style="border-left: none"> </th>
          <th> </th>
          <th rowspan="2">用途</th>
          <th colspan="3" rowspan="1">出让金</th>
          <th rowspan="2">容积率</th>
          <th rowspan="2">建筑密度</th>
          <th rowspan="2">绿地率</th>
          <th rowspan="2">规划建筑面积</th>
          <th rowspan="2">出让方式</th>
          <th rowspan="2">审批日期</th>
          <th rowspan="2">合同签订日期</th>
          <th rowspan="2">动工期限</th>
          <th rowspan="2">竣工日期</th>
          <th rowspan="2">批次情况</th>
          <th rowspan="2">合同约定缴费期限</th>
          <th rowspan="2">缴费情况</th>
          <th rowspan="2">滞纳金</th>
          <th rowspan="2" class="rightborder">备注</th>
        </tr>
        <tr style="height: 40px" class="header">
          <th>新增面积</th>
          <th style="font-size: 10pt">保障性住房用地占用面积</th>
          <th>应缴</th>
          <th>已缴</th>
          <th>未缴</th>
        </tr>
        <tr>
          <th>440183-2011-</th>
          <th colspan="2">45654</th>
          <th colspan="2"> </th>
          <th>1110000</th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th>111</th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th>拍卖出让</th>
          <th> </th>
          <th>2011-06-29</th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th class="rightborder"> </th>
        </tr>
        <tr>
          <th> </th>
          <th colspan="2">合计</th>
          <th colspan="2"> </th>
          <th>1110000</th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th>111</th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th class="rightborder"> </th>
        </tr>
      </table>
    </div>
  </body>
</html>
<html
  xmlns:v="urn:schemas-microsoft-com:vml"
  xmlns:o="urn:schemas-microsoft-com:office:office"
  xmlns:x="urn:schemas-microsoft-com:office:excel"
  xmlns="http://www.w3.org/TR/REC-html40"
>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <!--[if gte mso 9]>
      <xml>
        <x:ExcelWorkbook>
          <x:ExcelWorksheets>
            <x:ExcelWorksheet>
              <x:Name></x:Name>
              <x:WorksheetOptions><x:Selected /></x:WorksheetOptions>
            </x:ExcelWorksheet>
          </x:ExcelWorksheets>
        </x:ExcelWorkbook>
      </xml>
    <![endif]-->
    <style type="text/css">
      .td {
        width: 84px;
      }
      .gdtjContainer .tb tr {
        text-align: center;
        vertical-align: middle;
      }
      .gdtjContainer .tb th {
        border-left: 0.5pt solid #000;
        border-bottom: 0.5pt solid #000;
        text-align: center;
        font-weight: normal;
        font-size: 10pt;
        height: 30px;
      }
      .gdtjContainer .header th {
        font-size: 12pt;
      }
      .gdtjContainer .tb tr th.noleftborder {
        border-left: none;
      }
      .gdtjContainer .tb tr th.rightborder {
        border-right: 0.5pt solid #000;
      }
    </style>
  </head>
  <body>
    <div class="gdtjContainer">
      <table class="tb" cellspacing="0" cellpadding="0" border="0" width="2184px">
        <colgroup>
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
          <col class="td" />
        </colgroup>
        <tr style="height: 40px">
          <th style="font-size: 20pt; font-family: 宋体; border: none" colspan="26">
            2011年增城市单位土地使用权出让情况登记表(统计时间从2011-06-29至2011-06-30)
          </th>
        </tr>
        <tr>
          <th colspan="23" style="border-left: none"> </th>
          <th style="text-align: left; font-size: 12pt; border-left: none" colspan="3">
            单位:万元、平方米
          </th>
        </tr>
        <tr class="header">
          <th rowspan="2">合同编号</th>
          <th colspan="2" rowspan="2">用地单位</th>
          <th colspan="2" rowspan="2">土地座落</th>
          <th rowspan="2">供地面积</th>
          <th style="border-left: none"> </th>
          <th> </th>
          <th rowspan="2">用途</th>
          <th colspan="3" rowspan="1">出让金</th>
          <th rowspan="2">容积率</th>
          <th rowspan="2">建筑密度</th>
          <th rowspan="2">绿地率</th>
          <th rowspan="2">规划建筑面积</th>
          <th rowspan="2">出让方式</th>
          <th rowspan="2">审批日期</th>
          <th rowspan="2">合同签订日期</th>
          <th rowspan="2">动工期限</th>
          <th rowspan="2">竣工日期</th>
          <th rowspan="2">批次情况</th>
          <th rowspan="2">合同约定缴费期限</th>
          <th rowspan="2">缴费情况</th>
          <th rowspan="2">滞纳金</th>
          <th rowspan="2" class="rightborder">备注</th>
        </tr>
        <tr style="height: 40px" class="header">
          <th>新增面积</th>
          <th style="font-size: 10pt">保障性住房用地占用面积</th>
          <th>应缴</th>
          <th>已缴</th>
          <th>未缴</th>
        </tr>
        <tr>
          <th>440183-2011-</th>
          <th colspan="2">45654</th>
          <th colspan="2"> </th>
          <th>1110000</th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th>111</th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th>拍卖出让</th>
          <th> </th>
          <th>2011-06-29</th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th class="rightborder"> </th>
        </tr>
        <tr>
          <th> </th>
          <th colspan="2">合计</th>
          <th colspan="2"> </th>
          <th>1110000</th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th>111</th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th> </th>
          <th class="rightborder"> </th>
        </tr>
      </table>
    </div>
  </body>
</html>

完整导出excel示例

html
<template>
  <view class="content">
    <form @submit="formSubmit">
      <uni-table border stripe emptyText="暂无数据">
        <!-- 表头行 -->
        <uni-tr>
          <uni-th align="center" width="210">系统名称</uni-th>
          <uni-th align="center" width="40">总体巡视情况确认</uni-th>
        </uni-tr>
        <!-- 表格数据行 -->
        <uni-tr>
          <uni-td>OMS与集中监控系统</uni-td>
          <uni-td align="center">
            <checkbox-group name="1"><checkbox value="true" /></checkbox-group>
          </uni-td>
        </uni-tr>
        <uni-tr>
          <uni-td>EMS D5000系统</uni-td>
          <uni-td align="center">
            <checkbox-group name="2"><checkbox value="true" /></checkbox-group>
          </uni-td>
        </uni-tr>
        <uni-tr>
          <uni-td>电能量数据采集系统</uni-td>
          <uni-td align="center">
            <checkbox-group name="3"><checkbox value="true" /></checkbox-group>
          </uni-td>
        </uni-tr>
        <uni-tr>
          <uni-td>网络安全管理平台(安防平台)</uni-td>
          <uni-td align="center">
            <checkbox-group name="4"><checkbox value="true" /></checkbox-group>
          </uni-td>
        </uni-tr>
        <uni-tr>
          <uni-td>GPS监视系统</uni-td>
          <uni-td align="center">
            <checkbox-group name="5"><checkbox value="true" /></checkbox-group>
          </uni-td>
        </uni-tr>
        <uni-tr>
          <uni-td>配网自动化系统</uni-td>
          <uni-td align="center">
            <checkbox-group name="6"><checkbox value="true" /></checkbox-group>
          </uni-td>
        </uni-tr>
        <uni-tr>
          <uni-td>机房动环等</uni-td>
          <uni-td align="center">
            <checkbox-group name="7"><checkbox value="true" /></checkbox-group>
          </uni-td>
        </uni-tr>
        <uni-tr>
          <uni-td>综合网络管理平台与源网荷</uni-td>
          <uni-td align="center">
            <checkbox-group name="8"><checkbox value="true" /></checkbox-group>
          </uni-td>
        </uni-tr>
      </uni-table>
      <button form-type="submit" type="primary" class="btn">确认提交</button>
      <button type="warn" @click="tableToExcel">导出当日表单为excel</button>
      <button type="info" @click="openExcel">打开当日excel表单</button>
    </form>
    <view v-for="(item, index) in dbData" :key="index">{{ item.key }}</view>
    <uni-popup ref="popup" type="dialog">
      <uni-popup-dialog type="info" title="确认您的提交" content="将提交表单信息至本应用数据库" mode="base" @confirm="confirm"></uni-popup-dialog>
    </uni-popup>
  </view>
</template>

<script>
import { isSqliteOpen, openSqlite, createTable, insertTableData, selectTableData, dropTable } from '@/utils/sqlite.js'
export default {
  data() {
    return {
      keyArr: [
        'OMS与集中监控系统',
        'EMS D5000系统',
        '电能量数据采集系统',
        '网络安全管理平台(安防平台)',
        'GPS监视系统',
        '配网自动化系统',
        '机房动环等',
        '综合网络管理平台与源网荷'
      ],
      // 最终数据
      lastData: [],
      excelPath: '',
      dbData: []
    }
  },
  onReady() {},
  methods: {
    // 触发表单提交事件
    formSubmit(e) {
      this.$refs.popup.open('center') // 打开弹窗
      const lastData = []
      Object.values(e.detail.value).forEach(value => {
        lastData.push(value[0] ? 1 : 0)
      })
      this.lastData = lastData
    },
    // 确认提交后再将数据存入数据库
    confirm() {
      if (isSqliteOpen()) {
        createTable().then(() => {
          let sqlsArr = []
          this.lastData.forEach((item, index) => {
            sqlsArr.push(`INSERT INTO CHECKTABLE VALUES('${this.keyArr[index]}',${item});`)
          })
          console.log(sqlsArr)
          insertTableData(sqlsArr).then(() => {
            console.log('成功存储')
            selectTableData().then(res => {
              console.log(res)
              this.dbData = res
            })
          })
        })
      } else {
        openSqlite()
      }
    },
    tableToExcel() {
      let jsonData = []
      this.lastData.forEach((item, index) => {
        jsonData.push({ key: this.keyArr[index], value: item ? '已确认' : '未确认' })
      })
      // 列标题
      let worksheet = '自动化系统分布情况'
      let str = '<tr><th colspan="2" class="text">系统名称</th><th colspan="2" class="text">总体巡视情况确认</th></tr>'
      // 循环遍历,每行加入tr标签,每个单元格加td标签
      for (let i = 0; i < jsonData.length; i++) {
        str += '<tr>'
        for (let item in jsonData[i]) {
          // 增加\t为了不让表格显示科学计数法或者其他格式
          str += `<td class="text" colspan="2">${jsonData[i][item] + '\t'}</td>`
        }
        str += '</tr>'
      }
      // 下载的表格模板数据
      let template = `<html 
                 xmlns:v="urn:schemas-microsoft-com:vml"
                 xmlns:o="urn:schemas-microsoft-com:office:office"
                 xmlns:x="urn:schemas-microsoft-com:office:excel"
                 xmlns="http://www.w3.org/TR/REC-html40">
                <head>
                  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
                <!--[if gte mso 9]><xml encoding="UTF-8"><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet>
                <x:Name>${worksheet}</x:Name>
                <x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet>
                </x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]-->
                <style type="text/css">
                 .text {
                       text-align: center;
                     }
                </style>
                </head>
                <body><table>${str}</table></body>
                </html>`
      // 下载模板
      this.exportFile(template)
    },
    exportFile(fileData, documentName = '项目Excel文件') {
      plus.io.requestFileSystem(plus.io.PUBLIC_DOCUMENTS, fs => {
        let rootObj = fs.root
        let fullPath = rootObj.fullPath
        console.log('开始导出数据********')
        // 创建文件夹
        rootObj.getDirectory(documentName, { create: true }, dirEntry => {
          // 获取当前的年月继续创建文件夹
          let date = new Date()
          let year = date.getFullYear()
          let month = date.getMonth() + 1
          dirEntry.getDirectory(`${year}${month}月`, { create: true }, dirEntry2 => {
            // 创建文件,防止重名
            let fileName = 'excel'
            dirEntry2.getFile(`${fileName}.xlsx`, { create: true }, fileEntry => {
              fileEntry.createWriter(writer => {
                //  /storage/emulated/0指的就是系统路径
                let pathStr = fullPath.replace('/storage/emulated/0', '')
                writer.onwrite = e => {
                  // 导出路径
                  this.excelPath = `${pathStr}/${documentName}/${year}${month}月`
                  uni.showToast({
                    title: `成功导出`,
                    icon: 'success'
                  })
                }
                writer.write(fileData) // 写入内容
              })
            })
          })
        })
      })
    },
    openExcel() {
      const path = '/storage/emulated/0' + this.excelPath + '/excel.xlsx'
      uni.openDocument({
        filePath: path,
        showMenu: true,
        success: function(res) {
          console.log('打开文档成功')
        },
        fail: function(res) {
          console.log(res)
        }
      })
    }
  }
}
</script>

<style lang="scss">
page {
  background-color: #f1f1f1;

  .content {
    padding: 20rpx;
  }

  .btn {
    margin-top: 40rpx;
  }
}
</style>
<template>
  <view class="content">
    <form @submit="formSubmit">
      <uni-table border stripe emptyText="暂无数据">
        <!-- 表头行 -->
        <uni-tr>
          <uni-th align="center" width="210">系统名称</uni-th>
          <uni-th align="center" width="40">总体巡视情况确认</uni-th>
        </uni-tr>
        <!-- 表格数据行 -->
        <uni-tr>
          <uni-td>OMS与集中监控系统</uni-td>
          <uni-td align="center">
            <checkbox-group name="1"><checkbox value="true" /></checkbox-group>
          </uni-td>
        </uni-tr>
        <uni-tr>
          <uni-td>EMS D5000系统</uni-td>
          <uni-td align="center">
            <checkbox-group name="2"><checkbox value="true" /></checkbox-group>
          </uni-td>
        </uni-tr>
        <uni-tr>
          <uni-td>电能量数据采集系统</uni-td>
          <uni-td align="center">
            <checkbox-group name="3"><checkbox value="true" /></checkbox-group>
          </uni-td>
        </uni-tr>
        <uni-tr>
          <uni-td>网络安全管理平台(安防平台)</uni-td>
          <uni-td align="center">
            <checkbox-group name="4"><checkbox value="true" /></checkbox-group>
          </uni-td>
        </uni-tr>
        <uni-tr>
          <uni-td>GPS监视系统</uni-td>
          <uni-td align="center">
            <checkbox-group name="5"><checkbox value="true" /></checkbox-group>
          </uni-td>
        </uni-tr>
        <uni-tr>
          <uni-td>配网自动化系统</uni-td>
          <uni-td align="center">
            <checkbox-group name="6"><checkbox value="true" /></checkbox-group>
          </uni-td>
        </uni-tr>
        <uni-tr>
          <uni-td>机房动环等</uni-td>
          <uni-td align="center">
            <checkbox-group name="7"><checkbox value="true" /></checkbox-group>
          </uni-td>
        </uni-tr>
        <uni-tr>
          <uni-td>综合网络管理平台与源网荷</uni-td>
          <uni-td align="center">
            <checkbox-group name="8"><checkbox value="true" /></checkbox-group>
          </uni-td>
        </uni-tr>
      </uni-table>
      <button form-type="submit" type="primary" class="btn">确认提交</button>
      <button type="warn" @click="tableToExcel">导出当日表单为excel</button>
      <button type="info" @click="openExcel">打开当日excel表单</button>
    </form>
    <view v-for="(item, index) in dbData" :key="index">{{ item.key }}</view>
    <uni-popup ref="popup" type="dialog">
      <uni-popup-dialog type="info" title="确认您的提交" content="将提交表单信息至本应用数据库" mode="base" @confirm="confirm"></uni-popup-dialog>
    </uni-popup>
  </view>
</template>

<script>
import { isSqliteOpen, openSqlite, createTable, insertTableData, selectTableData, dropTable } from '@/utils/sqlite.js'
export default {
  data() {
    return {
      keyArr: [
        'OMS与集中监控系统',
        'EMS D5000系统',
        '电能量数据采集系统',
        '网络安全管理平台(安防平台)',
        'GPS监视系统',
        '配网自动化系统',
        '机房动环等',
        '综合网络管理平台与源网荷'
      ],
      // 最终数据
      lastData: [],
      excelPath: '',
      dbData: []
    }
  },
  onReady() {},
  methods: {
    // 触发表单提交事件
    formSubmit(e) {
      this.$refs.popup.open('center') // 打开弹窗
      const lastData = []
      Object.values(e.detail.value).forEach(value => {
        lastData.push(value[0] ? 1 : 0)
      })
      this.lastData = lastData
    },
    // 确认提交后再将数据存入数据库
    confirm() {
      if (isSqliteOpen()) {
        createTable().then(() => {
          let sqlsArr = []
          this.lastData.forEach((item, index) => {
            sqlsArr.push(`INSERT INTO CHECKTABLE VALUES('${this.keyArr[index]}',${item});`)
          })
          console.log(sqlsArr)
          insertTableData(sqlsArr).then(() => {
            console.log('成功存储')
            selectTableData().then(res => {
              console.log(res)
              this.dbData = res
            })
          })
        })
      } else {
        openSqlite()
      }
    },
    tableToExcel() {
      let jsonData = []
      this.lastData.forEach((item, index) => {
        jsonData.push({ key: this.keyArr[index], value: item ? '已确认' : '未确认' })
      })
      // 列标题
      let worksheet = '自动化系统分布情况'
      let str = '<tr><th colspan="2" class="text">系统名称</th><th colspan="2" class="text">总体巡视情况确认</th></tr>'
      // 循环遍历,每行加入tr标签,每个单元格加td标签
      for (let i = 0; i < jsonData.length; i++) {
        str += '<tr>'
        for (let item in jsonData[i]) {
          // 增加\t为了不让表格显示科学计数法或者其他格式
          str += `<td class="text" colspan="2">${jsonData[i][item] + '\t'}</td>`
        }
        str += '</tr>'
      }
      // 下载的表格模板数据
      let template = `<html 
                 xmlns:v="urn:schemas-microsoft-com:vml"
                 xmlns:o="urn:schemas-microsoft-com:office:office"
                 xmlns:x="urn:schemas-microsoft-com:office:excel"
                 xmlns="http://www.w3.org/TR/REC-html40">
                <head>
                  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
                <!--[if gte mso 9]><xml encoding="UTF-8"><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet>
                <x:Name>${worksheet}</x:Name>
                <x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet>
                </x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]-->
                <style type="text/css">
                 .text {
                       text-align: center;
                     }
                </style>
                </head>
                <body><table>${str}</table></body>
                </html>`
      // 下载模板
      this.exportFile(template)
    },
    exportFile(fileData, documentName = '项目Excel文件') {
      plus.io.requestFileSystem(plus.io.PUBLIC_DOCUMENTS, fs => {
        let rootObj = fs.root
        let fullPath = rootObj.fullPath
        console.log('开始导出数据********')
        // 创建文件夹
        rootObj.getDirectory(documentName, { create: true }, dirEntry => {
          // 获取当前的年月继续创建文件夹
          let date = new Date()
          let year = date.getFullYear()
          let month = date.getMonth() + 1
          dirEntry.getDirectory(`${year}${month}月`, { create: true }, dirEntry2 => {
            // 创建文件,防止重名
            let fileName = 'excel'
            dirEntry2.getFile(`${fileName}.xlsx`, { create: true }, fileEntry => {
              fileEntry.createWriter(writer => {
                //  /storage/emulated/0指的就是系统路径
                let pathStr = fullPath.replace('/storage/emulated/0', '')
                writer.onwrite = e => {
                  // 导出路径
                  this.excelPath = `${pathStr}/${documentName}/${year}${month}月`
                  uni.showToast({
                    title: `成功导出`,
                    icon: 'success'
                  })
                }
                writer.write(fileData) // 写入内容
              })
            })
          })
        })
      })
    },
    openExcel() {
      const path = '/storage/emulated/0' + this.excelPath + '/excel.xlsx'
      uni.openDocument({
        filePath: path,
        showMenu: true,
        success: function(res) {
          console.log('打开文档成功')
        },
        fail: function(res) {
          console.log(res)
        }
      })
    }
  }
}
</script>

<style lang="scss">
page {
  background-color: #f1f1f1;

  .content {
    padding: 20rpx;
  }

  .btn {
    margin-top: 40rpx;
  }
}
</style>

导出pdf

sh
npm i -s html2canvas jspdf
npm i -s html2canvas jspdf

main.js中挂载

js
import Vue from "vue"
import App from "./App.vue"
import html2Canvas from "html2canvas"
import JsPDF from "jspdf"
const usePdf = {
  install(Vue) {
    Vue.prototype.getPdf = function (title) {
      html2Canvas(document.querySelector("#pdfDom"), {
        // allowTaint: true 表示允许跨越的图片
        allowTaint: true
      }).then(function (canvas) {
        let contentWidth = canvas.width
        let contentHeight = canvas.height
        let imgWidth = contentWidth
        let imgHeight = contentHeight
        // 生成canvas截图,1表示生成的截图质量(0-1)
        let pageData = canvas.toDataURL("image/jpeg", 1.0)
        // new JsPDF接收三个参数,landscape表示横向(默认不填是纵向),打印单位和纸张尺寸
        let PDF = new JsPDF("landscape", "pt", "a4")
        // 调用addImage方法,第一个参数表示生成的截图内容,第二个参数表示图片格式,第三个参数表示距纸张左侧的距离,第四个参数表示距纸张上方的距离,第五个参数表示生成截图的image的宽度,第六个参数表示生成截图的image的高度
        PDF.addImage(pageData, "JPEG", 20, 20, imgWidth, imgHeight)
        // 调用save方法生成pdf文件
        PDF.save(title + ".pdf")
      })
    }
  }
}
Vue.config.productionTip = false
Vue.use(usePdf)
new Vue({
  render: h => h(App)
}).$mount("#app")

import Vue from "vue"
import App from "./App.vue"
import html2Canvas from "html2canvas"
import JsPDF from "jspdf"
const usePdf = {
  install(Vue) {
    Vue.prototype.getPdf = function (title) {
      html2Canvas(document.querySelector("#pdfDom"), {
        // allowTaint: true 表示允许跨越的图片
        allowTaint: true
      }).then(function (canvas) {
        let contentWidth = canvas.width
        let contentHeight = canvas.height
        let imgWidth = contentWidth
        let imgHeight = contentHeight
        // 生成canvas截图,1表示生成的截图质量(0-1)
        let pageData = canvas.toDataURL("image/jpeg", 1.0)
        // new JsPDF接收三个参数,landscape表示横向(默认不填是纵向),打印单位和纸张尺寸
        let PDF = new JsPDF("landscape", "pt", "a4")
        // 调用addImage方法,第一个参数表示生成的截图内容,第二个参数表示图片格式,第三个参数表示距纸张左侧的距离,第四个参数表示距纸张上方的距离,第五个参数表示生成截图的image的宽度,第六个参数表示生成截图的image的高度
        PDF.addImage(pageData, "JPEG", 20, 20, imgWidth, imgHeight)
        // 调用save方法生成pdf文件
        PDF.save(title + ".pdf")
      })
    }
  }
}
Vue.config.productionTip = false
Vue.use(usePdf)
new Vue({
  render: h => h(App)
}).$mount("#app")

页面中使用

js
<template>
  <div id="pdfDom">
    <div>首页</div>
    <button type="button" class="btn btn-primary" @click="getPdf('测试导出pdf')">导出PDF</button>
  </div>
</template>

<style>
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
#pdfDom {
  height: 100vh;
  background-color: pink;
}
</style>

<template>
  <div id="pdfDom">
    <div>首页</div>
    <button type="button" class="btn btn-primary" @click="getPdf('测试导出pdf')">导出PDF</button>
  </div>
</template>

<style>
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
#pdfDom {
  height: 100vh;
  background-color: pink;
}
</style>

多页面

js
import Vue from "vue"
import App from "./App.vue"
import html2Canvas from "html2canvas"
import JsPDF from "jspdf"
const usePdf = {
  install(Vue) {
    Vue.prototype.getPdf = function (title) {
      html2Canvas(document.querySelector("#pdfDom"), {
        // allowTaint: true 表示允许跨越的图片
        allowTaint: true
      }).then(function (canvas) {
        // a4纸的正常尺寸是宽592.28,高是841.89
        const pageWidth = 592.28
        const pageHeight = 841.89
        // 设置内容的宽高
        const contentWidth = canvas.width
        const contentHeight = canvas.height
        // 默认的偏移量
        let position = 0
        // 设置生成图片的宽高
        const imgCanvasWidth = pageWidth
        // const imgCanvasHeight = (841.89 / contentWidth) * contentHeight
        const imgCanvasHeight = contentHeight
        let imageHeight = imgCanvasHeight
        // 生成canvas截图,1表示生成的截图质量(0-1)
        let pageData = canvas.toDataURL("image/jpeg", 1.0)
        // new JsPDF接收三个参数,landscape表示横向(默认不填是纵向),打印单位和纸张尺寸
        let PDF = new JsPDF("landscape", "pt", "a4")
        // 当内容不超过a4纸一页的情况下
        if (imageHeight < pageHeight) {
          // 调用addImage方法,第一个参数表示生成的截图内容,第二个参数表示图片格式,第三个参数表示距纸张左侧的距离,第四个参数表示距纸张上方的距离,第五个参数表示生成截图的image的宽度,第六个参数表示生成截图的image的高度
          PDF.addImage(pageData, "JPEG", 20, 20, imgCanvasWidth, imgCanvasHeight)
        } else {
          // 当内容超过a4纸一页的情况下,需要增加一页
          while (imageHeight > 0) {
            PDF.addImage(pageData, "JPEG", 20, position, imgCanvasWidth, imgCanvasHeight)
            imageHeight -= pageHeight
            position -= pageHeight
            // 避免添加空白页
            if (imageHeight > 0) {
              PDF.addPage()
            }
          }
        }
        // 调用save方法生成pdf文件
        PDF.save(title + ".pdf")
      })
    }
  }
}
Vue.config.productionTip = false
Vue.use(usePdf)
new Vue({
  render: h => h(App)
}).$mount("#app")

import Vue from "vue"
import App from "./App.vue"
import html2Canvas from "html2canvas"
import JsPDF from "jspdf"
const usePdf = {
  install(Vue) {
    Vue.prototype.getPdf = function (title) {
      html2Canvas(document.querySelector("#pdfDom"), {
        // allowTaint: true 表示允许跨越的图片
        allowTaint: true
      }).then(function (canvas) {
        // a4纸的正常尺寸是宽592.28,高是841.89
        const pageWidth = 592.28
        const pageHeight = 841.89
        // 设置内容的宽高
        const contentWidth = canvas.width
        const contentHeight = canvas.height
        // 默认的偏移量
        let position = 0
        // 设置生成图片的宽高
        const imgCanvasWidth = pageWidth
        // const imgCanvasHeight = (841.89 / contentWidth) * contentHeight
        const imgCanvasHeight = contentHeight
        let imageHeight = imgCanvasHeight
        // 生成canvas截图,1表示生成的截图质量(0-1)
        let pageData = canvas.toDataURL("image/jpeg", 1.0)
        // new JsPDF接收三个参数,landscape表示横向(默认不填是纵向),打印单位和纸张尺寸
        let PDF = new JsPDF("landscape", "pt", "a4")
        // 当内容不超过a4纸一页的情况下
        if (imageHeight < pageHeight) {
          // 调用addImage方法,第一个参数表示生成的截图内容,第二个参数表示图片格式,第三个参数表示距纸张左侧的距离,第四个参数表示距纸张上方的距离,第五个参数表示生成截图的image的宽度,第六个参数表示生成截图的image的高度
          PDF.addImage(pageData, "JPEG", 20, 20, imgCanvasWidth, imgCanvasHeight)
        } else {
          // 当内容超过a4纸一页的情况下,需要增加一页
          while (imageHeight > 0) {
            PDF.addImage(pageData, "JPEG", 20, position, imgCanvasWidth, imgCanvasHeight)
            imageHeight -= pageHeight
            position -= pageHeight
            // 避免添加空白页
            if (imageHeight > 0) {
              PDF.addPage()
            }
          }
        }
        // 调用save方法生成pdf文件
        PDF.save(title + ".pdf")
      })
    }
  }
}
Vue.config.productionTip = false
Vue.use(usePdf)
new Vue({
  render: h => h(App)
}).$mount("#app")

canvas保存图片

  1. 绘制canvas
  2. 调用uni.canvasToTempFilePath存储临时路径
  3. 调用uni.saveImageToPhotosAlbum根据临时路径保存图片至手机相册
js
<template>
  <view><canvas style="width: 300px; height: 200px;" canvas-id="firstCanvas" id="firstCanvas" @click="exportImg"></canvas></view>
</template>
<script>
export default {
  onReady() {
    var context = uni.createCanvasContext('firstCanvas')
    context.setStrokeStyle('#00ff00')
    context.setLineWidth(5)
    context.rect(0, 0, 200, 200)
    context.stroke()
    context.setStrokeStyle('#ff0000')
    context.setLineWidth(2)
    context.moveTo(160, 100)
    context.arc(100, 100, 60, 0, 2 * Math.PI, true)
    context.moveTo(140, 100)
    context.arc(100, 100, 40, 0, Math.PI, false)
    context.moveTo(85, 80)
    context.arc(80, 80, 5, 0, 2 * Math.PI, true)
    context.moveTo(125, 80)
    context.arc(120, 80, 5, 0, 2 * Math.PI, true)
    context.stroke()
    context.draw()
  },
  methods: {
    exportImg() {
      uni.canvasToTempFilePath({
        fileType: 'jpg',
        canvasId: 'firstCanvas',
        success: function(res) {
          console.log(res.tempFilePath)
          uni.saveImageToPhotosAlbum({
            filePath: res.tempFilePath,
            success: function() {
              uni.showToast({
                icon: 'none',
                position: 'bottom',
                title: '图片已下载至【相册】,请打开【相册】查看'
              })
            }
          })
        }
      })
    }
  }
}
</script>
<template>
  <view><canvas style="width: 300px; height: 200px;" canvas-id="firstCanvas" id="firstCanvas" @click="exportImg"></canvas></view>
</template>
<script>
export default {
  onReady() {
    var context = uni.createCanvasContext('firstCanvas')
    context.setStrokeStyle('#00ff00')
    context.setLineWidth(5)
    context.rect(0, 0, 200, 200)
    context.stroke()
    context.setStrokeStyle('#ff0000')
    context.setLineWidth(2)
    context.moveTo(160, 100)
    context.arc(100, 100, 60, 0, 2 * Math.PI, true)
    context.moveTo(140, 100)
    context.arc(100, 100, 40, 0, Math.PI, false)
    context.moveTo(85, 80)
    context.arc(80, 80, 5, 0, 2 * Math.PI, true)
    context.moveTo(125, 80)
    context.arc(120, 80, 5, 0, 2 * Math.PI, true)
    context.stroke()
    context.draw()
  },
  methods: {
    exportImg() {
      uni.canvasToTempFilePath({
        fileType: 'jpg',
        canvasId: 'firstCanvas',
        success: function(res) {
          console.log(res.tempFilePath)
          uni.saveImageToPhotosAlbum({
            filePath: res.tempFilePath,
            success: function() {
              uni.showToast({
                icon: 'none',
                position: 'bottom',
                title: '图片已下载至【相册】,请打开【相册】查看'
              })
            }
          })
        }
      })
    }
  }
}
</script>

base64转换图片

  1. Bitmap原生图片对象,会占用较大的内存资源,在使用时需谨慎管理,当图片不再使用时应该及时调用clear方法进行销毁
  2. loadBase64Data方法加载Base64编码格式图片到Bitmap对象
js
 const bitmap = new plus.nativeObj.Bitmap('test')
      bitmap.loadBase64Data(
        this.base64,
        function() {
          const url = '_doc/' + new Date().getTime() + '.pdf' // url为时间戳命名方式
          console.log('saveHeadImgFile', url)
          bitmap.save(
            url,
            {
              overwrite: true // 是否覆盖
              // quality: 'quality'  // 图片清晰度
            },
            i => {
              uni.saveImageToPhotosAlbum({
                filePath: url,
                success: function() {
                  uni.showToast({
                    title: '图片保存成功',
                    icon: 'none'
                  })
                  bitmap.clear()
                }
              })
            },
            e => {
              uni.showToast({
                title: '图片保存失败',
                icon: 'none'
              })
              bitmap.clear()
            }
          )
        },
        e => {
          log(e)
          uni.showToast({
            title: '图片保存失败',
            icon: 'none'
          })
          bitmap.clear()
        }
      )
    }
 const bitmap = new plus.nativeObj.Bitmap('test')
      bitmap.loadBase64Data(
        this.base64,
        function() {
          const url = '_doc/' + new Date().getTime() + '.pdf' // url为时间戳命名方式
          console.log('saveHeadImgFile', url)
          bitmap.save(
            url,
            {
              overwrite: true // 是否覆盖
              // quality: 'quality'  // 图片清晰度
            },
            i => {
              uni.saveImageToPhotosAlbum({
                filePath: url,
                success: function() {
                  uni.showToast({
                    title: '图片保存成功',
                    icon: 'none'
                  })
                  bitmap.clear()
                }
              })
            },
            e => {
              uni.showToast({
                title: '图片保存失败',
                icon: 'none'
              })
              bitmap.clear()
            }
          )
        },
        e => {
          log(e)
          uni.showToast({
            title: '图片保存失败',
            icon: 'none'
          })
          bitmap.clear()
        }
      )
    }

主题切换/换肤

思路来源:https://ext.dcloud.net.cn/plugin?id=6215

思路:

  1. 页面通过style='--theme-color: #fff";'这种写法,样式绑定var变量字符串,主题切换就更改变量值
  2. 研究发现,可以在page选择器中定义var变量,但不能做到更改,所以最终只能每个页面都绑定var变量字符串,再基于vuexmixin简化写法
  3. 使用scss简化var变量写法(可选)
  4. 页面中使用scss变量或者var变量
  5. 原理示例:
vue
<template>
  <view class="content" :style="style">
    <view @click="change">改变</view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      style: "--theme-color: #fff"
    }
  },
  methods: {
    change() {
      this.style =
        this.style === "--theme-color: #fff"
          ? "--theme-color: #000"
          : "--theme-color: #fff"
    }
  }
}
</script>

<style lang="scss">
.content {
  background: var(--theme-color);
  color: pink;
  height: 100vh;
}
</style>
<template>
  <view class="content" :style="style">
    <view @click="change">改变</view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      style: "--theme-color: #fff"
    }
  },
  methods: {
    change() {
      this.style =
        this.style === "--theme-color: #fff"
          ? "--theme-color: #000"
          : "--theme-color: #fff"
    }
  }
}
</script>

<style lang="scss">
.content {
  background: var(--theme-color);
  color: pink;
  height: 100vh;
}
</style>

什么是var变量

https://juejin.cn/post/6937530846471520287

1.新建store/index.js

设置主题后,获取相应主题的var变量字符串

js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
    themeName: "light",
    themeStyle: {
      "light": `
			--nav-bg:#42b983;
			--nav-color:#ffffff;
		`,
      "dark": `
			--nav-bg:#000;
			--nav-color:#ffffff;
		`
    }
  },
  getters: {
    theme(state) {
      return state.themeStyle[state.themeName]
    }
  },
  mutations: {
    setTheme(state, themeName = "light") {
      state.themeName = themeName
    }
  }
})

export default store
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
    themeName: "light",
    themeStyle: {
      "light": `
			--nav-bg:#42b983;
			--nav-color:#ffffff;
		`,
      "dark": `
			--nav-bg:#000;
			--nav-color:#ffffff;
		`
    }
  },
  getters: {
    theme(state) {
      return state.themeStyle[state.themeName]
    }
  },
  mutations: {
    setTheme(state, themeName = "light") {
      state.themeName = themeName
    }
  }
})

export default store

2.使用mixin

每个页面都需要获取相应主题的var变量字符串,使用mixin进行简化写法

js
import {
  mapState,
  mapGetters
} from 'vuex'
export default {
  install(Vue) {
    Vue.mixin({
      computed: {
        ...mapState({
          themeName: 'themeName'
        }),
        ...mapGetters({
          theme: "theme"
        })
      }
    })
  }
}
import {
  mapState,
  mapGetters
} from 'vuex'
export default {
  install(Vue) {
    Vue.mixin({
      computed: {
        ...mapState({
          themeName: 'themeName'
        }),
        ...mapGetters({
          theme: "theme"
        })
      }
    })
  }
}

3.main.js中导入store

js
import Vue from 'vue'
import App from './App'
import store from './store'
import mixin from '@/mixin/themeMixin.js'
Vue.use(mixin)
Vue.config.productionTip = false
App.mpType = 'app'

const app = new Vue({
  store,
  ...App
})
app.$mount()
import Vue from 'vue'
import App from './App'
import store from './store'
import mixin from '@/mixin/themeMixin.js'
Vue.use(mixin)
Vue.config.productionTip = false
App.mpType = 'app'

const app = new Vue({
  store,
  ...App
})
app.$mount()

4.使用scss简化var变量写法(可选)

uni.scss加入代码

scss
$nav-bg: var(--nav-bg);
$nav-color: var(--nav-color);
$nav-bg: var(--nav-bg);
$nav-color: var(--nav-color);

页面中使用var变量的写法

scss
<style lang="scss">
.btn {
  background-color: var(--nav-bg) !important;
  color: var(--nav-color) !important;
}
</style>
<style lang="scss">
.btn {
  background-color: var(--nav-bg) !important;
  color: var(--nav-color) !important;
}
</style>

页面中使用scss变量的写法

scss
<style lang="scss">
.btn {
  background-color: $nav-color !important;
  color: $nav-bg !important;
}
</style>
<style lang="scss">
.btn {
  background-color: $nav-color !important;
  color: $nav-bg !important;
}
</style>

5.切换主题

vue
<template>
  <view :style="theme" class="page">
    <button @click="setTheme('dark')" class="btn">黑夜</button>
    <button @click="setTheme('light')" class="btn">白天</button>
  </view>
</template>

<script>
export default {
  data() {
    return {}
  },
  methods: {
    setTheme(theme) {
      this.$store.commit("setTheme", theme)
    }
  }
}
</script>

<style lang="scss">
.page {
  background-color: $nav-bg;
  height: 100vh;
}

.btn {
  background-color: $nav-color !important;
  color: $nav-bg !important;
}
</style>
<template>
  <view :style="theme" class="page">
    <button @click="setTheme('dark')" class="btn">黑夜</button>
    <button @click="setTheme('light')" class="btn">白天</button>
  </view>
</template>

<script>
export default {
  data() {
    return {}
  },
  methods: {
    setTheme(theme) {
      this.$store.commit("setTheme", theme)
    }
  }
}
</script>

<style lang="scss">
.page {
  background-color: $nav-bg;
  height: 100vh;
}

.btn {
  background-color: $nav-color !important;
  color: $nav-bg !important;
}
</style>

注意点:不能使用page选择器

下方这种写法不能正确切换主题,因为绑定的var变量字符串是绑定在页面最外层元素上的,而page层是页面最外层元素的祖先级(目前没找到办法,更改page层的var变量值)

css
<template>
  <view :style="theme">
  </view>
</template>

<style lang="scss">
page {
  background-color: $nav-bg;
}
</style>
<template>
  <view :style="theme">
  </view>
</template>

<style lang="scss">
page {
  background-color: $nav-bg;
}
</style>

只能使用这种写法

css
<template>
  <view :style="theme" class="page">
  </view>
</template>

<style lang="scss">
.page {
  background-color: $nav-bg;
}
</style>
<template>
  <view :style="theme" class="page">
  </view>
</template>

<style lang="scss">
.page {
  background-color: $nav-bg;
}
</style>

黑白主题

css
page {
  filter: grayscale(100%);
}
page {
  filter: grayscale(100%);
}

设置头部标题

js
  setNavigationBarColor(bool) {
      uni.setNavigationBarColor({
        backgroundColor: bool ? "#ffffff" : "#000000",
        frontColor: bool ? "#000000" : "#ffffff",
      });
    },
  setNavigationBarColor(bool) {
      uni.setNavigationBarColor({
        backgroundColor: bool ? "#ffffff" : "#000000",
        frontColor: bool ? "#000000" : "#ffffff",
      });
    },

隐藏显示TabBar

小程序端才能有动画效果

js
 hideTabBar() {
      uni.hideTabBar({
        animation: true
      })
    },
    showTabBar() {
      uni.showTabBar({
        animation: true
      })
    },
 hideTabBar() {
      uni.hideTabBar({
        animation: true
      })
    },
    showTabBar() {
      uni.showTabBar({
        animation: true
      })
    },

editor

https://uniapp.dcloud.net.cn/api/media/editor-context.html

uniapp h5端和app端可视区域高度不一样问题

h5会把顶部算入视口高度,app端和小程序端不会

滑动切换页面

vue
<template>
  <view class="big">
    <view class="trade">
      <view
        class="texts"
        :class="curr == 0 ? 'active' : ''"
        data-index="0"
        @tap="setCurr">
        第一个页面
      </view>
      <view
        class="texts"
        :class="curr == 1 ? 'active' : ''"
        data-index="1"
        @tap="setCurr">
        第二个页面
      </view>
      <view
        class="texts"
        :class="curr == 2 ? 'active' : ''"
        data-index="2"
        @tap="setCurr">
        第三个页面
      </view>
    </view>
    <swiper
      style="height: 100vh"
      :current="curr"
      @change="setCurr">
      <swiper-item>
        <scroll-view>
          <view class="a">aaa</view>
        </scroll-view>
      </swiper-item>
      <swiper-item>
        <scroll-view>
          <view class="b">b</view>
        </scroll-view>
      </swiper-item>
      <swiper-item>
        <scroll-view>
          <view class="c">c</view>
        </scroll-view>
      </swiper-item>
    </swiper>
  </view>
</template>
<script>
export default {
  data() {
    return {
      curr: 0,
    };
  },
  methods: {
    setCurr(e) {
      // console.log(e.detail.current)
      let thisCurr = e.detail.current || e.currentTarget.dataset.index || 0;
      // console.log(thisCurr)
      this.curr = thisCurr;
    },
  },
};
</script>
<style>
.trade {
  width: 100%;
  color: #007aff;
  overflow: auto;
}
.trade view {
  text-align: center;
  padding-left: 25upx;
  width: 30%;
  float: left;
}
.trade .texts.active {
  border-bottom: 8upx solid #f0ad4e;
}
.a {
  background-color: #007aff;
  height: 100vh;
}
.b {
  background-color: #f0ad4e;
  height: 100vh;
}
.c {
  background-color: antiquewhite;
  height: 100vh;
}
</style>

<template>
  <view class="big">
    <view class="trade">
      <view
        class="texts"
        :class="curr == 0 ? 'active' : ''"
        data-index="0"
        @tap="setCurr">
        第一个页面
      </view>
      <view
        class="texts"
        :class="curr == 1 ? 'active' : ''"
        data-index="1"
        @tap="setCurr">
        第二个页面
      </view>
      <view
        class="texts"
        :class="curr == 2 ? 'active' : ''"
        data-index="2"
        @tap="setCurr">
        第三个页面
      </view>
    </view>
    <swiper
      style="height: 100vh"
      :current="curr"
      @change="setCurr">
      <swiper-item>
        <scroll-view>
          <view class="a">aaa</view>
        </scroll-view>
      </swiper-item>
      <swiper-item>
        <scroll-view>
          <view class="b">b</view>
        </scroll-view>
      </swiper-item>
      <swiper-item>
        <scroll-view>
          <view class="c">c</view>
        </scroll-view>
      </swiper-item>
    </swiper>
  </view>
</template>
<script>
export default {
  data() {
    return {
      curr: 0,
    };
  },
  methods: {
    setCurr(e) {
      // console.log(e.detail.current)
      let thisCurr = e.detail.current || e.currentTarget.dataset.index || 0;
      // console.log(thisCurr)
      this.curr = thisCurr;
    },
  },
};
</script>
<style>
.trade {
  width: 100%;
  color: #007aff;
  overflow: auto;
}
.trade view {
  text-align: center;
  padding-left: 25upx;
  width: 30%;
  float: left;
}
.trade .texts.active {
  border-bottom: 8upx solid #f0ad4e;
}
.a {
  background-color: #007aff;
  height: 100vh;
}
.b {
  background-color: #f0ad4e;
  height: 100vh;
}
.c {
  background-color: antiquewhite;
  height: 100vh;
}
</style>

Released under the MIT License.