├── tools ├── demo │ ├── app.wxss │ ├── package.json │ ├── app.js │ ├── pages │ │ └── index │ │ │ ├── index.wxss │ │ │ ├── index.js │ │ │ ├── index.wxml │ │ │ └── index.json │ ├── app.json │ └── project.config.json ├── config.js ├── checkcomponents.js ├── checkwxss.js ├── utils.js └── build.js ├── .eslintrc.js ├── src ├── utils.js ├── index.json ├── assets │ ├── demo1.jpg │ └── demo2.jpg ├── index.wxml ├── index.wxss └── index.js ├── .gitignore ├── .babelrc ├── .npmignore ├── test ├── wx.test.js ├── index.test.js └── utils.js ├── gulpfile.js ├── LICENSE ├── README.md └── package.json /tools/demo/app.wxss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tools/demo/package.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = {}; -------------------------------------------------------------------------------- /tools/demo/app.js: -------------------------------------------------------------------------------- 1 | App({}) 2 | -------------------------------------------------------------------------------- /tools/demo/pages/index/index.wxss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | module.exports = {}; 2 | -------------------------------------------------------------------------------- /tools/demo/pages/index/index.js: -------------------------------------------------------------------------------- 1 | Page({}) 2 | -------------------------------------------------------------------------------- /tools/demo/pages/index/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /src/assets/demo1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xjh22222228/weapp-input-frame/HEAD/src/assets/demo1.jpg -------------------------------------------------------------------------------- /src/assets/demo2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xjh22222228/weapp-input-frame/HEAD/src/assets/demo2.jpg -------------------------------------------------------------------------------- /tools/demo/pages/index/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": { 3 | "comp": "../../components/index" 4 | } 5 | } -------------------------------------------------------------------------------- /.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 | miniprogram_dist 12 | miniprogram_dev 13 | node_modules 14 | coverage -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["module-resolver", { 4 | "root": ["./src"], 5 | "alias": {} 6 | }] 7 | ], 8 | "presets": [ 9 | ["env", {"loose": true, "modules": "commonjs"}] 10 | ] 11 | } -------------------------------------------------------------------------------- /.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 | src 12 | test 13 | tools 14 | docs 15 | miniprogram_dev 16 | node_modules 17 | coverage 18 | .babelrc 19 | gulpfile.js 20 | .eslintrc.js -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | 16 | 22 | {{ valueList[index] }} 23 | 24 | 25 | -------------------------------------------------------------------------------- /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-false')).toBe(true) 11 | 12 | await _.sleep(10) 13 | 14 | expect(_.match(component.dom, 'index.test.properties-true')).toBe(true) 15 | }) 16 | -------------------------------------------------------------------------------- /test/utils.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const simulate = require('miniprogram-simulate') 3 | 4 | const config = require('../tools/config') 5 | 6 | const srcPath = config.srcPath 7 | const oldLoad = simulate.load 8 | simulate.load = function (componentPath, ...args) { 9 | if (typeof componentPath === 'string') componentPath = path.join(srcPath, componentPath) 10 | return oldLoad(componentPath, ...args) 11 | } 12 | 13 | module.exports = simulate 14 | 15 | // adjust the simulated wx api 16 | const oldGetSystemInfoSync = global.wx.getSystemInfoSync 17 | global.wx.getSystemInfoSync = function() { 18 | const res = oldGetSystemInfoSync() 19 | res.SDKVersion = '2.4.1' 20 | 21 | return res 22 | } 23 | -------------------------------------------------------------------------------- /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.2.3", 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 | } -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/index.wxss: -------------------------------------------------------------------------------- 1 | .input-frame { 2 | position: relative; 3 | display: flex; 4 | justify-content: center; 5 | } 6 | 7 | .input-frame .input-item { 8 | width: 50px; 9 | height: 50px; 10 | display: flex; 11 | justify-content: center; 12 | align-items: center; 13 | border: 1px solid #ccc; 14 | } 15 | 16 | .input-frame__input { 17 | position: absolute; 18 | top: 0; 19 | left: 0; 20 | right: 0; 21 | bottom: 0; 22 | width: 100%; 23 | height: 100%; 24 | opacity: 0; 25 | left: -5000px; 26 | } 27 | 28 | .input-frame .input-item:not(:nth-last-child(1)) { 29 | border-right-color: transparent; 30 | } 31 | 32 | /* divider style */ 33 | .input-frame.divider .input-item { 34 | border-top-color: transparent; 35 | border-right-color: transparent; 36 | border-left-color: transparent; 37 | margin: 0 7px; 38 | width: 40px; 39 | height: 40px; 40 | } 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 xiejiahe 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 | # input-frame ![GitHub package.json version](https://img.shields.io/github/package-json/v/xjh22222228/weapp-input-frame) ![GitHub](https://img.shields.io/github/license/xjh22222228/weapp-input-frame) 2 | 3 | 小程序输入框组件,适用于支付密码、登录密码 等。 4 | 5 | ## Screenshots 6 |
7 | 8 | 9 |
10 | 11 | 12 | ## 安装 13 | 安装完成在开发者工具执行 `npm build` 14 | ```bash 15 | npm install weapp-input-frame -S 16 | ``` 17 | 18 | ## 使用 19 | *.json 20 | ```json 21 | "usingComponents": { 22 | "input-frame": "miniprogram_npm/weapp-input-frame/index" 23 | } 24 | ``` 25 | 26 | *.wxml 27 | ```html 28 | 29 | ``` 30 | 31 | 32 | ## API 33 | - value 输入框默认值 34 | - plaintext 是否明文显示, 默认 false 35 | - focus 是否获取焦点, 默认 false 36 | - bind:change 输入发生变化触发 37 | - bind:finished 输入完成时触发 38 | - space 输入框的格子数量,一般 4 - 6, 默认 6 39 | - frameStyle 输入框的风格, `divider` / '' , 默认 '' 40 | - custom-class 自定义组件class 41 | 42 | ```html 43 | 50 | ``` 51 | 52 | ## 暴露方法 53 | - getValue 获取输入框值 54 | - setValue 动态设置输入框值 55 | 56 | wxml 57 | ```html 58 | { 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/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 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------