├── .babelrc ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── gulpfile.js ├── imgs ├── 1.jpg ├── 2.jpg ├── 3.jpg ├── 4.jpg ├── 5.jpg ├── 6.jpg ├── 7.jpg └── 8.jpg ├── miniprogram_dev ├── app.js ├── app.json ├── app.wxss ├── components │ ├── assets │ │ ├── copy.wxss │ │ └── icon.png │ ├── common.wxss │ ├── index.js │ ├── index.js.map │ ├── index.json │ ├── index.wxml │ ├── index.wxss │ ├── lib.js │ ├── lib.js.map │ ├── reset.wxss │ └── utils.js ├── package.json ├── pages │ └── index │ │ ├── config.js │ │ ├── index.js │ │ ├── index.json │ │ ├── index.wxml │ │ └── index.wxss ├── project.config.json └── sitemap.json ├── miniprogram_dist ├── index.js ├── index.js.map ├── index.json ├── index.wxml ├── index.wxss ├── lib.js └── lib.js.map ├── package.json ├── src ├── index.js ├── index.json ├── index.wxml ├── index.wxss └── lib.ts ├── test ├── index.test.js ├── utils.js └── wx.test.js ├── tools ├── build.js ├── checkcomponents.js ├── checkwxss.js ├── config.js ├── demo │ ├── app.js │ ├── app.json │ ├── app.wxss │ ├── package.json │ ├── pages │ │ └── index │ │ │ ├── index.js │ │ │ ├── index.json │ │ │ ├── index.wxml │ │ │ └── index.wxss │ └── project.config.json └── utils.js └── tsconfig.json /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["module-resolver", { 4 | "root": ["./src"], 5 | "alias": {} 6 | }] 7 | ], 8 | "presets": [ 9 | ["env", {"loose": true, "modules": "commonjs"}] 10 | ] 11 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .DS_Store 3 | package-lock.json 4 | 5 | logs 6 | *.log 7 | npm-debug.log* 8 | yarn-debug.log* 9 | yarn-error.log* 10 | 11 | node_modules 12 | coverage -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .DS_Store 3 | package-lock.json 4 | 5 | logs 6 | *.log 7 | npm-debug.log* 8 | yarn-debug.log* 9 | yarn-error.log* 10 | 11 | test 12 | tools 13 | docs 14 | miniprogram_dev 15 | node_modules 16 | coverage -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 wechat-miniprogram 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # miniprogram-table-component 2 | 3 | 微信小程序自定义组件 - table组件 - 支持第三方npm包使用 4 | 5 | > 使用此组件需要依赖小程序基础库 2.2.2 版本,同时依赖开发者工具的 npm 构建。具体详情可查阅[官方 npm 文档](https://github.com/wechat-miniprogram/miniprogram-custom-component/blob/master/README.md)。 6 | 7 | ## table组件 8 | 9 | 实现了table的以下功能: 10 | 11 | - 1.基础表格 12 | - 2.带斑马纹表格 13 | - 3.带间隔边框表格 14 | - 4.自定义无数据的提示文案 15 | - 5.自定义表格头样式 16 | - 6.固定表头 17 | - 7.表格横向滑动 18 | - 8.自定义表格行和单元格样式 19 | - 9.某一行被点击时会触发对外事件 20 | 21 | ## 快速上手 22 | 23 | 一个简易的微信小程序 `table组件`诞生了。使用很简单,就是按照npm包和微信自定组件的用法使用。 24 | 25 | ### 1、安装和引入 26 | - 安装组件: 27 | ``` 28 | npm install --save miniprogram-table-component 29 | ``` 30 | - 引入table自定义组件 31 | 32 | 在页面的 json 配置文件中添加 recycle-view 和 recycle-item 自定义组件的配置 33 | 34 | ```json 35 | { 36 | "usingComponents": { 37 | "table-view": "../../../miniprogram_npm/miniprogram-table-component" 38 | } 39 | } 40 | ``` 41 | 42 | > 注意:npm包的路径。如果这里遇到找不到包的问题,可以查看下方的 `微信小程序 npm 找到不到npm包的坑?` 43 | 44 | ### 2、使用table组件 45 | 46 | 在wxml页面需要用到的地方使用,如下: 47 | 48 | ```html 49 | 55 | ``` 56 | 57 | 在js页面需要用到的地方使用,如下: 58 | 59 | ```javascript 60 | Page({ 61 | /** 62 | * 页面的初始数据 63 | */ 64 | data: { 65 | tableHeader: [ 66 | { 67 | prop: 'datetime', 68 | width: 150, 69 | label: '日期', 70 | color: '#55C355' 71 | }, 72 | { 73 | prop: 'sign_in', 74 | width: 152, 75 | label: '上班时间' 76 | }, 77 | { 78 | prop: 'sign_out', 79 | width: 152, 80 | label: '下班时间' 81 | }, 82 | { 83 | prop: 'work_hour', 84 | width: 110, 85 | label: '工时' 86 | }, 87 | { 88 | prop: 'statusText', 89 | width: 110, 90 | label: '状态' 91 | } 92 | ], 93 | stripe: true, 94 | border: true, 95 | outBorder: true, 96 | row: [ 97 | { 98 | "id": 1, 99 | "status": '正常', 100 | "datetime": "04-01", 101 | "sign_in_time": '09:30:00', 102 | "sign_out_time": '18:30:00', 103 | "work_hour": 8, 104 | }, { 105 | "id": 2, 106 | "status": '迟到', 107 | "datetime": "04-02", 108 | "sign_in_time": '10:30:00', 109 | "sign_out_time": '18:30:00', 110 | "work_hour": 7, 111 | }, { 112 | "id": 29, 113 | "status": '正常', 114 | "datetime": "04-03", 115 | "sign_in_time": '09:30:00', 116 | "sign_out_time": '18:30:00', 117 | "work_hour": 8, 118 | }, { 119 | "id": 318, 120 | "status": '休息日', 121 | "datetime": "04-04", 122 | "sign_in_time": '', 123 | "sign_out_time": '', 124 | "work_hour": '', 125 | }, { 126 | "id": 319, 127 | "status": '正常', 128 | "datetime": "04-05", 129 | "sign_in_time": '09:30:00', 130 | "sign_out_time": '18:30:00', 131 | "work_hour": 8, 132 | } 133 | ], 134 | msg: '暂无数据' 135 | }, 136 | 137 | /** 138 | * 点击表格一行 139 | */ 140 | onRowClick: function(e) { 141 | console.log('e: ', e) 142 | } 143 | }) 144 | ``` 145 | 146 | 147 | ### 3、配置 148 | 149 | 配置部分主要配置这么几个属性,分别是: 150 | 151 | 配置项 | 说明 | 类型 | 可选值 | 默认值 | 必填 152 | ---|---|---|---|---|--- 153 | headers | 表格头部标题、列宽度、列属性 | Array | `{prop: 'datetime', width: 150, label: '日期'}` | [] | yes 154 | data | 表格列表数据 | Array | | [] | no 155 | stripe | 是否为斑马纹 | boolean | true/false | false | no 156 | border | 是否有间隔线 | boolean | true/false | false | no 157 | height | 纵向内容过多时,可选择设置高度固定表头。 | string | | auto | no 158 | msg | 固定无数据情况,展示文案 | string | | `暂无数据~` | no 159 | header-row-class-name | 自定义表格头样式 | string | | | no 160 | row-class-name | 自定义表格行样式 | string | | | no 161 | cell-class-name | 自定义单元格样式 | string | | | no 162 | bind:rowHandle | 行被点击时会触发该事件 | string | | | no 163 | 164 | 配置相关代码🌰: 165 | 166 | ```javascript 167 | 180 | ``` 181 | > `header-row-class-name`、`row-class-name`、`cell-class-name` 是通过externalClasses支持外部样式,在父组件中控制表格的样式,[externalClasses外部样式类, 官方说明](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/wxml-wxss.html)。例子源码通过[github地址](https://github.com/habc0807/miniprogram-table-component)查看。 182 | 183 | ## 实现一个自定义表格组件遇到的坑 184 | 185 | ### npm 登录不上和发布不了的问题? 186 | 187 | 之前也发布过 npm 包,遗忘了 `npm login` 登录不上需要将淘宝镜像改回npm的。还有一点需要注意的是,每次发布都需要更新 `package.json` 文件里的版本号。 188 | 189 | ### 微信小程序 npm 找到不到npm包的坑? 190 | 191 | 组件开发完,引入使用的时候,发现npm的包,找不到了?这里比较坑的是小程序的npm有特殊的使用方式。 192 | 193 | - 首先在项目的根目录初始化 npm: 194 | 195 | ``` 196 | npm init -f 197 | ``` 198 | - 然后安装对应的自定义组件包 199 | 200 | ``` 201 | npm install -production miniprogram-table-component 202 | ``` 203 | > npm/cnpm/yarn add 均可 204 | 205 | - 在微信开发者工具中,设置 —> 项目设置—> 勾选使用npm模块。 206 | 207 | - 在微信开发者工具中,工具 —> 构建npm,构建完成会生成 `miniprogram_npm` 文件夹,项目用到的npm包都在这里。 208 | - 按照自己的使用路径,从 `miniprogram_npm` 引入需要的包。 209 | 210 | 211 | ## 源码 212 | 213 | - [npm地址](https://www.npmjs.com/package/miniprogram-table-component) 214 | - [github地址](https://github.com/habc0807/miniprogram-table-component) 215 | 216 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp') 2 | const clean = require('gulp-clean') 3 | 4 | const config = require('./tools/config') 5 | const BuildTask = require('./tools/build') 6 | const id = require('./package.json').name || 'miniprogram-custom-component' 7 | 8 | // 构建任务实例 9 | // eslint-disable-next-line no-new 10 | new BuildTask(id, config.entry) 11 | 12 | // 清空生成目录和文件 13 | gulp.task('clean', gulp.series(() => gulp.src(config.distPath, {read: false, allowEmpty: true}).pipe(clean()), done => { 14 | if (config.isDev) { 15 | return gulp.src(config.demoDist, {read: false, allowEmpty: true}) 16 | .pipe(clean()) 17 | } 18 | 19 | return done() 20 | })) 21 | // 监听文件变化并进行开发模式构建 22 | gulp.task('watch', gulp.series(`${id}-watch`)) 23 | // 开发模式构建 24 | gulp.task('dev', gulp.series(`${id}-dev`)) 25 | // 生产模式构建 26 | gulp.task('default', gulp.series(`${id}-default`)) 27 | -------------------------------------------------------------------------------- /imgs/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habc0807/miniprogram-table-component/be20af2c32e8616de021de2642e53ad5c8de15ac/imgs/1.jpg -------------------------------------------------------------------------------- /imgs/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habc0807/miniprogram-table-component/be20af2c32e8616de021de2642e53ad5c8de15ac/imgs/2.jpg -------------------------------------------------------------------------------- /imgs/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habc0807/miniprogram-table-component/be20af2c32e8616de021de2642e53ad5c8de15ac/imgs/3.jpg -------------------------------------------------------------------------------- /imgs/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habc0807/miniprogram-table-component/be20af2c32e8616de021de2642e53ad5c8de15ac/imgs/4.jpg -------------------------------------------------------------------------------- /imgs/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habc0807/miniprogram-table-component/be20af2c32e8616de021de2642e53ad5c8de15ac/imgs/5.jpg -------------------------------------------------------------------------------- /imgs/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habc0807/miniprogram-table-component/be20af2c32e8616de021de2642e53ad5c8de15ac/imgs/6.jpg -------------------------------------------------------------------------------- /imgs/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habc0807/miniprogram-table-component/be20af2c32e8616de021de2642e53ad5c8de15ac/imgs/7.jpg -------------------------------------------------------------------------------- /imgs/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habc0807/miniprogram-table-component/be20af2c32e8616de021de2642e53ad5c8de15ac/imgs/8.jpg -------------------------------------------------------------------------------- /miniprogram_dev/app.js: -------------------------------------------------------------------------------- 1 | App({}) 2 | -------------------------------------------------------------------------------- /miniprogram_dev/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages": [ 3 | "pages/index/index" 4 | ], 5 | "window": { 6 | "backgroundTextStyle": "light", 7 | "navigationBarBackgroundColor": "#fff", 8 | "navigationBarTitleText": "WeChat", 9 | "navigationBarTextStyle": "black" 10 | }, 11 | "sitemapLocation": "sitemap.json" 12 | } -------------------------------------------------------------------------------- /miniprogram_dev/app.wxss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habc0807/miniprogram-table-component/be20af2c32e8616de021de2642e53ad5c8de15ac/miniprogram_dev/app.wxss -------------------------------------------------------------------------------- /miniprogram_dev/components/assets/copy.wxss: -------------------------------------------------------------------------------- 1 | page { 2 | width: 100%; 3 | } 4 | -------------------------------------------------------------------------------- /miniprogram_dev/components/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habc0807/miniprogram-table-component/be20af2c32e8616de021de2642e53ad5c8de15ac/miniprogram_dev/components/assets/icon.png -------------------------------------------------------------------------------- /miniprogram_dev/components/common.wxss: -------------------------------------------------------------------------------- 1 | @import "./reset.wxss"; 2 | 3 | .other { 4 | font-size: 20px; 5 | } 6 | -------------------------------------------------------------------------------- /miniprogram_dev/components/index.js: -------------------------------------------------------------------------------- 1 | module.exports = 2 | /******/ (function(modules) { // webpackBootstrap 3 | /******/ // The module cache 4 | /******/ var installedModules = {}; 5 | /******/ 6 | /******/ // The require function 7 | /******/ function __webpack_require__(moduleId) { 8 | /******/ 9 | /******/ // Check if module is in cache 10 | /******/ if(installedModules[moduleId]) { 11 | /******/ return installedModules[moduleId].exports; 12 | /******/ } 13 | /******/ // Create a new module (and put it into the cache) 14 | /******/ var module = installedModules[moduleId] = { 15 | /******/ i: moduleId, 16 | /******/ l: false, 17 | /******/ exports: {} 18 | /******/ }; 19 | /******/ 20 | /******/ // Execute the module function 21 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 22 | /******/ 23 | /******/ // Flag the module as loaded 24 | /******/ module.l = true; 25 | /******/ 26 | /******/ // Return the exports of the module 27 | /******/ return module.exports; 28 | /******/ } 29 | /******/ 30 | /******/ 31 | /******/ // expose the modules object (__webpack_modules__) 32 | /******/ __webpack_require__.m = modules; 33 | /******/ 34 | /******/ // expose the module cache 35 | /******/ __webpack_require__.c = installedModules; 36 | /******/ 37 | /******/ // define getter function for harmony exports 38 | /******/ __webpack_require__.d = function(exports, name, getter) { 39 | /******/ if(!__webpack_require__.o(exports, name)) { 40 | /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); 41 | /******/ } 42 | /******/ }; 43 | /******/ 44 | /******/ // define __esModule on exports 45 | /******/ __webpack_require__.r = function(exports) { 46 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 47 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 48 | /******/ } 49 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 50 | /******/ }; 51 | /******/ 52 | /******/ // create a fake namespace object 53 | /******/ // mode & 1: value is a module id, require it 54 | /******/ // mode & 2: merge all properties of value into the ns 55 | /******/ // mode & 4: return value when already ns object 56 | /******/ // mode & 8|1: behave like require 57 | /******/ __webpack_require__.t = function(value, mode) { 58 | /******/ if(mode & 1) value = __webpack_require__(value); 59 | /******/ if(mode & 8) return value; 60 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 61 | /******/ var ns = Object.create(null); 62 | /******/ __webpack_require__.r(ns); 63 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 64 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 65 | /******/ return ns; 66 | /******/ }; 67 | /******/ 68 | /******/ // getDefaultExport function for compatibility with non-harmony modules 69 | /******/ __webpack_require__.n = function(module) { 70 | /******/ var getter = module && module.__esModule ? 71 | /******/ function getDefault() { return module['default']; } : 72 | /******/ function getModuleExports() { return module; }; 73 | /******/ __webpack_require__.d(getter, 'a', getter); 74 | /******/ return getter; 75 | /******/ }; 76 | /******/ 77 | /******/ // Object.prototype.hasOwnProperty.call 78 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 79 | /******/ 80 | /******/ // __webpack_public_path__ 81 | /******/ __webpack_require__.p = ""; 82 | /******/ 83 | /******/ 84 | /******/ // Load entry module and return exports 85 | /******/ return __webpack_require__(__webpack_require__.s = 0); 86 | /******/ }) 87 | /************************************************************************/ 88 | /******/ ([ 89 | /* 0 */ 90 | /***/ (function(module, exports, __webpack_require__) { 91 | 92 | "use strict"; 93 | 94 | 95 | var _ = __webpack_require__(1); 96 | 97 | Component({ 98 | /** 99 | * 外部样式类 100 | */ 101 | externalClasses: ['header-row-class-name', 'row-class-name', 'cell-class-name'], 102 | 103 | /** 104 | * 组件样式隔离 105 | */ 106 | options: { 107 | styleIsolation: "isolated", 108 | multipleSlots: true // 支持多个slot 109 | }, 110 | 111 | /** 112 | * 组件的属性列表 113 | */ 114 | properties: { 115 | data: { 116 | type: Array, 117 | value: [] 118 | }, 119 | headers: { 120 | type: Array, 121 | value: [] 122 | }, 123 | // table的高度, 溢出可滚动 124 | height: { 125 | type: String, 126 | value: 'auto' 127 | }, 128 | width: { 129 | type: Number || String, 130 | value: '100%' 131 | }, 132 | // 单元格的宽度 133 | tdWidth: { 134 | type: Number, 135 | value: 35 136 | }, 137 | // 固定表头 thead达到Header的位置时就应该被fixed了 138 | offsetTop: { 139 | type: Number, 140 | value: 150 141 | }, 142 | // 是否带有纵向边框 143 | stripe: { 144 | type: Boolean, 145 | value: false 146 | }, 147 | // 是否带有纵向边框 148 | border: { 149 | type: Boolean, 150 | value: false 151 | }, 152 | msg: { 153 | type: String, 154 | value: '暂无数据~' 155 | } 156 | }, 157 | 158 | /** 159 | * 组件的初始数据 160 | */ 161 | data: { 162 | scrolWidth: '100%' 163 | }, 164 | 165 | /** 166 | * 组件的监听属性 167 | */ 168 | observers: { 169 | // 在 numberA 或者 numberB 被设置时,执行这个函数 170 | 'headers': function headers(_headers) { 171 | var reducer = function reducer(accumulator, currentValue) { 172 | return accumulator + Number(currentValue.width); 173 | }; 174 | var scrolWidth = _headers.reduce(reducer, 0); 175 | 176 | this.setData({ 177 | scrolWidth: scrolWidth 178 | }); 179 | } 180 | }, 181 | 182 | /** 183 | * 组件的方法列表 184 | */ 185 | methods: { 186 | onRowClick: function onRowClick(e) { 187 | this.triggerEvent('rowClick', e, e.currentTarget.dataset.it); 188 | } 189 | } 190 | }); 191 | 192 | /***/ }), 193 | /* 1 */ 194 | /***/ (function(module, exports, __webpack_require__) { 195 | 196 | "use strict"; 197 | 198 | 199 | module.exports = { 200 | getFlag: function getFlag() { 201 | return true; 202 | } 203 | }; 204 | 205 | /***/ }) 206 | /******/ ]); 207 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /miniprogram_dev/components/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack:///webpack/bootstrap","webpack:///./src/index.js","webpack:///./src/utils.js"],"names":["_","require","Component","externalClasses","options","styleIsolation","multipleSlots","properties","data","type","Array","value","headers","height","String","width","Number","tdWidth","offsetTop","stripe","Boolean","border","msg","scrolWidth","observers","reducer","accumulator","currentValue","reduce","setData","methods","onRowClick","e","triggerEvent","currentTarget","dataset","it","module","exports","getFlag"],"mappings":";;QAAA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;;QAEA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;;;QAGA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;QACA,0CAA0C,gCAAgC;QAC1E;QACA;;QAEA;QACA;QACA;QACA,wDAAwD,kBAAkB;QAC1E;QACA,iDAAiD,cAAc;QAC/D;;QAEA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA,yCAAyC,iCAAiC;QAC1E,gHAAgH,mBAAmB,EAAE;QACrI;QACA;;QAEA;QACA;QACA;QACA,2BAA2B,0BAA0B,EAAE;QACvD,iCAAiC,eAAe;QAChD;QACA;QACA;;QAEA;QACA,sDAAsD,+DAA+D;;QAErH;QACA;;;QAGA;QACA;;;;;;;;;;AClFA,IAAMA,IAAIC,mBAAOA,CAACA,CAASA,CAA3B;;AAEAC,UAAU;AACR;;;AAGAC,mBAAiB,CAAC,uBAAD,EAA0B,gBAA1B,EAA4C,iBAA5C,CAJT;;AAMR;;;AAGAC,WAAS;AACPC,oBAAgB,UADT;AAEPC,mBAAe,IAFR,CAEc;AAFd,GATD;;AAcR;;;AAGAC,cAAY;AACVC,UAAM;AACJC,YAAMC,KADF;AAEJC,aAAO;AAFH,KADI;AAKVC,aAAS;AACPH,YAAMC,KADC;AAEPC,aAAO;AAFA,KALC;AASV;AACAE,YAAQ;AACNJ,YAAMK,MADA;AAENH,aAAO;AAFD,KAVE;AAcVI,WAAO;AACLN,YAAMO,UAAUF,MADX;AAELH,aAAO;AAFF,KAdG;AAkBV;AACAM,aAAS;AACPR,YAAMO,MADC;AAEPL,aAAO;AAFA,KAnBC;AAuBV;AACAO,eAAW;AACTT,YAAMO,MADG;AAETL,aAAO;AAFE,KAxBD;AA4BV;AACAQ,YAAQ;AACNV,YAAMW,OADA;AAENT,aAAO;AAFD,KA7BE;AAiCV;AACAU,YAAQ;AACNZ,YAAMW,OADA;AAENT,aAAO;AAFD,KAlCE;AAsCVW,SAAK;AACHb,YAAMK,MADH;AAEHH,aAAO;AAFJ;AAtCK,GAjBJ;;AA6DR;;;AAGAH,QAAM;AACJe,gBAAY;AADR,GAhEE;;AAoER;;;AAGAC,aAAW;AACT;AACA,eAAW,iBAAUZ,QAAV,EAAmB;AAC5B,UAAMa,UAAU,SAAVA,OAAU,CAACC,WAAD,EAAcC,YAAd,EAA+B;AAC7C,eAAOD,cAAcV,OAAOW,aAAaZ,KAApB,CAArB;AACD,OAFD;AAGA,UAAMQ,aAAaX,SAAQgB,MAAR,CAAeH,OAAf,EAAwB,CAAxB,CAAnB;;AAEA,WAAKI,OAAL,CAAa;AACXN,oBAAYA;AADD,OAAb;AAGD;AAXQ,GAvEH;;AAqFR;;;AAGAO,WAAS;AACPC,cADO,sBACIC,CADJ,EACO;AACZ,WAAKC,YAAL,CAAkB,UAAlB,EAA8BD,CAA9B,EAAiCA,EAAEE,aAAF,CAAgBC,OAAhB,CAAwBC,EAAzD;AACD;AAHM;AAxFD,CAAV,E;;;;;;;;;ACFAC,OAAOC,OAAP,GAAiB;AACfC,SADe,qBACL;AACR,WAAO,IAAP;AACD;AAHc,CAAjB,C","file":"index.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n","const _ = require('./utils')\n\nComponent({\n /**\n * 外部样式类\n */\n externalClasses: ['header-row-class-name', 'row-class-name', 'cell-class-name'], \n\n /**\n * 组件样式隔离\n */\n options: {\n styleIsolation: \"isolated\", \n multipleSlots: true, // 支持多个slot\n },\n\n /**\n * 组件的属性列表\n */\n properties: {\n data: {\n type: Array,\n value: []\n },\n headers: {\n type: Array,\n value: []\n },\n // table的高度, 溢出可滚动\n height: { \n type: String,\n value: 'auto'\n },\n width: {\n type: Number || String,\n value: '100%'\n },\n // 单元格的宽度\n tdWidth: {\n type: Number,\n value: 35\n },\n // 固定表头 thead达到Header的位置时就应该被fixed了\n offsetTop: {\n type: Number,\n value: 150\n },\n // 是否带有纵向边框\n stripe: {\n type: Boolean,\n value: false\n },\n // 是否带有纵向边框\n border: {\n type: Boolean,\n value: false\n }, \n msg: {\n type: String,\n value: '暂无数据~'\n }\n },\n\n /**\n * 组件的初始数据\n */\n data: {\n scrolWidth: '100%'\n },\n\n /**\n * 组件的监听属性\n */\n observers: {\n // 在 numberA 或者 numberB 被设置时,执行这个函数\n 'headers': function (headers) {\n const reducer = (accumulator, currentValue) => {\n return accumulator + Number(currentValue.width)\n };\n const scrolWidth = headers.reduce(reducer, 0)\n\n this.setData({\n scrolWidth: scrolWidth\n })\n }\n },\n\n /**\n * 组件的方法列表\n */\n methods: {\n onRowClick(e) {\n this.triggerEvent('rowClick', e, e.currentTarget.dataset.it)\n },\n }\n})","module.exports = {\n getFlag() {\n return true\n },\n}\n"],"sourceRoot":""} -------------------------------------------------------------------------------- /miniprogram_dev/components/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {}, 4 | "componentGenerics": { 5 | "genericsTest": true 6 | } 7 | } -------------------------------------------------------------------------------- /miniprogram_dev/components/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 13 | {{ item.label }} 14 | 15 | 16 | 17 | 18 | 19 | 24 | 31 | 32 | 42 | {{it[head["prop"]]}} 43 | 44 | 45 | 46 | 47 | 48 | {{ msg }} 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /miniprogram_dev/components/index.wxss: -------------------------------------------------------------------------------- 1 | @import "./common.wxss"; 2 | @import "./reset.wxss"; 3 | 4 | .table { 5 | position: relative; 6 | font-size: 28rpx; 7 | background: #fff; 8 | border-right:none; 9 | border-radius: 8rpx; 10 | overflow: hidden; 11 | } 12 | .thead{ 13 | border-bottom: none; 14 | display: flex; 15 | justify-content: flex-start; 16 | border-top-right-radius: 8rpx; 17 | border-top-left-radius: 8rpx; 18 | overflow: visible; 19 | color: #909399; 20 | border: 1px solid #ebeef5; 21 | box-sizing: border-box; 22 | } 23 | .thead .td { 24 | padding: 20rpx 10rpx; 25 | font-weight: bold; 26 | display: inline-block; 27 | white-space:nowrap; 28 | text-align: center; 29 | border-right: 1rpx solid #fff; 30 | } 31 | .thead .td:last-child { 32 | border-right: none; 33 | } 34 | .thead-border .td { 35 | border-right: 1rpx solid #ebeef5; 36 | } 37 | .thead-border .td:last-child { 38 | border-right: none; 39 | } 40 | /* .tr{ 41 | display: flex; 42 | white-space:nowrap; 43 | } */ 44 | .tbody { 45 | box-sizing: border-box; 46 | font-size: 28rpx; 47 | color: #666; 48 | border: 1px solid #ebeef5; 49 | border-top: none; 50 | border-bottom-left-radius: 8rpx; 51 | border-bottom-right-radius: 8rpx; 52 | } 53 | .tbody-tr { 54 | display: flex; 55 | border-bottom: 1px solid #ebeef5; 56 | } 57 | .tbody-tr:last-child { 58 | border-bottom-left-radius: 8rpx; 59 | border-bottom-right-radius: 8rpx; 60 | } 61 | 62 | .tbody-tr-stripe { 63 | background: #fff; 64 | border-bottom: none; 65 | } 66 | .tbody-tr-stripe:nth-child(2n) { 67 | background: #F6F6F6; 68 | } 69 | .tbody-tr .td { 70 | white-space: wrap; 71 | padding:20rpx 10rpx; 72 | text-align: center; 73 | } 74 | 75 | .tbody-tr-border .td { 76 | border-right: 1rpx solid #F6F6F6; 77 | } 78 | .tbody-tr-border .td:last-child { 79 | border-right: none; 80 | } 81 | .no-data { 82 | display: flex; 83 | padding: 50rpx; 84 | color: #666; 85 | justify-content: center; 86 | } -------------------------------------------------------------------------------- /miniprogram_dev/components/lib.js: -------------------------------------------------------------------------------- 1 | module.exports = 2 | /******/ (function(modules) { // webpackBootstrap 3 | /******/ // The module cache 4 | /******/ var installedModules = {}; 5 | /******/ 6 | /******/ // The require function 7 | /******/ function __webpack_require__(moduleId) { 8 | /******/ 9 | /******/ // Check if module is in cache 10 | /******/ if(installedModules[moduleId]) { 11 | /******/ return installedModules[moduleId].exports; 12 | /******/ } 13 | /******/ // Create a new module (and put it into the cache) 14 | /******/ var module = installedModules[moduleId] = { 15 | /******/ i: moduleId, 16 | /******/ l: false, 17 | /******/ exports: {} 18 | /******/ }; 19 | /******/ 20 | /******/ // Execute the module function 21 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 22 | /******/ 23 | /******/ // Flag the module as loaded 24 | /******/ module.l = true; 25 | /******/ 26 | /******/ // Return the exports of the module 27 | /******/ return module.exports; 28 | /******/ } 29 | /******/ 30 | /******/ 31 | /******/ // expose the modules object (__webpack_modules__) 32 | /******/ __webpack_require__.m = modules; 33 | /******/ 34 | /******/ // expose the module cache 35 | /******/ __webpack_require__.c = installedModules; 36 | /******/ 37 | /******/ // define getter function for harmony exports 38 | /******/ __webpack_require__.d = function(exports, name, getter) { 39 | /******/ if(!__webpack_require__.o(exports, name)) { 40 | /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); 41 | /******/ } 42 | /******/ }; 43 | /******/ 44 | /******/ // define __esModule on exports 45 | /******/ __webpack_require__.r = function(exports) { 46 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 47 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 48 | /******/ } 49 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 50 | /******/ }; 51 | /******/ 52 | /******/ // create a fake namespace object 53 | /******/ // mode & 1: value is a module id, require it 54 | /******/ // mode & 2: merge all properties of value into the ns 55 | /******/ // mode & 4: return value when already ns object 56 | /******/ // mode & 8|1: behave like require 57 | /******/ __webpack_require__.t = function(value, mode) { 58 | /******/ if(mode & 1) value = __webpack_require__(value); 59 | /******/ if(mode & 8) return value; 60 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 61 | /******/ var ns = Object.create(null); 62 | /******/ __webpack_require__.r(ns); 63 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 64 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 65 | /******/ return ns; 66 | /******/ }; 67 | /******/ 68 | /******/ // getDefaultExport function for compatibility with non-harmony modules 69 | /******/ __webpack_require__.n = function(module) { 70 | /******/ var getter = module && module.__esModule ? 71 | /******/ function getDefault() { return module['default']; } : 72 | /******/ function getModuleExports() { return module; }; 73 | /******/ __webpack_require__.d(getter, 'a', getter); 74 | /******/ return getter; 75 | /******/ }; 76 | /******/ 77 | /******/ // Object.prototype.hasOwnProperty.call 78 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 79 | /******/ 80 | /******/ // __webpack_public_path__ 81 | /******/ __webpack_require__.p = ""; 82 | /******/ 83 | /******/ 84 | /******/ // Load entry module and return exports 85 | /******/ return __webpack_require__(__webpack_require__.s = 2); 86 | /******/ }) 87 | /************************************************************************/ 88 | /******/ ({ 89 | 90 | /***/ 2: 91 | /***/ (function(module, exports, __webpack_require__) { 92 | 93 | "use strict"; 94 | 95 | 96 | exports.__esModule = true; 97 | exports.default = { 98 | printf: function printf() { 99 | return 'miniprogram-custom-component api demo'; 100 | } 101 | }; 102 | 103 | /***/ }) 104 | 105 | /******/ }); 106 | //# sourceMappingURL=lib.js.map -------------------------------------------------------------------------------- /miniprogram_dev/components/lib.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack:///webpack/bootstrap","webpack:///./src/lib.ts"],"names":[],"mappings":";;QAAA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;;QAEA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;;;QAGA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;QACA,0CAA0C,gCAAgC;QAC1E;QACA;;QAEA;QACA;QACA;QACA,wDAAwD,kBAAkB;QAC1E;QACA,iDAAiD,cAAc;QAC/D;;QAEA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA,yCAAyC,iCAAiC;QAC1E,gHAAgH,mBAAmB,EAAE;QACrI;QACA;;QAEA;QACA;QACA;QACA,2BAA2B,0BAA0B,EAAE;QACvD,iCAAiC,eAAe;QAChD;QACA;QACA;;QAEA;QACA,sDAAsD,+DAA+D;;QAErH;QACA;;;QAGA;QACA;;;;;;;;;;;;kBClFe;AACb,UADa,oBACP;AACJ,eAAO,uCAAP;AACD;AAHY,C","file":"lib.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 2);\n","export default {\r\n printf() {\r\n return 'miniprogram-custom-component api demo'\r\n }\r\n}\r\n"],"sourceRoot":""} -------------------------------------------------------------------------------- /miniprogram_dev/components/reset.wxss: -------------------------------------------------------------------------------- 1 | .reset { 2 | background: white; 3 | } 4 | -------------------------------------------------------------------------------- /miniprogram_dev/components/utils.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | getFlag() { 3 | return true 4 | }, 5 | } 6 | -------------------------------------------------------------------------------- /miniprogram_dev/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": {} 3 | } 4 | -------------------------------------------------------------------------------- /miniprogram_dev/pages/index/config.js: -------------------------------------------------------------------------------- 1 | export const tableHeader = [ 2 | { 3 | prop: 'datetime', 4 | width: 150, 5 | label: '日期', 6 | }, 7 | { 8 | prop: 'sign_in_time', 9 | width: 152, 10 | label: '上班时间' 11 | }, 12 | { 13 | prop: 'sign_out_time', 14 | width: 152, 15 | label: '下班时间' 16 | }, 17 | { 18 | prop: 'work_hour', 19 | width: 110, 20 | label: '工时' 21 | }, 22 | { 23 | prop: 'status', 24 | width: 110, 25 | label: '状态' 26 | 27 | } 28 | ]; 29 | 30 | export const tableHeader2 = [ 31 | { 32 | prop: 'datetime', 33 | width: 150, 34 | label: '日期', 35 | color: '#55C355' 36 | }, 37 | { 38 | prop: 'sign_in_time', 39 | width: 152, 40 | label: '上班时间' 41 | }, 42 | { 43 | prop: 'sign_out_time', 44 | width: 152, 45 | label: '下班时间' 46 | }, 47 | { 48 | prop: 'work_hour', 49 | width: 110, 50 | label: '工时' 51 | }, 52 | { 53 | prop: 'status', 54 | width: 110, 55 | label: '状态' 56 | 57 | }, 58 | { 59 | prop: 'sign_out_time', 60 | width: 200, 61 | label: '下班时间' 62 | }, 63 | { 64 | prop: 'work_hour', 65 | width: 200, 66 | label: '工时' 67 | }, 68 | { 69 | prop: 'status', 70 | width: 200, 71 | label: '状态' 72 | }, 73 | ] 74 | 75 | export const row = [{ 76 | "id": 1, 77 | "status": '正常', 78 | "datetime": "04-01", 79 | "sign_in_time": '09:30:00', 80 | "sign_out_time": '18:30:00', 81 | "work_hour": 8, 82 | }, { 83 | "id": 2, 84 | "status": '迟到', 85 | "datetime": "04-02", 86 | "sign_in_time": '10:30:00', 87 | "sign_out_time": '18:30:00', 88 | "work_hour": 7, 89 | }, { 90 | "id": 29, 91 | "status": '正常', 92 | "datetime": "04-03", 93 | "sign_in_time": '09:30:00', 94 | "sign_out_time": '18:30:00', 95 | "work_hour": 8, 96 | }, { 97 | "id": 318, 98 | "status": '休息日', 99 | "datetime": "04-04", 100 | "sign_in_time": '', 101 | "sign_out_time": '', 102 | "work_hour": '', 103 | }, { 104 | "id": 319, 105 | "status": '正常', 106 | "datetime": "04-05", 107 | "sign_in_time": '09:30:00', 108 | "sign_out_time": '18:30:00', 109 | "work_hour": 8, 110 | }] -------------------------------------------------------------------------------- /miniprogram_dev/pages/index/index.js: -------------------------------------------------------------------------------- 1 | import { tableHeader, tableHeader2, row } from './config.js' 2 | 3 | Page({ 4 | /** 5 | * 页面的初始数据 6 | */ 7 | data: { 8 | month: '', 9 | user_name: '', 10 | tableHeader, 11 | tableHeader2, 12 | stripe: true, 13 | border: true, 14 | outBorder: true, 15 | height: '150px', 16 | row, 17 | row2: [], 18 | msg: '没有打卡记录哦~' 19 | }, 20 | /** 21 | * 生命周期函数--监听页面加载 22 | */ 23 | onLoad: function (options) { 24 | 25 | }, 26 | /** 27 | * 点击表格一行 28 | */ 29 | onRowClick: function(e) { 30 | console.log('e: ', e) 31 | 32 | wx.showToast({ 33 | title: '您点击了这一行:', 34 | icon: 'none' 35 | }) 36 | } 37 | }) 38 | -------------------------------------------------------------------------------- /miniprogram_dev/pages/index/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": { 3 | "table": "../../components/index" 4 | } 5 | } -------------------------------------------------------------------------------- /miniprogram_dev/pages/index/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1.基础表格 4 | 基础的表格展示用例。 5 | 6 | 10 | 11 | 12 | 13 | 14 | 2.带斑马纹表格 15 | 使用带斑马纹的表格,可以更容易区分出不同行的数据。 16 | 17 |
22 | 23 | 24 | 25 | 26 | 3.带间隔边框表格 27 | 28 |
33 | 34 | 35 | 36 | 37 | 4.自定义无数据的提示文案 38 | 表格没有数据的情况,可自定义展示文案。 39 | 40 | 41 |
46 | 47 | 48 | 49 | 50 | 5.自定义表格头样式 51 | 可自定义表格头的样式。 52 | 53 | 54 |
61 | 62 | 63 | 64 | 65 | 6.固定表头 66 | 纵向内容过多时,可选择固定表头。 67 | 68 |
75 | 76 | 77 | 78 | 79 | 7.表格横向滑动 80 | 横向内容过多时,可选择左右滑动。 81 | 82 |
88 | 89 | 90 | 91 | 92 | 8.自定义表格行和单元格样式 93 | 94 | 95 |
100 | 101 | 102 | 103 | 104 | 9.当某一行被点击时会触发该事件 105 | 106 | 107 |
112 | 113 | 114 | 115 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /miniprogram_dev/pages/index/index.wxss: -------------------------------------------------------------------------------- 1 | .container { 2 | padding: 30rpx; 3 | } 4 | .group { 5 | margin-bottom: 60rpx; 6 | } 7 | .group .group-title { 8 | margin-bottom: 30rpx; 9 | font-size: 34rpx; 10 | font-weight: 700; 11 | color: #333; 12 | } 13 | .group .group-explain { 14 | margin-bottom: 20rpx; 15 | font-size: 28rpx; 16 | color: #666; 17 | } 18 | 19 | 20 | .header-class { 21 | border: 1rpx solid #55C355; 22 | background-color: #55C355; 23 | color: #fff!important; 24 | } 25 | .header-class .td:first-child { 26 | color: #55C355; 27 | } 28 | .row-class:nth-child(2n) { 29 | background-color: #c1e4c175; 30 | } 31 | /* .cell-class { 32 | border-right: 1rpx solid #fff!important; 33 | } 34 | .cell-class:last-child { 35 | border-right: none!important; 36 | } */ 37 | 38 | 39 | -------------------------------------------------------------------------------- /miniprogram_dev/project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "项目配置文件。", 3 | "packOptions": { 4 | "ignore": [] 5 | }, 6 | "setting": { 7 | "urlCheck": true, 8 | "es6": true, 9 | "postcss": true, 10 | "minified": true, 11 | "newFeature": true, 12 | "nodeModules": true 13 | }, 14 | "compileType": "miniprogram", 15 | "libVersion": "2.10.4", 16 | "appid": "wxd53c182e8d8edcb0", 17 | "projectname": "miniprogram-demo", 18 | "isGameTourist": false, 19 | "simulatorType": "wechat", 20 | "simulatorPluginLibVersion": {}, 21 | "condition": { 22 | "search": { 23 | "current": -1, 24 | "list": [] 25 | }, 26 | "conversation": { 27 | "current": -1, 28 | "list": [] 29 | }, 30 | "game": { 31 | "currentL": -1, 32 | "list": [] 33 | }, 34 | "miniprogram": { 35 | "current": -1, 36 | "list": [] 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /miniprogram_dev/sitemap.json: -------------------------------------------------------------------------------- 1 | { 2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html", 3 | "rules": [{ 4 | "action": "allow", 5 | "page": "*" 6 | }] 7 | } -------------------------------------------------------------------------------- /miniprogram_dist/index.js: -------------------------------------------------------------------------------- 1 | module.exports = 2 | /******/ (function(modules) { // webpackBootstrap 3 | /******/ // The module cache 4 | /******/ var installedModules = {}; 5 | /******/ 6 | /******/ // The require function 7 | /******/ function __webpack_require__(moduleId) { 8 | /******/ 9 | /******/ // Check if module is in cache 10 | /******/ if(installedModules[moduleId]) { 11 | /******/ return installedModules[moduleId].exports; 12 | /******/ } 13 | /******/ // Create a new module (and put it into the cache) 14 | /******/ var module = installedModules[moduleId] = { 15 | /******/ i: moduleId, 16 | /******/ l: false, 17 | /******/ exports: {} 18 | /******/ }; 19 | /******/ 20 | /******/ // Execute the module function 21 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 22 | /******/ 23 | /******/ // Flag the module as loaded 24 | /******/ module.l = true; 25 | /******/ 26 | /******/ // Return the exports of the module 27 | /******/ return module.exports; 28 | /******/ } 29 | /******/ 30 | /******/ 31 | /******/ // expose the modules object (__webpack_modules__) 32 | /******/ __webpack_require__.m = modules; 33 | /******/ 34 | /******/ // expose the module cache 35 | /******/ __webpack_require__.c = installedModules; 36 | /******/ 37 | /******/ // define getter function for harmony exports 38 | /******/ __webpack_require__.d = function(exports, name, getter) { 39 | /******/ if(!__webpack_require__.o(exports, name)) { 40 | /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); 41 | /******/ } 42 | /******/ }; 43 | /******/ 44 | /******/ // define __esModule on exports 45 | /******/ __webpack_require__.r = function(exports) { 46 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 47 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 48 | /******/ } 49 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 50 | /******/ }; 51 | /******/ 52 | /******/ // create a fake namespace object 53 | /******/ // mode & 1: value is a module id, require it 54 | /******/ // mode & 2: merge all properties of value into the ns 55 | /******/ // mode & 4: return value when already ns object 56 | /******/ // mode & 8|1: behave like require 57 | /******/ __webpack_require__.t = function(value, mode) { 58 | /******/ if(mode & 1) value = __webpack_require__(value); 59 | /******/ if(mode & 8) return value; 60 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 61 | /******/ var ns = Object.create(null); 62 | /******/ __webpack_require__.r(ns); 63 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 64 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 65 | /******/ return ns; 66 | /******/ }; 67 | /******/ 68 | /******/ // getDefaultExport function for compatibility with non-harmony modules 69 | /******/ __webpack_require__.n = function(module) { 70 | /******/ var getter = module && module.__esModule ? 71 | /******/ function getDefault() { return module['default']; } : 72 | /******/ function getModuleExports() { return module; }; 73 | /******/ __webpack_require__.d(getter, 'a', getter); 74 | /******/ return getter; 75 | /******/ }; 76 | /******/ 77 | /******/ // Object.prototype.hasOwnProperty.call 78 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 79 | /******/ 80 | /******/ // __webpack_public_path__ 81 | /******/ __webpack_require__.p = ""; 82 | /******/ 83 | /******/ 84 | /******/ // Load entry module and return exports 85 | /******/ return __webpack_require__(__webpack_require__.s = 0); 86 | /******/ }) 87 | /************************************************************************/ 88 | /******/ ([ 89 | /* 0 */ 90 | /***/ (function(module, exports, __webpack_require__) { 91 | 92 | "use strict"; 93 | 94 | 95 | Component({ 96 | /** 97 | * 外部样式类 98 | */ 99 | externalClasses: ['header-row-class-name', 'row-class-name', 'cell-class-name'], 100 | 101 | /** 102 | * 组件样式隔离 103 | */ 104 | options: { 105 | styleIsolation: "isolated", 106 | multipleSlots: true // 支持多个slot 107 | }, 108 | 109 | /** 110 | * 组件的属性列表 111 | */ 112 | properties: { 113 | data: { 114 | type: Array, 115 | value: [] 116 | }, 117 | headers: { 118 | type: Array, 119 | value: [] 120 | }, 121 | // table的高度, 溢出可滚动 122 | height: { 123 | type: String, 124 | value: 'auto' 125 | }, 126 | width: { 127 | type: Number || String, 128 | value: '100%' 129 | }, 130 | // 单元格的宽度 131 | tdWidth: { 132 | type: Number, 133 | value: 35 134 | }, 135 | // 固定表头 thead达到Header的位置时就应该被fixed了 136 | offsetTop: { 137 | type: Number, 138 | value: 150 139 | }, 140 | // 是否带有纵向边框 141 | stripe: { 142 | type: Boolean, 143 | value: false 144 | }, 145 | // 是否带有纵向边框 146 | border: { 147 | type: Boolean, 148 | value: false 149 | }, 150 | msg: { 151 | type: String, 152 | value: '暂无数据~' 153 | } 154 | }, 155 | 156 | /** 157 | * 组件的初始数据 158 | */ 159 | data: { 160 | scrolWidth: '100%' 161 | }, 162 | 163 | /** 164 | * 组件的监听属性 165 | */ 166 | observers: { 167 | // 在 numberA 或者 numberB 被设置时,执行这个函数 168 | 'headers': function headers(_headers) { 169 | var reducer = function reducer(accumulator, currentValue) { 170 | return accumulator + Number(currentValue.width); 171 | }; 172 | var scrolWidth = _headers.reduce(reducer, 0); 173 | 174 | this.setData({ 175 | scrolWidth: scrolWidth 176 | }); 177 | } 178 | }, 179 | 180 | /** 181 | * 组件的方法列表 182 | */ 183 | methods: { 184 | onRowClick: function onRowClick(e) { 185 | this.triggerEvent('rowClick', e, e.currentTarget.dataset.it); 186 | } 187 | } 188 | }); 189 | 190 | /***/ }) 191 | /******/ ]); 192 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /miniprogram_dist/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack:///webpack/bootstrap","webpack:///./src/index.js"],"names":["Component","externalClasses","options","styleIsolation","multipleSlots","properties","data","type","Array","value","headers","height","String","width","Number","tdWidth","offsetTop","stripe","Boolean","border","msg","scrolWidth","observers","reducer","accumulator","currentValue","reduce","setData","methods","onRowClick","e","triggerEvent","currentTarget","dataset","it"],"mappings":";;QAAA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;;QAEA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;;;QAGA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;QACA,0CAA0C,gCAAgC;QAC1E;QACA;;QAEA;QACA;QACA;QACA,wDAAwD,kBAAkB;QAC1E;QACA,iDAAiD,cAAc;QAC/D;;QAEA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA,yCAAyC,iCAAiC;QAC1E,gHAAgH,mBAAmB,EAAE;QACrI;QACA;;QAEA;QACA;QACA;QACA,2BAA2B,0BAA0B,EAAE;QACvD,iCAAiC,eAAe;QAChD;QACA;QACA;;QAEA;QACA,sDAAsD,+DAA+D;;QAErH;QACA;;;QAGA;QACA;;;;;;;;;;AClFAA,UAAU;AACR;;;AAGAC,mBAAiB,CAAC,uBAAD,EAA0B,gBAA1B,EAA4C,iBAA5C,CAJT;;AAMR;;;AAGAC,WAAS;AACPC,oBAAgB,UADT;AAEPC,mBAAe,IAFR,CAEc;AAFd,GATD;;AAcR;;;AAGAC,cAAY;AACVC,UAAM;AACJC,YAAMC,KADF;AAEJC,aAAO;AAFH,KADI;AAKVC,aAAS;AACPH,YAAMC,KADC;AAEPC,aAAO;AAFA,KALC;AASV;AACAE,YAAQ;AACNJ,YAAMK,MADA;AAENH,aAAO;AAFD,KAVE;AAcVI,WAAO;AACLN,YAAMO,UAAUF,MADX;AAELH,aAAO;AAFF,KAdG;AAkBV;AACAM,aAAS;AACPR,YAAMO,MADC;AAEPL,aAAO;AAFA,KAnBC;AAuBV;AACAO,eAAW;AACTT,YAAMO,MADG;AAETL,aAAO;AAFE,KAxBD;AA4BV;AACAQ,YAAQ;AACNV,YAAMW,OADA;AAENT,aAAO;AAFD,KA7BE;AAiCV;AACAU,YAAQ;AACNZ,YAAMW,OADA;AAENT,aAAO;AAFD,KAlCE;AAsCVW,SAAK;AACHb,YAAMK,MADH;AAEHH,aAAO;AAFJ;AAtCK,GAjBJ;;AA6DR;;;AAGAH,QAAM;AACJe,gBAAY;AADR,GAhEE;;AAoER;;;AAGAC,aAAW;AACT;AACA,eAAW,iBAAUZ,QAAV,EAAmB;AAC5B,UAAMa,UAAU,SAAVA,OAAU,CAACC,WAAD,EAAcC,YAAd,EAA+B;AAC7C,eAAOD,cAAcV,OAAOW,aAAaZ,KAApB,CAArB;AACD,OAFD;AAGA,UAAMQ,aAAaX,SAAQgB,MAAR,CAAeH,OAAf,EAAwB,CAAxB,CAAnB;;AAEA,WAAKI,OAAL,CAAa;AACXN,oBAAYA;AADD,OAAb;AAGD;AAXQ,GAvEH;;AAqFR;;;AAGAO,WAAS;AACPC,cADO,sBACIC,CADJ,EACO;AACZ,WAAKC,YAAL,CAAkB,UAAlB,EAA8BD,CAA9B,EAAiCA,EAAEE,aAAF,CAAgBC,OAAhB,CAAwBC,EAAzD;AACD;AAHM;AAxFD,CAAV,E","file":"index.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n","Component({\n /**\n * 外部样式类\n */\n externalClasses: ['header-row-class-name', 'row-class-name', 'cell-class-name'], \n\n /**\n * 组件样式隔离\n */\n options: {\n styleIsolation: \"isolated\", \n multipleSlots: true, // 支持多个slot\n },\n\n /**\n * 组件的属性列表\n */\n properties: {\n data: {\n type: Array,\n value: []\n },\n headers: {\n type: Array,\n value: []\n },\n // table的高度, 溢出可滚动\n height: { \n type: String,\n value: 'auto'\n },\n width: {\n type: Number || String,\n value: '100%'\n },\n // 单元格的宽度\n tdWidth: {\n type: Number,\n value: 35\n },\n // 固定表头 thead达到Header的位置时就应该被fixed了\n offsetTop: {\n type: Number,\n value: 150\n },\n // 是否带有纵向边框\n stripe: {\n type: Boolean,\n value: false\n },\n // 是否带有纵向边框\n border: {\n type: Boolean,\n value: false\n }, \n msg: {\n type: String,\n value: '暂无数据~'\n }\n },\n\n /**\n * 组件的初始数据\n */\n data: {\n scrolWidth: '100%'\n },\n\n /**\n * 组件的监听属性\n */\n observers: {\n // 在 numberA 或者 numberB 被设置时,执行这个函数\n 'headers': function (headers) {\n const reducer = (accumulator, currentValue) => {\n return accumulator + Number(currentValue.width)\n };\n const scrolWidth = headers.reduce(reducer, 0)\n\n this.setData({\n scrolWidth: scrolWidth\n })\n }\n },\n\n /**\n * 组件的方法列表\n */\n methods: {\n onRowClick(e) {\n this.triggerEvent('rowClick', e, e.currentTarget.dataset.it)\n },\n }\n})"],"sourceRoot":""} -------------------------------------------------------------------------------- /miniprogram_dist/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {}, 4 | "componentGenerics": { 5 | "genericsTest": true 6 | } 7 | } -------------------------------------------------------------------------------- /miniprogram_dist/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 13 | {{ item.label }} 14 | 15 | 16 | 17 | 18 | 19 | 24 | 31 | 32 | 42 | {{it[head["prop"]]}} 43 | 44 | 45 | 46 | 47 | 48 | {{ msg }} 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /miniprogram_dist/index.wxss: -------------------------------------------------------------------------------- 1 | .table { 2 | position: relative; 3 | font-size: 28rpx; 4 | background: #fff; 5 | border-right:none; 6 | border-radius: 8rpx; 7 | overflow: hidden; 8 | } 9 | .thead{ 10 | border-bottom: none; 11 | display: flex; 12 | justify-content: flex-start; 13 | border-top-right-radius: 8rpx; 14 | border-top-left-radius: 8rpx; 15 | overflow: visible; 16 | color: #909399; 17 | border: 1px solid #ebeef5; 18 | box-sizing: border-box; 19 | } 20 | .thead .td { 21 | padding: 20rpx 10rpx; 22 | font-weight: bold; 23 | display: inline-block; 24 | text-align: center; 25 | border-right: 1rpx solid #fff; 26 | } 27 | .thead .td:last-child { 28 | border-right: none; 29 | } 30 | .thead-border .td { 31 | border-right: 1rpx solid #ebeef5; 32 | } 33 | .thead-border .td:last-child { 34 | border-right: none; 35 | } 36 | /* .tr{ 37 | display: flex; 38 | white-space:nowrap; 39 | } */ 40 | .tbody { 41 | box-sizing: border-box; 42 | font-size: 28rpx; 43 | color: #666; 44 | border: 1px solid #ebeef5; 45 | border-top: none; 46 | border-bottom-left-radius: 8rpx; 47 | border-bottom-right-radius: 8rpx; 48 | } 49 | .tbody-tr { 50 | display: flex; 51 | border-bottom: 1px solid #ebeef5; 52 | } 53 | .tbody-tr:last-child { 54 | border-bottom-left-radius: 8rpx; 55 | border-bottom-right-radius: 8rpx; 56 | } 57 | 58 | .tbody-tr-stripe { 59 | background: #fff; 60 | border-bottom: none; 61 | } 62 | .tbody-tr-stripe:nth-child(2n) { 63 | background: #F6F6F6; 64 | } 65 | .tbody-tr .td { 66 | white-space: wrap; 67 | padding:20rpx 10rpx; 68 | text-align: center; 69 | } 70 | 71 | .tbody-tr-border .td { 72 | border-right: 1rpx solid #F6F6F6; 73 | } 74 | .tbody-tr-border .td:last-child { 75 | border-right: none; 76 | } 77 | .no-data { 78 | display: flex; 79 | padding: 50rpx; 80 | color: #666; 81 | justify-content: center; 82 | } -------------------------------------------------------------------------------- /miniprogram_dist/lib.js: -------------------------------------------------------------------------------- 1 | module.exports = 2 | /******/ (function(modules) { // webpackBootstrap 3 | /******/ // The module cache 4 | /******/ var installedModules = {}; 5 | /******/ 6 | /******/ // The require function 7 | /******/ function __webpack_require__(moduleId) { 8 | /******/ 9 | /******/ // Check if module is in cache 10 | /******/ if(installedModules[moduleId]) { 11 | /******/ return installedModules[moduleId].exports; 12 | /******/ } 13 | /******/ // Create a new module (and put it into the cache) 14 | /******/ var module = installedModules[moduleId] = { 15 | /******/ i: moduleId, 16 | /******/ l: false, 17 | /******/ exports: {} 18 | /******/ }; 19 | /******/ 20 | /******/ // Execute the module function 21 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 22 | /******/ 23 | /******/ // Flag the module as loaded 24 | /******/ module.l = true; 25 | /******/ 26 | /******/ // Return the exports of the module 27 | /******/ return module.exports; 28 | /******/ } 29 | /******/ 30 | /******/ 31 | /******/ // expose the modules object (__webpack_modules__) 32 | /******/ __webpack_require__.m = modules; 33 | /******/ 34 | /******/ // expose the module cache 35 | /******/ __webpack_require__.c = installedModules; 36 | /******/ 37 | /******/ // define getter function for harmony exports 38 | /******/ __webpack_require__.d = function(exports, name, getter) { 39 | /******/ if(!__webpack_require__.o(exports, name)) { 40 | /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); 41 | /******/ } 42 | /******/ }; 43 | /******/ 44 | /******/ // define __esModule on exports 45 | /******/ __webpack_require__.r = function(exports) { 46 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 47 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 48 | /******/ } 49 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 50 | /******/ }; 51 | /******/ 52 | /******/ // create a fake namespace object 53 | /******/ // mode & 1: value is a module id, require it 54 | /******/ // mode & 2: merge all properties of value into the ns 55 | /******/ // mode & 4: return value when already ns object 56 | /******/ // mode & 8|1: behave like require 57 | /******/ __webpack_require__.t = function(value, mode) { 58 | /******/ if(mode & 1) value = __webpack_require__(value); 59 | /******/ if(mode & 8) return value; 60 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 61 | /******/ var ns = Object.create(null); 62 | /******/ __webpack_require__.r(ns); 63 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 64 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 65 | /******/ return ns; 66 | /******/ }; 67 | /******/ 68 | /******/ // getDefaultExport function for compatibility with non-harmony modules 69 | /******/ __webpack_require__.n = function(module) { 70 | /******/ var getter = module && module.__esModule ? 71 | /******/ function getDefault() { return module['default']; } : 72 | /******/ function getModuleExports() { return module; }; 73 | /******/ __webpack_require__.d(getter, 'a', getter); 74 | /******/ return getter; 75 | /******/ }; 76 | /******/ 77 | /******/ // Object.prototype.hasOwnProperty.call 78 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 79 | /******/ 80 | /******/ // __webpack_public_path__ 81 | /******/ __webpack_require__.p = ""; 82 | /******/ 83 | /******/ 84 | /******/ // Load entry module and return exports 85 | /******/ return __webpack_require__(__webpack_require__.s = 1); 86 | /******/ }) 87 | /************************************************************************/ 88 | /******/ ([ 89 | /* 0 */, 90 | /* 1 */ 91 | /***/ (function(module, exports, __webpack_require__) { 92 | 93 | "use strict"; 94 | 95 | 96 | exports.__esModule = true; 97 | exports.default = { 98 | printf: function printf() { 99 | return 'miniprogram-custom-component api demo'; 100 | } 101 | }; 102 | 103 | /***/ }) 104 | /******/ ]); 105 | //# sourceMappingURL=lib.js.map -------------------------------------------------------------------------------- /miniprogram_dist/lib.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack:///webpack/bootstrap","webpack:///./src/lib.ts"],"names":[],"mappings":";;QAAA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;;QAEA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;;;QAGA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;QACA,0CAA0C,gCAAgC;QAC1E;QACA;;QAEA;QACA;QACA;QACA,wDAAwD,kBAAkB;QAC1E;QACA,iDAAiD,cAAc;QAC/D;;QAEA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA,yCAAyC,iCAAiC;QAC1E,gHAAgH,mBAAmB,EAAE;QACrI;QACA;;QAEA;QACA;QACA;QACA,2BAA2B,0BAA0B,EAAE;QACvD,iCAAiC,eAAe;QAChD;QACA;QACA;;QAEA;QACA,sDAAsD,+DAA+D;;QAErH;QACA;;;QAGA;QACA;;;;;;;;;;;;kBClFe;AACb,UADa,oBACP;AACJ,eAAO,uCAAP;AACD;AAHY,C","file":"lib.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 1);\n","export default {\r\n printf() {\r\n return 'miniprogram-custom-component api demo'\r\n }\r\n}\r\n"],"sourceRoot":""} -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "miniprogram-table-component", 3 | "version": "1.1.0", 4 | "description": "", 5 | "main": "miniprogram_dist/index.js", 6 | "scripts": { 7 | "dev": "gulp dev --develop", 8 | "watch": "gulp watch --develop --watch", 9 | "build": "gulp", 10 | "dist": "npm run build", 11 | "clean-dev": "gulp clean --develop", 12 | "clean": "gulp clean", 13 | "test": "jest --bail", 14 | "test-debug": "node --inspect-brk ./node_modules/jest/bin/jest.js --runInBand --bail", 15 | "coverage": "jest ./test/* --coverage --bail", 16 | "lint": "eslint \"src/**/*.js\" --fix", 17 | "lint-tools": "eslint \"tools/**/*.js\" --rule \"import/no-extraneous-dependencies: false\" --fix" 18 | }, 19 | "miniprogram": "miniprogram_dist", 20 | "jest": { 21 | "testEnvironment": "jsdom", 22 | "testURL": "https://jest.test", 23 | "collectCoverageFrom": [ 24 | "miniprogram_dist/**/*.js" 25 | ], 26 | "moduleDirectories": [ 27 | "node_modules", 28 | "miniprogram_dist" 29 | ] 30 | }, 31 | "repository": { 32 | "type": "git", 33 | "url": "https://github.com/habc0807/miniprogram-table-component" 34 | }, 35 | "author": "wechat-miniprogram", 36 | "license": "MIT", 37 | "devDependencies": { 38 | "@typescript-eslint/eslint-plugin": "^2.28.0", 39 | "@typescript-eslint/parser": "^2.28.0", 40 | "babel-core": "^6.26.3", 41 | "babel-loader": "^7.1.5", 42 | "babel-plugin-module-resolver": "^3.2.0", 43 | "babel-preset-env": "^1.7.0", 44 | "colors": "^1.3.1", 45 | "eslint": "^5.14.1", 46 | "eslint-config-airbnb-base": "13.1.0", 47 | "eslint-loader": "^2.1.2", 48 | "eslint-plugin-import": "^2.16.0", 49 | "eslint-plugin-node": "^7.0.1", 50 | "eslint-plugin-promise": "^3.8.0", 51 | "gulp": "^4.0.0", 52 | "gulp-clean": "^0.4.0", 53 | "gulp-if": "^2.0.2", 54 | "gulp-install": "^1.1.0", 55 | "gulp-less": "^4.0.1", 56 | "gulp-rename": "^1.4.0", 57 | "gulp-sourcemaps": "^2.6.5", 58 | "jest": "^23.5.0", 59 | "miniprogram-api-typings": "^2.10.3-1", 60 | "miniprogram-simulate": "^1.2.0", 61 | "thread-loader": "^2.1.3", 62 | "through2": "^2.0.3", 63 | "ts-loader": "^7.0.0", 64 | "typescript": "^3.8.3", 65 | "vinyl": "^2.2.0", 66 | "webpack": "^4.29.5", 67 | "webpack-node-externals": "^1.7.2" 68 | }, 69 | "dependencies": {} 70 | } 71 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | Component({ 2 | /** 3 | * 外部样式类 4 | */ 5 | externalClasses: ['header-row-class-name', 'row-class-name', 'cell-class-name'], 6 | 7 | /** 8 | * 组件样式隔离 9 | */ 10 | options: { 11 | styleIsolation: "isolated", 12 | multipleSlots: true, // 支持多个slot 13 | }, 14 | 15 | /** 16 | * 组件的属性列表 17 | */ 18 | properties: { 19 | data: { 20 | type: Array, 21 | value: [] 22 | }, 23 | headers: { 24 | type: Array, 25 | value: [] 26 | }, 27 | // table的高度, 溢出可滚动 28 | height: { 29 | type: String, 30 | value: 'auto' 31 | }, 32 | width: { 33 | type: Number || String, 34 | value: '100%' 35 | }, 36 | // 单元格的宽度 37 | tdWidth: { 38 | type: Number, 39 | value: 35 40 | }, 41 | // 固定表头 thead达到Header的位置时就应该被fixed了 42 | offsetTop: { 43 | type: Number, 44 | value: 150 45 | }, 46 | // 是否带有纵向边框 47 | stripe: { 48 | type: Boolean, 49 | value: false 50 | }, 51 | // 是否带有纵向边框 52 | border: { 53 | type: Boolean, 54 | value: false 55 | }, 56 | msg: { 57 | type: String, 58 | value: '暂无数据~' 59 | } 60 | }, 61 | 62 | /** 63 | * 组件的初始数据 64 | */ 65 | data: { 66 | scrolWidth: '100%' 67 | }, 68 | 69 | /** 70 | * 组件的监听属性 71 | */ 72 | observers: { 73 | // 在 numberA 或者 numberB 被设置时,执行这个函数 74 | 'headers': function (headers) { 75 | const reducer = (accumulator, currentValue) => { 76 | return accumulator + Number(currentValue.width) 77 | }; 78 | const scrolWidth = headers.reduce(reducer, 0) 79 | 80 | this.setData({ 81 | scrolWidth: scrolWidth 82 | }) 83 | } 84 | }, 85 | 86 | /** 87 | * 组件的方法列表 88 | */ 89 | methods: { 90 | onRowClick(e) { 91 | this.triggerEvent('rowClick', e, e.currentTarget.dataset.it) 92 | }, 93 | } 94 | }) -------------------------------------------------------------------------------- /src/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {}, 4 | "componentGenerics": { 5 | "genericsTest": true 6 | } 7 | } -------------------------------------------------------------------------------- /src/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 13 | {{ item.label }} 14 | 15 | 16 | 17 | 18 | 19 | 24 | 31 | 32 | 42 | {{it[head["prop"]]}} 43 | 44 | 45 | 46 | 47 | 48 | {{ msg }} 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /src/index.wxss: -------------------------------------------------------------------------------- 1 | .table { 2 | position: relative; 3 | font-size: 28rpx; 4 | background: #fff; 5 | border-right:none; 6 | border-radius: 8rpx; 7 | overflow: hidden; 8 | } 9 | .thead{ 10 | border-bottom: none; 11 | display: flex; 12 | justify-content: flex-start; 13 | border-top-right-radius: 8rpx; 14 | border-top-left-radius: 8rpx; 15 | overflow: visible; 16 | color: #909399; 17 | border: 1px solid #ebeef5; 18 | box-sizing: border-box; 19 | } 20 | .thead .td { 21 | padding: 20rpx 10rpx; 22 | font-weight: bold; 23 | display: inline-block; 24 | text-align: center; 25 | border-right: 1rpx solid #fff; 26 | } 27 | .thead .td:last-child { 28 | border-right: none; 29 | } 30 | .thead-border .td { 31 | border-right: 1rpx solid #ebeef5; 32 | } 33 | .thead-border .td:last-child { 34 | border-right: none; 35 | } 36 | /* .tr{ 37 | display: flex; 38 | white-space:nowrap; 39 | } */ 40 | .tbody { 41 | box-sizing: border-box; 42 | font-size: 28rpx; 43 | color: #666; 44 | border: 1px solid #ebeef5; 45 | border-top: none; 46 | border-bottom-left-radius: 8rpx; 47 | border-bottom-right-radius: 8rpx; 48 | } 49 | .tbody-tr { 50 | display: flex; 51 | border-bottom: 1px solid #ebeef5; 52 | } 53 | .tbody-tr:last-child { 54 | border-bottom-left-radius: 8rpx; 55 | border-bottom-right-radius: 8rpx; 56 | } 57 | 58 | .tbody-tr-stripe { 59 | background: #fff; 60 | border-bottom: none; 61 | } 62 | .tbody-tr-stripe:nth-child(2n) { 63 | background: #F6F6F6; 64 | } 65 | .tbody-tr .td { 66 | white-space: wrap; 67 | padding:20rpx 10rpx; 68 | text-align: center; 69 | } 70 | 71 | .tbody-tr-border .td { 72 | border-right: 1rpx solid #F6F6F6; 73 | } 74 | .tbody-tr-border .td:last-child { 75 | border-right: none; 76 | } 77 | .no-data { 78 | display: flex; 79 | padding: 50rpx; 80 | color: #666; 81 | justify-content: center; 82 | } -------------------------------------------------------------------------------- /src/lib.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | printf() { 3 | return 'miniprogram-custom-component api demo' 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/index.test.js: -------------------------------------------------------------------------------- 1 | const _ = require('./utils') 2 | 3 | test('render', async () => { 4 | const componentId = _.load('index', 'comp') 5 | const component = _.render(componentId, {prop: 'index.test.properties'}) 6 | 7 | const parent = document.createElement('parent-wrapper') 8 | component.attach(parent) 9 | 10 | expect(_.match(component.dom, 'index.test.properties-falseother.properties-other')).toBe(true) 11 | 12 | await _.sleep(10) 13 | 14 | expect(_.match(component.dom, 'index.test.properties-trueother.properties-other')).toBe(true) 15 | }) 16 | -------------------------------------------------------------------------------- /test/utils.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const simulate = require('miniprogram-simulate') 4 | const config = require('../tools/config') 5 | 6 | // const dir = config.srcPath // 使用源码进行测试,对于 debug 和代码覆盖率检测会比较友好 7 | const dir = config.distPath // 使用构建后代码进行测试,如果使用了 typescript 进行开发,必须选择此目录 8 | 9 | try { 10 | fs.accessSync(dir) 11 | } catch (err) { 12 | console.error('请先执行 npm run build 再进行单元测试!!!') 13 | } 14 | 15 | const oldLoad = simulate.load 16 | simulate.load = function (componentPath, ...args) { 17 | if (typeof componentPath === 'string') componentPath = path.join(dir, componentPath) 18 | return oldLoad(componentPath, ...args) 19 | } 20 | 21 | module.exports = simulate 22 | 23 | // adjust the simulated wx api 24 | const oldGetSystemInfoSync = global.wx.getSystemInfoSync 25 | global.wx.getSystemInfoSync = function() { 26 | const res = oldGetSystemInfoSync() 27 | res.SDKVersion = '2.4.1' 28 | 29 | return res 30 | } 31 | -------------------------------------------------------------------------------- /test/wx.test.js: -------------------------------------------------------------------------------- 1 | const _ = require('./utils') 2 | 3 | test('wx.getSystemInfo', async () => { 4 | wx.getSystemInfo({ 5 | success(res) { 6 | expect(res.errMsg).toBe('getSystemInfo:ok') 7 | }, 8 | complete(res) { 9 | expect(res.errMsg).toBe('getSystemInfo:ok') 10 | }, 11 | }) 12 | }) 13 | 14 | test('wx.getSystemInfoSync', async () => { 15 | const info = wx.getSystemInfoSync() 16 | expect(info.SDKVersion).toBe('2.4.1') 17 | expect(info.version).toBe('6.6.3') 18 | }) 19 | -------------------------------------------------------------------------------- /tools/build.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const fs = require('fs') 3 | 4 | const gulp = require('gulp') 5 | const clean = require('gulp-clean') 6 | const less = require('gulp-less') 7 | const rename = require('gulp-rename') 8 | const gulpif = require('gulp-if') 9 | const sourcemaps = require('gulp-sourcemaps') 10 | const webpack = require('webpack') 11 | const gulpInstall = require('gulp-install') 12 | 13 | const config = require('./config') 14 | const checkComponents = require('./checkcomponents') 15 | const checkWxss = require('./checkwxss') 16 | const _ = require('./utils') 17 | 18 | const jsConfig = config.js || {} 19 | const wxssConfig = config.wxss || {} 20 | const srcPath = config.srcPath 21 | const distPath = config.distPath 22 | 23 | /** 24 | * 获取 wxss 流 25 | */ 26 | function wxss(wxssFileList) { 27 | if (!wxssFileList.length) return false 28 | 29 | return gulp.src(wxssFileList, {cwd: srcPath, base: srcPath}) 30 | .pipe(checkWxss.start()) // 开始处理 import 31 | .pipe(gulpif(wxssConfig.less && wxssConfig.sourcemap, sourcemaps.init())) 32 | .pipe(gulpif(wxssConfig.less, less({paths: [srcPath]}))) 33 | .pipe(checkWxss.end()) // 结束处理 import 34 | .pipe(rename({extname: '.wxss'})) 35 | .pipe(gulpif(wxssConfig.less && wxssConfig.sourcemap, sourcemaps.write('./'))) 36 | .pipe(_.logger(wxssConfig.less ? 'generate' : undefined)) 37 | .pipe(gulp.dest(distPath)) 38 | } 39 | 40 | /** 41 | * 获取 js 流 42 | */ 43 | function js(jsFileMap, scope) { 44 | const webpackConfig = config.webpack 45 | const webpackCallback = (err, stats) => { 46 | if (!err) { 47 | // eslint-disable-next-line no-console 48 | console.log(stats.toString({ 49 | assets: true, 50 | cached: false, 51 | colors: true, 52 | children: false, 53 | errors: true, 54 | warnings: true, 55 | version: true, 56 | modules: false, 57 | publicPath: true, 58 | })) 59 | } else { 60 | // eslint-disable-next-line no-console 61 | console.log(err) 62 | } 63 | } 64 | 65 | webpackConfig.entry = jsFileMap 66 | webpackConfig.output.path = distPath 67 | 68 | if (scope.webpackWatcher) { 69 | scope.webpackWatcher.close() 70 | scope.webpackWatcher = null 71 | } 72 | 73 | if (config.isWatch) { 74 | scope.webpackWatcher = webpack(webpackConfig).watch({ 75 | ignored: /node_modules/, 76 | }, webpackCallback) 77 | } else { 78 | webpack(webpackConfig).run(webpackCallback) 79 | } 80 | } 81 | 82 | /** 83 | * 拷贝文件 84 | */ 85 | function copy(copyFileList) { 86 | if (!copyFileList.length) return false 87 | 88 | return gulp.src(copyFileList, {cwd: srcPath, base: srcPath}) 89 | .pipe(_.logger()) 90 | .pipe(gulp.dest(distPath)) 91 | } 92 | 93 | /** 94 | * 安装依赖包 95 | */ 96 | function install() { 97 | return gulp.series(async () => { 98 | const demoDist = config.demoDist 99 | const demoPackageJsonPath = path.join(demoDist, 'package.json') 100 | const packageJson = _.readJson(path.resolve(__dirname, '../package.json')) 101 | const dependencies = packageJson.dependencies || {} 102 | 103 | await _.writeFile(demoPackageJsonPath, JSON.stringify({dependencies}, null, '\t')) // write dev demo's package.json 104 | }, () => { 105 | const demoDist = config.demoDist 106 | const demoPackageJsonPath = path.join(demoDist, 'package.json') 107 | 108 | return gulp.src(demoPackageJsonPath) 109 | .pipe(gulpInstall({production: true})) 110 | }) 111 | } 112 | 113 | class BuildTask { 114 | constructor(id, entry) { 115 | if (!entry) return 116 | 117 | this.id = id 118 | this.entries = Array.isArray(config.entry) ? config.entry : [config.entry] 119 | this.copyList = Array.isArray(config.copy) ? config.copy : [] 120 | this.componentListMap = {} 121 | this.cachedComponentListMap = {} 122 | 123 | this.init() 124 | } 125 | 126 | init() { 127 | const id = this.id 128 | 129 | /** 130 | * 清空目标目录 131 | */ 132 | gulp.task(`${id}-clean-dist`, () => gulp.src(distPath, {read: false, allowEmpty: true}).pipe(clean())) 133 | 134 | /** 135 | * 拷贝 demo 到目标目录 136 | */ 137 | let isDemoExists = false 138 | gulp.task(`${id}-demo`, gulp.series(async () => { 139 | const demoDist = config.demoDist 140 | 141 | isDemoExists = await _.checkFileExists(path.join(demoDist, 'project.config.json')) 142 | }, done => { 143 | if (!isDemoExists) { 144 | const demoSrc = config.demoSrc 145 | const demoDist = config.demoDist 146 | 147 | return gulp.src('**/*', {cwd: demoSrc, base: demoSrc}) 148 | .pipe(gulp.dest(demoDist)) 149 | } 150 | 151 | return done() 152 | })) 153 | 154 | /** 155 | * 安装依赖包 156 | */ 157 | gulp.task(`${id}-install`, install()) 158 | 159 | /** 160 | * 检查自定义组件 161 | */ 162 | gulp.task(`${id}-component-check`, async () => { 163 | const entries = this.entries 164 | const mergeComponentListMap = {} 165 | for (let i = 0, len = entries.length; i < len; i++) { 166 | let entry = entries[i] 167 | entry = path.join(srcPath, `${entry}.json`) 168 | const newComponentListMap = await checkComponents(entry) 169 | 170 | _.merge(mergeComponentListMap, newComponentListMap) 171 | } 172 | 173 | this.cachedComponentListMap = this.componentListMap 174 | this.componentListMap = mergeComponentListMap 175 | }) 176 | 177 | /** 178 | * 写 json 文件到目标目录 179 | */ 180 | gulp.task(`${id}-component-json`, done => { 181 | const jsonFileList = this.componentListMap.jsonFileList 182 | 183 | if (jsonFileList && jsonFileList.length) { 184 | return copy(this.componentListMap.jsonFileList) 185 | } 186 | 187 | return done() 188 | }) 189 | 190 | /** 191 | * 拷贝 wxml 文件到目标目录 192 | */ 193 | gulp.task(`${id}-component-wxml`, done => { 194 | const wxmlFileList = this.componentListMap.wxmlFileList 195 | 196 | if (wxmlFileList && 197 | wxmlFileList.length && 198 | !_.compareArray(this.cachedComponentListMap.wxmlFileList, wxmlFileList)) { 199 | return copy(wxmlFileList) 200 | } 201 | 202 | return done() 203 | }) 204 | 205 | /** 206 | * 生成 wxss 文件到目标目录 207 | */ 208 | gulp.task(`${id}-component-wxss`, done => { 209 | const wxssFileList = this.componentListMap.wxssFileList 210 | 211 | if (wxssFileList && 212 | wxssFileList.length && 213 | !_.compareArray(this.cachedComponentListMap.wxssFileList, wxssFileList)) { 214 | return wxss(wxssFileList, srcPath, distPath) 215 | } 216 | 217 | return done() 218 | }) 219 | 220 | /** 221 | * 生成 js 文件到目标目录 222 | */ 223 | gulp.task(`${id}-component-js`, done => { 224 | const jsFileList = this.componentListMap.jsFileList 225 | 226 | if (jsFileList && 227 | jsFileList.length && 228 | !_.compareArray(this.cachedComponentListMap.jsFileList, jsFileList)) { 229 | if (jsConfig.webpack) { 230 | js(this.componentListMap.jsFileMap, this) 231 | } else { 232 | return copy(jsFileList) 233 | } 234 | } 235 | 236 | return done() 237 | }) 238 | 239 | /** 240 | * 拷贝相关资源到目标目录 241 | */ 242 | gulp.task(`${id}-copy`, gulp.parallel(done => { 243 | const copyList = this.copyList 244 | const copyFileList = copyList.map(copyFilePath => { 245 | try { 246 | if (fs.statSync(path.join(srcPath, copyFilePath)).isDirectory()) { 247 | return path.join(copyFilePath, '**/*.!(wxss)') 248 | } else { 249 | return copyFilePath 250 | } 251 | } catch (err) { 252 | // eslint-disable-next-line no-console 253 | console.error(err) 254 | return null 255 | } 256 | }).filter(copyFilePath => !!copyFilePath) 257 | 258 | if (copyFileList.length) return copy(copyFileList) 259 | 260 | return done() 261 | }, done => { 262 | const copyList = this.copyList 263 | const copyFileList = copyList.map(copyFilePath => { 264 | try { 265 | if (fs.statSync(path.join(srcPath, copyFilePath)).isDirectory()) { 266 | return path.join(copyFilePath, '**/*.wxss') 267 | } else if (copyFilePath.slice(-5) === '.wxss') { 268 | return copyFilePath 269 | } else { 270 | return null 271 | } 272 | } catch (err) { 273 | // eslint-disable-next-line no-console 274 | console.error(err) 275 | return null 276 | } 277 | }).filter(copyFilePath => !!copyFilePath) 278 | 279 | if (copyFileList.length) return wxss(copyFileList, srcPath, distPath) 280 | 281 | return done() 282 | })) 283 | 284 | /** 285 | * 监听 js 变化 286 | */ 287 | gulp.task(`${id}-watch-js`, done => { 288 | if (!jsConfig.webpack) { 289 | return gulp.watch(this.componentListMap.jsFileList, {cwd: srcPath, base: srcPath}, gulp.series(`${id}-component-js`)) 290 | } 291 | 292 | return done() 293 | }) 294 | 295 | /** 296 | * 监听 json 变化 297 | */ 298 | gulp.task(`${id}-watch-json`, () => gulp.watch(this.componentListMap.jsonFileList, {cwd: srcPath, base: srcPath}, gulp.series(`${id}-component-check`, gulp.parallel(`${id}-component-wxml`, `${id}-component-wxss`, `${id}-component-js`, `${id}-component-json`)))) 299 | 300 | /** 301 | * 监听 wxml 变化 302 | */ 303 | gulp.task(`${id}-watch-wxml`, () => { 304 | this.cachedComponentListMap.wxmlFileList = null 305 | return gulp.watch(this.componentListMap.wxmlFileList, {cwd: srcPath, base: srcPath}, gulp.series(`${id}-component-wxml`)) 306 | }) 307 | 308 | /** 309 | * 监听 wxss 变化 310 | */ 311 | gulp.task(`${id}-watch-wxss`, () => { 312 | this.cachedComponentListMap.wxssFileList = null 313 | return gulp.watch('**/*.wxss', {cwd: srcPath, base: srcPath}, gulp.series(`${id}-component-wxss`)) 314 | }) 315 | 316 | /** 317 | * 监听相关资源变化 318 | */ 319 | gulp.task(`${id}-watch-copy`, () => { 320 | const copyList = this.copyList 321 | const copyFileList = copyList.map(copyFilePath => { 322 | try { 323 | if (fs.statSync(path.join(srcPath, copyFilePath)).isDirectory()) { 324 | return path.join(copyFilePath, '**/*') 325 | } else { 326 | return copyFilePath 327 | } 328 | } catch (err) { 329 | // eslint-disable-next-line no-console 330 | console.error(err) 331 | return null 332 | } 333 | }).filter(copyFilePath => !!copyFilePath) 334 | const watchCallback = filePath => copy([filePath]) 335 | 336 | return gulp.watch(copyFileList, {cwd: srcPath, base: srcPath}) 337 | .on('change', watchCallback) 338 | .on('add', watchCallback) 339 | .on('unlink', watchCallback) 340 | }) 341 | 342 | /** 343 | * 监听 demo 变化 344 | */ 345 | gulp.task(`${id}-watch-demo`, () => { 346 | const demoSrc = config.demoSrc 347 | const demoDist = config.demoDist 348 | const watchCallback = filePath => gulp.src(filePath, {cwd: demoSrc, base: demoSrc}) 349 | .pipe(gulp.dest(demoDist)) 350 | 351 | return gulp.watch('**/*', {cwd: demoSrc, base: demoSrc}) 352 | .on('change', watchCallback) 353 | .on('add', watchCallback) 354 | .on('unlink', watchCallback) 355 | }) 356 | 357 | /** 358 | * 监听安装包列表变化 359 | */ 360 | gulp.task(`${id}-watch-install`, () => gulp.watch(path.resolve(__dirname, '../package.json'), install())) 361 | 362 | /** 363 | * 构建相关任务 364 | */ 365 | gulp.task(`${id}-build`, gulp.series(`${id}-clean-dist`, `${id}-component-check`, gulp.parallel(`${id}-component-wxml`, `${id}-component-wxss`, `${id}-component-js`, `${id}-component-json`, `${id}-copy`))) 366 | 367 | gulp.task(`${id}-watch`, gulp.series(`${id}-build`, `${id}-demo`, `${id}-install`, gulp.parallel(`${id}-watch-wxml`, `${id}-watch-wxss`, `${id}-watch-js`, `${id}-watch-json`, `${id}-watch-copy`, `${id}-watch-install`, `${id}-watch-demo`))) 368 | 369 | gulp.task(`${id}-dev`, gulp.series(`${id}-build`, `${id}-demo`, `${id}-install`)) 370 | 371 | gulp.task(`${id}-default`, gulp.series(`${id}-build`)) 372 | } 373 | } 374 | 375 | module.exports = BuildTask 376 | -------------------------------------------------------------------------------- /tools/checkcomponents.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | const _ = require('./utils') 4 | const config = require('./config') 5 | 6 | const srcPath = config.srcPath 7 | 8 | /** 9 | * 获取 json 路径相关信息 10 | */ 11 | function getJsonPathInfo(jsonPath) { 12 | const dirPath = path.dirname(jsonPath) 13 | const fileName = path.basename(jsonPath, '.json') 14 | const relative = path.relative(srcPath, dirPath) 15 | const fileBase = path.join(relative, fileName) 16 | 17 | return { 18 | dirPath, fileName, relative, fileBase 19 | } 20 | } 21 | 22 | /** 23 | * 检测是否包含其他自定义组件 24 | */ 25 | const checkProps = ['usingComponents', 'componentGenerics'] 26 | const hasCheckMap = {} 27 | async function checkIncludedComponents(jsonPath, componentListMap) { 28 | const json = _.readJson(jsonPath) 29 | if (!json) throw new Error(`json is not valid: "${jsonPath}"`) 30 | 31 | const {dirPath, fileName, fileBase} = getJsonPathInfo(jsonPath) 32 | if (hasCheckMap[fileBase]) return 33 | hasCheckMap[fileBase] = true 34 | 35 | for (let i = 0, len = checkProps.length; i < len; i++) { 36 | const checkProp = checkProps[i] 37 | const checkPropValue = json[checkProp] || {} 38 | const keys = Object.keys(checkPropValue) 39 | 40 | for (let j = 0, jlen = keys.length; j < jlen; j++) { 41 | const key = keys[j] 42 | let value = typeof checkPropValue[key] === 'object' ? checkPropValue[key].default : checkPropValue[key] 43 | if (!value || typeof value === 'boolean') continue 44 | 45 | value = _.transformPath(value, path.sep) 46 | 47 | // 检查相对路径 48 | const componentPath = `${path.join(dirPath, value)}.json` 49 | const isExists = await _.checkFileExists(componentPath) 50 | if (isExists) { 51 | await checkIncludedComponents(componentPath, componentListMap) 52 | } 53 | } 54 | } 55 | 56 | const wholeFileBase = path.join(dirPath, fileName) 57 | let jsExt = '.js' 58 | const isJsFileExists = await _.checkFileExists(wholeFileBase + '.ts') 59 | if (isJsFileExists) { 60 | jsExt = '.ts' 61 | } 62 | 63 | // 进入存储 64 | componentListMap.wxmlFileList.push(`${fileBase}.wxml`) 65 | componentListMap.wxssFileList.push(`${fileBase}.wxss`) 66 | componentListMap.jsonFileList.push(`${fileBase}.json`) 67 | componentListMap.jsFileList.push(`${fileBase}${jsExt}`) 68 | 69 | componentListMap.jsFileMap[fileBase] = `${wholeFileBase}${jsExt}` 70 | } 71 | 72 | module.exports = async function (entry) { 73 | const componentListMap = { 74 | wxmlFileList: [], 75 | wxssFileList: [], 76 | jsonFileList: [], 77 | jsFileList: [], 78 | 79 | jsFileMap: {}, // 为 webpack entry 所用 80 | } 81 | 82 | const isExists = await _.checkFileExists(entry) 83 | if (!isExists) { 84 | const {dirPath, fileName, fileBase} = getJsonPathInfo(entry) 85 | 86 | const wholeFileBase = path.join(dirPath, fileName) 87 | let jsExt = '.js' 88 | const isJsFileExists = await _.checkFileExists(wholeFileBase + '.ts') 89 | if (isJsFileExists) { 90 | jsExt = '.ts' 91 | } 92 | componentListMap.jsFileList.push(`${fileBase}${jsExt}`) 93 | componentListMap.jsFileMap[fileBase] = `${wholeFileBase}${jsExt}` 94 | 95 | return componentListMap 96 | } 97 | 98 | await checkIncludedComponents(entry, componentListMap) 99 | 100 | return componentListMap 101 | } 102 | -------------------------------------------------------------------------------- /tools/checkwxss.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const through = require('through2') 3 | const Vinyl = require('vinyl') 4 | 5 | const _ = require('./utils') 6 | 7 | /** 8 | * 获取 import 列表 9 | */ 10 | function getImportList(wxss, filePath) { 11 | const reg = /@import\s+(?:(?:"([^"]+)")|(?:'([^']+)'));/ig 12 | const importList = [] 13 | let execRes = reg.exec(wxss) 14 | 15 | while (execRes && (execRes[1] || execRes[2])) { 16 | importList.push({ 17 | code: execRes[0], 18 | path: path.join(path.dirname(filePath), execRes[1] || execRes[2]), 19 | }) 20 | execRes = reg.exec(wxss) 21 | } 22 | 23 | return importList 24 | } 25 | 26 | /** 27 | * 获取 wxss 内容 28 | */ 29 | async function getContent(wxss, filePath, cwd) { 30 | let importList = [] 31 | 32 | if (wxss) { 33 | const currentImportList = getImportList(wxss, filePath) 34 | 35 | for (const item of currentImportList) { 36 | // 替换掉 import 语句,不让 less 编译 37 | wxss = wxss.replace(item.code, `/* *updated for miniprogram-custom-component* ${item.code} */`) 38 | 39 | // 处理依赖的 wxss 40 | const importWxss = await _.readFile(item.path) 41 | const importInfo = await getContent(importWxss, item.path, cwd) 42 | 43 | // 获取依赖列表 44 | importList.push(new Vinyl({ 45 | cwd, 46 | path: item.path, 47 | contents: Buffer.from(importInfo.wxss, 'utf8'), 48 | })) 49 | importList = importList.concat(importInfo.importList) 50 | } 51 | } 52 | 53 | return { 54 | wxss, 55 | importList, 56 | } 57 | } 58 | 59 | module.exports = { 60 | start() { 61 | return through.obj(function (file, enc, cb) { 62 | if (file.isBuffer()) { 63 | getContent(file.contents.toString('utf8'), file.path, file.cwd).then(res => { 64 | const {wxss, importList} = res 65 | 66 | importList.forEach(importFile => this.push(importFile)) 67 | 68 | file.contents = Buffer.from(wxss, 'utf8') 69 | this.push(file) 70 | // eslint-disable-next-line promise/no-callback-in-promise 71 | cb() 72 | }).catch(err => { 73 | // eslint-disable-next-line no-console 74 | console.warn(`deal with ${file.path} failed: ${err.stack}`) 75 | this.push(file) 76 | // eslint-disable-next-line promise/no-callback-in-promise 77 | cb() 78 | }) 79 | } else { 80 | this.push(file) 81 | cb() 82 | } 83 | }) 84 | }, 85 | 86 | end() { 87 | return through.obj(function (file, enc, cb) { 88 | if (file.isBuffer) { 89 | const reg = /\/\*\s\*updated for miniprogram-custom-component\*\s(@import\s+(?:(?:"([^"]+)")|(?:'([^"]+)'));)\s\*\//ig 90 | const wxss = file.contents.toString('utf8').replace(reg, (all, $1) => $1) 91 | 92 | file.contents = Buffer.from(wxss, 'utf8') 93 | this.push(file) 94 | cb() 95 | } else { 96 | this.push(file) 97 | cb() 98 | } 99 | }) 100 | }, 101 | } 102 | -------------------------------------------------------------------------------- /tools/config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | const webpack = require('webpack') 4 | const nodeExternals = require('webpack-node-externals') 5 | 6 | const isDev = process.argv.indexOf('--develop') >= 0 7 | const isWatch = process.argv.indexOf('--watch') >= 0 8 | const demoSrc = path.resolve(__dirname, './demo') 9 | const demoDist = path.resolve(__dirname, '../miniprogram_dev') 10 | const src = path.resolve(__dirname, '../src') 11 | const dev = path.join(demoDist, 'components') 12 | const dist = path.resolve(__dirname, '../miniprogram_dist') 13 | 14 | module.exports = { 15 | entry: ['index', 'lib'], 16 | 17 | isDev, 18 | isWatch, 19 | srcPath: src, // 源目录 20 | distPath: isDev ? dev : dist, // 目标目录 21 | 22 | demoSrc, // demo 源目录 23 | demoDist, // demo 目标目录 24 | 25 | wxss: { 26 | less: false, // 使用 less 来编写 wxss 27 | sourcemap: false, // 生成 less sourcemap 28 | }, 29 | 30 | js: { 31 | webpack: true, // 使用 webpack 来构建 js 32 | }, 33 | 34 | webpack: { 35 | mode: 'production', 36 | output: { 37 | filename: '[name].js', 38 | libraryTarget: 'commonjs2', 39 | }, 40 | target: 'node', 41 | externals: [nodeExternals()], // 忽略 node_modules 42 | module: { 43 | rules: [{ 44 | test: /\.js$/i, 45 | use: [{ 46 | loader: 'thread-loader', 47 | }, { 48 | loader: 'babel-loader', 49 | options: { 50 | cacheDirectory: true, 51 | }, 52 | }, 53 | ], 54 | exclude: /node_modules/ 55 | }, { 56 | test: /\.ts$/, 57 | exclude: /node_modules/, 58 | use: [{ 59 | loader: 'thread-loader', 60 | }, { 61 | loader: 'babel-loader', 62 | options: { 63 | cacheDirectory: true, 64 | }, 65 | }, { 66 | loader: 'ts-loader', 67 | options: { 68 | appendTsSuffixTo: [/\.vue$/], 69 | happyPackMode: true, 70 | }, 71 | }, 72 | ], 73 | }], 74 | }, 75 | resolve: { 76 | modules: [src, 'node_modules'], 77 | extensions: ['.js', '.json'], 78 | }, 79 | plugins: [ 80 | new webpack.DefinePlugin({}), 81 | new webpack.optimize.LimitChunkCountPlugin({maxChunks: 1}), 82 | ], 83 | optimization: { 84 | minimize: false, 85 | }, 86 | devtool: 'source-map', // 生成 js sourcemap 87 | performance: { 88 | hints: 'warning', 89 | assetFilter: assetFilename => assetFilename.endsWith('.js') 90 | } 91 | }, 92 | 93 | copy: ['./assets', './utils.js'], // 将会复制到目标目录 94 | } 95 | -------------------------------------------------------------------------------- /tools/demo/app.js: -------------------------------------------------------------------------------- 1 | App({}) 2 | -------------------------------------------------------------------------------- /tools/demo/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages":[ 3 | "pages/index/index" 4 | ], 5 | "window":{ 6 | "backgroundTextStyle":"light", 7 | "navigationBarBackgroundColor": "#fff", 8 | "navigationBarTitleText": "WeChat", 9 | "navigationBarTextStyle":"black" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tools/demo/app.wxss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habc0807/miniprogram-table-component/be20af2c32e8616de021de2642e53ad5c8de15ac/tools/demo/app.wxss -------------------------------------------------------------------------------- /tools/demo/package.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /tools/demo/pages/index/index.js: -------------------------------------------------------------------------------- 1 | Page({}) 2 | -------------------------------------------------------------------------------- /tools/demo/pages/index/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": { 3 | "comp": "../../components/index" 4 | } 5 | } -------------------------------------------------------------------------------- /tools/demo/pages/index/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tools/demo/pages/index/index.wxss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habc0807/miniprogram-table-component/be20af2c32e8616de021de2642e53ad5c8de15ac/tools/demo/pages/index/index.wxss -------------------------------------------------------------------------------- /tools/demo/project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "项目配置文件。", 3 | "packOptions": { 4 | "ignore": [] 5 | }, 6 | "setting": { 7 | "urlCheck": true, 8 | "es6": true, 9 | "postcss": true, 10 | "minified": true, 11 | "newFeature": true, 12 | "nodeModules": true 13 | }, 14 | "compileType": "miniprogram", 15 | "libVersion": "2.10.4", 16 | "appid": "", 17 | "projectname": "miniprogram-demo", 18 | "isGameTourist": false, 19 | "condition": { 20 | "search": { 21 | "current": -1, 22 | "list": [] 23 | }, 24 | "conversation": { 25 | "current": -1, 26 | "list": [] 27 | }, 28 | "game": { 29 | "currentL": -1, 30 | "list": [] 31 | }, 32 | "miniprogram": { 33 | "current": -1, 34 | "list": [] 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /tools/utils.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | 4 | // eslint-disable-next-line no-unused-vars 5 | const colors = require('colors') 6 | const through = require('through2') 7 | 8 | /** 9 | * 异步函数封装 10 | */ 11 | function wrap(func, scope) { 12 | return function (...args) { 13 | if (args.length) { 14 | const temp = args.pop() 15 | if (typeof temp !== 'function') { 16 | args.push(temp) 17 | } 18 | } 19 | 20 | return new Promise(function (resolve, reject) { 21 | args.push(function (err, data) { 22 | if (err) reject(err) 23 | else resolve(data) 24 | }) 25 | 26 | func.apply((scope || null), args) 27 | }) 28 | } 29 | } 30 | 31 | const accessSync = wrap(fs.access) 32 | const statSync = wrap(fs.stat) 33 | const renameSync = wrap(fs.rename) 34 | const mkdirSync = wrap(fs.mkdir) 35 | const readFileSync = wrap(fs.readFile) 36 | const writeFileSync = wrap(fs.writeFile) 37 | 38 | /** 39 | * 调整路径分隔符 40 | */ 41 | function transformPath(filePath, sep = '/') { 42 | return filePath.replace(/[\\/]/g, sep) 43 | } 44 | 45 | /** 46 | * 检查文件是否存在 47 | */ 48 | async function checkFileExists(filePath) { 49 | try { 50 | await accessSync(filePath) 51 | return true 52 | } catch (err) { 53 | return false 54 | } 55 | } 56 | 57 | /** 58 | * 递归创建目录 59 | */ 60 | async function recursiveMkdir(dirPath) { 61 | const prevDirPath = path.dirname(dirPath) 62 | try { 63 | await accessSync(prevDirPath) 64 | } catch (err) { 65 | // 上一级目录不存在 66 | await recursiveMkdir(prevDirPath) 67 | } 68 | 69 | try { 70 | await accessSync(dirPath) 71 | 72 | const stat = await statSync(dirPath) 73 | if (stat && !stat.isDirectory()) { 74 | // 目标路径存在,但不是目录 75 | await renameSync(dirPath, `${dirPath}.bak`) // 将此文件重命名为 .bak 后缀 76 | await mkdirSync(dirPath) 77 | } 78 | } catch (err) { 79 | // 目标路径不存在 80 | await mkdirSync(dirPath) 81 | } 82 | } 83 | 84 | /** 85 | * 读取 json 86 | */ 87 | function readJson(filePath) { 88 | try { 89 | // eslint-disable-next-line import/no-dynamic-require 90 | const content = require(filePath) 91 | delete require.cache[require.resolve(filePath)] 92 | return content 93 | } catch (err) { 94 | return null 95 | } 96 | } 97 | 98 | /** 99 | * 读取文件 100 | */ 101 | async function readFile(filePath) { 102 | try { 103 | return await readFileSync(filePath, 'utf8') 104 | } catch (err) { 105 | // eslint-disable-next-line no-console 106 | return console.error(err) 107 | } 108 | } 109 | 110 | /** 111 | * 写文件 112 | */ 113 | async function writeFile(filePath, data) { 114 | try { 115 | await recursiveMkdir(path.dirname(filePath)) 116 | return await writeFileSync(filePath, data, 'utf8') 117 | } catch (err) { 118 | // eslint-disable-next-line no-console 119 | return console.error(err) 120 | } 121 | } 122 | 123 | /** 124 | * 时间格式化 125 | */ 126 | function format(time, reg) { 127 | const date = typeof time === 'string' ? new Date(time) : time 128 | const map = {} 129 | map.yyyy = date.getFullYear() 130 | map.yy = ('' + map.yyyy).substr(2) 131 | map.M = date.getMonth() + 1 132 | map.MM = (map.M < 10 ? '0' : '') + map.M 133 | map.d = date.getDate() 134 | map.dd = (map.d < 10 ? '0' : '') + map.d 135 | map.H = date.getHours() 136 | map.HH = (map.H < 10 ? '0' : '') + map.H 137 | map.m = date.getMinutes() 138 | map.mm = (map.m < 10 ? '0' : '') + map.m 139 | map.s = date.getSeconds() 140 | map.ss = (map.s < 10 ? '0' : '') + map.s 141 | 142 | return reg.replace(/\byyyy|yy|MM|M|dd|d|HH|H|mm|m|ss|s\b/g, $1 => map[$1]) 143 | } 144 | 145 | /** 146 | * 日志插件 147 | */ 148 | function logger(action = 'copy') { 149 | return through.obj(function (file, enc, cb) { 150 | const type = path.extname(file.path).slice(1).toLowerCase() 151 | 152 | // eslint-disable-next-line no-console 153 | console.log(`[${format(new Date(), 'yyyy-MM-dd HH:mm:ss').grey}] [${action.green} ${type.green}] ${'=>'.cyan} ${file.path}`) 154 | 155 | this.push(file) 156 | cb() 157 | }) 158 | } 159 | 160 | /** 161 | * 比较数组是否相等 162 | */ 163 | function compareArray(arr1, arr2) { 164 | if (!Array.isArray(arr1) || !Array.isArray(arr2)) return false 165 | if (arr1.length !== arr2.length) return false 166 | 167 | for (let i = 0, len = arr1.length; i < len; i++) { 168 | if (arr1[i] !== arr2[i]) return false 169 | } 170 | 171 | return true 172 | } 173 | 174 | /** 175 | * 合并两个对象 176 | */ 177 | function merge(obj1, obj2) { 178 | Object.keys(obj2).forEach(key => { 179 | if (Array.isArray(obj1[key]) && Array.isArray(obj2[key])) { 180 | obj1[key] = obj1[key].concat(obj2[key]) 181 | } else if (typeof obj1[key] === 'object' && typeof obj2[key] === 'object') { 182 | obj1[key] = Object.assign(obj1[key], obj2[key]) 183 | } else { 184 | obj1[key] = obj2[key] 185 | } 186 | }) 187 | 188 | return obj1 189 | } 190 | 191 | /** 192 | * 获取 id 193 | */ 194 | let seed = +new Date() 195 | function getId() { 196 | return ++seed 197 | } 198 | 199 | module.exports = { 200 | wrap, 201 | transformPath, 202 | 203 | checkFileExists, 204 | readJson, 205 | readFile, 206 | writeFile, 207 | 208 | logger, 209 | format, 210 | compareArray, 211 | merge, 212 | getId, 213 | } 214 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "esnext", 4 | "target": "es2015", 5 | "lib": ["es2015", "es2017", "dom"], 6 | "noImplicitAny": false, 7 | "moduleResolution": "node", 8 | "sourceMap": true, 9 | "baseUrl": ".", 10 | "allowSyntheticDefaultImports": true, 11 | "experimentalDecorators": true, 12 | "emitDecoratorMetadata":true, 13 | "esModuleInterop": true, 14 | "resolveJsonModule": true 15 | }, 16 | "files": [ 17 | "node_modules/miniprogram-api-typings/index.d.ts" 18 | ], 19 | "include": [ 20 | "src/**/*.ts" 21 | ], 22 | "exclude": [ 23 | "node_modules" 24 | ] 25 | } 26 | --------------------------------------------------------------------------------