├── pages └── index │ ├── index.wxss │ ├── index.wxml │ ├── index.json │ └── index.js ├── component └── uploadImages │ ├── index.json │ ├── index.wxml │ ├── index.wxss │ └── index.js ├── README.md ├── app.wxss ├── app.json ├── utils ├── util.js ├── diff.js └── create.js ├── project.config.json └── app.js /pages/index/index.wxss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /component/uploadImages/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /pages/index/index.wxml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pages/index/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "多张图片上传", 3 | "usingComponents": { 4 | "uploadImages": "/component/uploadImages/index" 5 | } 6 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | uploadImages 微信小程序上传多张图片 2 | ==================== 3 | ## 使用需要填写uploadImgUrl 4 | ``` 5 | showImgUrl: "", //路径拼接,一般上传返回的都是文件名 6 | 7 | uploadImgUrl:''//图片的上传的路径 8 | ``` 9 | -------------------------------------------------------------------------------- /app.wxss: -------------------------------------------------------------------------------- 1 | /**app.wxss**/ 2 | .container { 3 | height: 100%; 4 | display: flex; 5 | flex-direction: column; 6 | align-items: center; 7 | justify-content: space-between; 8 | padding: 200rpx 0; 9 | box-sizing: border-box; 10 | } 11 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /pages/index/index.js: -------------------------------------------------------------------------------- 1 | // pages/weijieke/product/index.js 2 | const app = getApp(); 3 | Page({ 4 | 5 | /** 6 | * 页面的初始数据 7 | */ 8 | data: { 9 | countPic:9,//上传图片最大数量 10 | showImgUrl: "", //路径拼接,一般上传返回的都是文件名, 11 | uploadImgUrl:''//图片的上传的路径 12 | }, 13 | 14 | //监听组件事件,返回的结果 15 | myEventListener:function(e){ 16 | console.log("上传的图片结果集合") 17 | console.log(e.detail.picsList) 18 | }, 19 | 20 | }) -------------------------------------------------------------------------------- /utils/util.js: -------------------------------------------------------------------------------- 1 | const formatTime = date => { 2 | const year = date.getFullYear() 3 | const month = date.getMonth() + 1 4 | const day = date.getDate() 5 | const hour = date.getHours() 6 | const minute = date.getMinutes() 7 | const second = date.getSeconds() 8 | 9 | return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':') 10 | } 11 | 12 | const formatNumber = n => { 13 | n = n.toString() 14 | return n[1] ? n : '0' + n 15 | } 16 | 17 | module.exports = { 18 | formatTime: formatTime 19 | } 20 | -------------------------------------------------------------------------------- /component/uploadImages/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 长按对应的图片即可删除 14 | 15 | -------------------------------------------------------------------------------- /project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "项目配置文件", 3 | "packOptions": { 4 | "ignore": [] 5 | }, 6 | "setting": { 7 | "urlCheck": false, 8 | "es6": true, 9 | "postcss": true, 10 | "minified": true, 11 | "newFeature": true 12 | }, 13 | "compileType": "miniprogram", 14 | "libVersion": "2.3.0", 15 | "appid": "wx2ab3b0e447dbecf4", 16 | "projectname": "uploadImages", 17 | "debugOptions": { 18 | "hidedInDevtools": [] 19 | }, 20 | "isGameTourist": false, 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 | } -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | //app.js 2 | App({ 3 | onLaunch: function () { 4 | // 展示本地存储能力 5 | var logs = wx.getStorageSync('logs') || [] 6 | logs.unshift(Date.now()) 7 | wx.setStorageSync('logs', logs) 8 | 9 | // 登录 10 | wx.login({ 11 | success: res => { 12 | // 发送 res.code 到后台换取 openId, sessionKey, unionId 13 | } 14 | }) 15 | // 获取用户信息 16 | wx.getSetting({ 17 | success: res => { 18 | if (res.authSetting['scope.userInfo']) { 19 | // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框 20 | wx.getUserInfo({ 21 | success: res => { 22 | // 可以将 res 发送给后台解码出 unionId 23 | this.globalData.userInfo = res.userInfo 24 | 25 | // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回 26 | // 所以此处加入 callback 以防止这种情况 27 | if (this.userInfoReadyCallback) { 28 | this.userInfoReadyCallback(res) 29 | } 30 | } 31 | }) 32 | } 33 | } 34 | }) 35 | }, 36 | globalData: { 37 | userInfo: null 38 | } 39 | }) -------------------------------------------------------------------------------- /component/uploadImages/index.wxss: -------------------------------------------------------------------------------- 1 | page { 2 | background-color: #f1f0f5; 3 | } 4 | 5 | .content { 6 | width: 100%; 7 | background-color: #fff; 8 | } 9 | 10 | .img-list { 11 | display: flex; 12 | display: -webkit-flex; 13 | flex-direction: row; 14 | justify-content: flex-start; 15 | align-items: center; 16 | flex-wrap: wrap; 17 | } 18 | 19 | .img-item { 20 | width: 30%; 21 | text-align: left; 22 | margin-right: 20rpx; 23 | margin-bottom: 10rpx; 24 | } 25 | 26 | .img-item image { 27 | width: 180rpx; 28 | height: 180rpx; 29 | } 30 | 31 | .submit-btn { 32 | width: 100%; 33 | background-color: #fff; 34 | height: 80rpx; 35 | text-align: center; 36 | line-height: 80rpx; 37 | font-size: 30rpx; 38 | position: fixed; 39 | bottom: 100rpx; 40 | } 41 | 42 | .chooseimg { 43 | background-color: #fff; 44 | } 45 | 46 | .weui-uploader__input-box { 47 | float: left; 48 | position: relative; 49 | margin-right: 9px; 50 | margin-bottom: 9px; 51 | width: 180rpx; 52 | height: 180rpx; 53 | border: 1px solid #d9d9d9; 54 | } 55 | 56 | .weui-uploader__input-box:before { 57 | width: 2px; 58 | height: 39.5px; 59 | } 60 | 61 | .weui-uploader__input-box:after, .weui-uploader__input-box:before { 62 | content: " "; 63 | position: absolute; 64 | top: 50%; 65 | left: 50%; 66 | -webkit-transform: translate(-50%, -50%); 67 | transform: translate(-50%, -50%); 68 | background-color: #d9d9d9; 69 | } 70 | 71 | .weui-uploader__input-box:after { 72 | width: 39.5px; 73 | height: 2px; 74 | } 75 | 76 | .weui-uploader__input-box:after, .weui-uploader__input-box:before { 77 | content: " "; 78 | position: absolute; 79 | top: 50%; 80 | left: 50%; 81 | -webkit-transform: translate(-50%, -50%); 82 | transform: translate(-50%, -50%); 83 | background-color: #d9d9d9; 84 | } 85 | 86 | .tips { 87 | color: #666; 88 | font-size: 24rpx; 89 | padding-bottom: 20rpx; 90 | } 91 | 92 | .img-box { 93 | width: 92%; 94 | margin: auto; 95 | padding-top: 20rpx; 96 | } 97 | -------------------------------------------------------------------------------- /component/uploadImages/index.js: -------------------------------------------------------------------------------- 1 | // component/uploadImages/index.js 2 | Component({ 3 | /** 4 | * 组件的属性列表 5 | */ 6 | properties: { 7 | count: { //最多选择图片的张数,默认9张 8 | type: Number, 9 | value: 9 10 | }, 11 | uploadUrl: { //图片上传的服务器路径 12 | type: String, 13 | value: '' 14 | }, 15 | showUrl: { //图片的拼接路径 16 | type: String, 17 | value: '' 18 | } 19 | }, 20 | 21 | /** 22 | * 组件的初始数据 23 | */ 24 | data: { 25 | detailPics: [], //上传的结果图片集合 26 | }, 27 | 28 | ready: function() { 29 | console.log(this.data) 30 | }, 31 | 32 | /** 33 | * 组件的方法列表 34 | */ 35 | methods: { 36 | 37 | /** 38 | * 上传详细图片 39 | */ 40 | uploadDetailImage: function(e) { //这里是选取图片的方法 41 | var that = this; 42 | var pics = []; 43 | var detailPics = that.data.detailPics; 44 | if (detailPics.length >= that.data.count) { 45 | wx.showToast({ 46 | title: '最多选择' + that.data.count + '张!', 47 | }) 48 | return; 49 | } 50 | wx.chooseImage({ 51 | count: that.data.count, // 最多可以选择的图片张数,默认9 52 | sizeType: ['original', 'compressed'], // original 原图,compressed 压缩图,默认二者都有 53 | sourceType: ['album', 'camera'], // album 从相册选图,camera 使用相机,默认二者都有 54 | success: function(res) { 55 | var imgs = res.tempFilePaths; 56 | for (var i = 0; i < imgs.length; i++) { 57 | pics.push(imgs[i]) 58 | } 59 | that.uploadimg({ 60 | url: that.data.uploadUrl, //这里是你图片上传的接口 61 | path: pics, //这里是选取的图片的地址数组 62 | }); 63 | }, 64 | }) 65 | 66 | }, 67 | //多张图片上传 68 | uploadimg: function(data) { 69 | wx.showLoading({ 70 | title: '上传中...', 71 | mask: true, 72 | }) 73 | var that = this, 74 | i = data.i ? data.i : 0, 75 | success = data.success ? data.success : 0, 76 | fail = data.fail ? data.fail : 0; 77 | wx.uploadFile({ 78 | url: data.url, 79 | filePath: data.path[i], 80 | name: 'fileData', 81 | formData: null, 82 | success: (resp) => { 83 | wx.hideLoading(); 84 | success++; 85 | var str = resp.data //返回的结果,可能不同项目结果不一样 86 | var pic = JSON.parse(str); 87 | var pic_name = that.data.showUrl + pic.Data; 88 | var detailPics = that.data.detailPics; 89 | detailPics.push(pic_name) 90 | that.setData({ 91 | detailPics: detailPics 92 | }) 93 | }, 94 | fail: (res) => { 95 | fail++; 96 | console.log('fail:' + i + "fail:" + fail); 97 | }, 98 | complete: () => { 99 | i++; 100 | if (i == data.path.length) { //当图片传完时,停止调用 101 | console.log('执行完毕'); 102 | console.log('成功:' + success + " 失败:" + fail); 103 | var myEventDetail = { 104 | picsList: that.data.detailPics 105 | } // detail对象,提供给事件监听函数 106 | var myEventOption = {} // 触发事件的选项 107 | that.triggerEvent('myevent', myEventDetail, myEventOption) 108 | } else { //若图片还没有传完,则继续调用函数 109 | data.i = i; 110 | data.success = success; 111 | data.fail = fail; 112 | that.uploadimg(data); 113 | } 114 | } 115 | }); 116 | }, 117 | 118 | } 119 | }) -------------------------------------------------------------------------------- /utils/diff.js: -------------------------------------------------------------------------------- 1 | const ARRAYTYPE = '[object Array]' 2 | const OBJECTTYPE = '[object Object]' 3 | const FUNCTIONTYPE = '[object Function]' 4 | 5 | export default function diff(current, pre) { 6 | const result = {} 7 | syncKeys(current, pre) 8 | _diff(current, pre, '', result) 9 | return result 10 | } 11 | 12 | function syncKeys(current, pre) { 13 | if (current === pre) return 14 | const rootCurrentType = type(current) 15 | const rootPreType = type(pre) 16 | if (rootCurrentType == OBJECTTYPE && rootPreType == OBJECTTYPE) { 17 | if(Object.keys(current).length >= Object.keys(pre).length){ 18 | for (let key in pre) { 19 | const currentValue = current[key] 20 | if (currentValue === undefined) { 21 | current[key] = null 22 | } else { 23 | syncKeys(currentValue, pre[key]) 24 | } 25 | } 26 | } 27 | } else if (rootCurrentType == ARRAYTYPE && rootPreType == ARRAYTYPE) { 28 | if (current.length >= pre.length) { 29 | pre.forEach((item, index) => { 30 | syncKeys(current[index], item) 31 | }) 32 | } 33 | } 34 | } 35 | 36 | function _diff(current, pre, path, result) { 37 | if (current === pre) return 38 | const rootCurrentType = type(current) 39 | const rootPreType = type(pre) 40 | if (rootCurrentType == OBJECTTYPE) { 41 | if (rootPreType != OBJECTTYPE || Object.keys(current).length < Object.keys(pre).length) { 42 | setResult(result, path, current) 43 | } else { 44 | for (let key in current) { 45 | const currentValue = current[key] 46 | const preValue = pre[key] 47 | const currentType = type(currentValue) 48 | const preType = type(preValue) 49 | if (currentType != ARRAYTYPE && currentType != OBJECTTYPE) { 50 | if (currentValue != pre[key]) { 51 | setResult(result, (path == '' ? '' : path + ".") + key, currentValue) 52 | } 53 | } else if (currentType == ARRAYTYPE) { 54 | if (preType != ARRAYTYPE) { 55 | setResult(result, (path == '' ? '' : path + ".") + key, currentValue) 56 | } else { 57 | if (currentValue.length < preValue.length) { 58 | setResult(result, (path == '' ? '' : path + ".") + key, currentValue) 59 | } else { 60 | currentValue.forEach((item, index) => { 61 | _diff(item, preValue[index], (path == '' ? '' : path + ".") + key + '[' + index + ']', result) 62 | }) 63 | } 64 | } 65 | } else if (currentType == OBJECTTYPE) { 66 | if (preType != OBJECTTYPE || Object.keys(currentValue).length < Object.keys(preValue).length) { 67 | setResult(result, (path == '' ? '' : path + ".") + key, currentValue) 68 | } else { 69 | for (let subKey in currentValue) { 70 | _diff(currentValue[subKey], preValue[subKey], (path == '' ? '' : path + ".") + key + '.' + subKey, result) 71 | } 72 | } 73 | } 74 | } 75 | } 76 | } else if (rootCurrentType == ARRAYTYPE) { 77 | if (rootPreType != ARRAYTYPE) { 78 | setResult(result, path, current) 79 | } else { 80 | if (current.length < pre.length) { 81 | setResult(result, path, current) 82 | } else { 83 | current.forEach((item, index) => { 84 | _diff(item, pre[index], path + '[' + index + ']', result) 85 | }) 86 | } 87 | } 88 | } else { 89 | setResult(result, path, current) 90 | } 91 | } 92 | 93 | function setResult(result, k, v) { 94 | const t = type(v) 95 | if (t != FUNCTIONTYPE) { 96 | //if (t != OBJECTTYPE && t != ARRAYTYPE) { 97 | result[k] = v 98 | // } else { 99 | // result[k] = JSON.parse(JSON.stringify(v)) 100 | // } 101 | } 102 | } 103 | 104 | function type(obj) { 105 | return Object.prototype.toString.call(obj) 106 | } -------------------------------------------------------------------------------- /utils/create.js: -------------------------------------------------------------------------------- 1 | import diff from './diff' 2 | 3 | let originData = null 4 | let globalStore = null 5 | let fnMapping = {} 6 | 7 | const ARRAYTYPE = '[object Array]' 8 | const OBJECTTYPE = '[object Object]' 9 | const FUNCTIONTYPE = '[object Function]' 10 | 11 | export default function create(store, option) { 12 | let updatePath = null 13 | if (arguments.length === 2) { 14 | if (option.data && Object.keys(option.data).length > 0) { 15 | updatePath = getUpdatePath(option.data) 16 | syncValues(store.data, option.data) 17 | } 18 | if (!originData) { 19 | originData = JSON.parse(JSON.stringify(store.data)) 20 | globalStore = store 21 | store.instances = {} 22 | store.update = update 23 | store.push = push 24 | store.pull = pull 25 | store.add = add 26 | store.remove = remove 27 | store.originData = originData 28 | store.env && initCloud(store.env) 29 | extendStoreMethod(store) 30 | } 31 | getApp().globalData && (getApp().globalData.store = store) 32 | option.data = store.data 33 | const onLoad = option.onLoad 34 | walk(store.data) 35 | option.onLoad = function (e) { 36 | this.store = store 37 | this._updatePath = updatePath 38 | rewriteUpdate(this) 39 | store.instances[this.route] = [] 40 | store.instances[this.route].push(this) 41 | onLoad && onLoad.call(this, e) 42 | } 43 | Page(option) 44 | } else { 45 | const ready = store.ready 46 | const pure = store.pure 47 | store.ready = function () { 48 | if (pure) { 49 | this.store = { data: store.data || {} } 50 | this.store.originData = store.data ? JSON.parse(JSON.stringify(store.data)) : {} 51 | walk(store.data || {}) 52 | rewritePureUpdate(this) 53 | } else { 54 | this.page = getCurrentPages()[getCurrentPages().length - 1] 55 | this.store = this.page.store 56 | this._updatePath = getUpdatePath(store.data) 57 | syncValues(this.store.data, store.data) 58 | walk(store.data || {}) 59 | this.setData.call(this, this.store.data) 60 | rewriteUpdate(this) 61 | this.store.instances[this.page.route].push(this) 62 | } 63 | ready && ready.call(this) 64 | } 65 | Component(store) 66 | } 67 | } 68 | 69 | function syncValues(from, to){ 70 | Object.keys(to).forEach(key=>{ 71 | to[key] = from[key] 72 | }) 73 | } 74 | 75 | 76 | function getUpdatePath(data) { 77 | const result = {} 78 | dataToPath(data, result) 79 | return result 80 | } 81 | 82 | function dataToPath(data, result) { 83 | Object.keys(data).forEach(key => { 84 | result[key] = true 85 | const type = Object.prototype.toString.call(data[key]) 86 | if (type === OBJECTTYPE) { 87 | _objToPath(data[key], key, result) 88 | } else if (type === ARRAYTYPE) { 89 | _arrayToPath(data[key], key, result) 90 | } 91 | }) 92 | } 93 | 94 | function _objToPath(data, path, result) { 95 | Object.keys(data).forEach(key => { 96 | result[path + '.' + key] = true 97 | delete result[path] 98 | const type = Object.prototype.toString.call(data[key]) 99 | if (type === OBJECTTYPE) { 100 | _objToPath(data[key], path + '.' + key, result) 101 | } else if (type === ARRAYTYPE) { 102 | _arrayToPath(data[key], path + '.' + key, result) 103 | } 104 | }) 105 | } 106 | 107 | function _arrayToPath(data, path, result) { 108 | data.forEach((item, index) => { 109 | result[path + '[' + index + ']'] = true 110 | delete result[path] 111 | const type = Object.prototype.toString.call(item) 112 | if (type === OBJECTTYPE) { 113 | _objToPath(item, path + '[' + index + ']', result) 114 | } else if (type === ARRAYTYPE) { 115 | _arrayToPath(item, path + '[' + index + ']', result) 116 | } 117 | }) 118 | } 119 | 120 | function rewritePureUpdate(ctx) { 121 | ctx.update = function (patch) { 122 | const store = this.store 123 | //defineFnProp(store.data) 124 | if (patch) { 125 | for (let key in patch) { 126 | updateByPath(store.data, key, patch[key]) 127 | } 128 | } 129 | let diffResult = diff(store.data, store.originData) 130 | if (Object.keys(diffResult)[0] == '') { 131 | diffResult = diffResult[''] 132 | } 133 | if (Object.keys(diffResult).length > 0) { 134 | this.setData(diffResult) 135 | store.onChange && store.onChange(diffResult) 136 | for (let key in diffResult) { 137 | updateByPath(store.originData, key, typeof diffResult[key] === 'object' ? JSON.parse(JSON.stringify(diffResult[key])) : diffResult[key]) 138 | } 139 | } 140 | return diffResult 141 | } 142 | } 143 | 144 | function initCloud(env) { 145 | wx.cloud.init() 146 | globalStore.db = wx.cloud.database({ 147 | env: env 148 | }) 149 | } 150 | 151 | function push(patch) { 152 | return new Promise(function (resolve, reject) { 153 | _push(update(patch), resolve, reject) 154 | }) 155 | } 156 | 157 | function _push(diffResult, resolve) { 158 | const objs = diffToPushObj(diffResult) 159 | Object.keys(objs).forEach((path) => { 160 | const arr = path.split('-') 161 | const id = globalStore.data[arr[0]][parseInt(arr[1])]._id 162 | const obj = objs[path] 163 | if (globalStore.methods && globalStore.methods[arr[0]]) { 164 | Object.keys(globalStore.methods[arr[0]]).forEach(key => { 165 | if (obj.hasOwnProperty(key)) { 166 | delete obj[key] 167 | } 168 | }) 169 | } 170 | globalStore.db.collection(arr[0]).doc(id).update({ 171 | data: obj 172 | }).then((res) => { 173 | resolve(res) 174 | }) 175 | }) 176 | } 177 | 178 | function update(patch) { 179 | //defineFnProp(globalStore.data) 180 | if (patch) { 181 | for (let key in patch) { 182 | updateByPath(globalStore.data, key, patch[key]) 183 | } 184 | } 185 | let diffResult = diff(globalStore.data, originData) 186 | if (Object.keys(diffResult)[0] == '') { 187 | diffResult = diffResult[''] 188 | } 189 | const updateAll = matchGlobalData(diffResult) 190 | if (Object.keys(diffResult).length > 0) { 191 | for (let key in globalStore.instances) { 192 | globalStore.instances[key].forEach(ins => { 193 | if(updateAll || globalStore.updateAll || ins._updatePath && needUpdate(diffResult, ins._updatePath)){ 194 | ins.setData.call(ins, diffResult) 195 | } 196 | }) 197 | } 198 | globalStore.onChange && globalStore.onChange(diffResult) 199 | for (let key in diffResult) { 200 | updateByPath(originData, key, typeof diffResult[key] === 'object' ? JSON.parse(JSON.stringify(diffResult[key])) : diffResult[key]) 201 | } 202 | } 203 | return diffResult 204 | } 205 | 206 | function matchGlobalData(diffResult) { 207 | if(!globalStore.globalData) return false 208 | for (let keyA in diffResult) { 209 | if (globalStore.globalData.indexOf(keyA) > -1) { 210 | return true 211 | } 212 | for (let i = 0, len = globalStore.globalData.length; i < len; i++) { 213 | if (includePath(keyA, globalStore.globalData[i])) { 214 | return true 215 | } 216 | } 217 | } 218 | return false 219 | } 220 | 221 | function needUpdate(diffResult, updatePath){ 222 | for(let keyA in diffResult){ 223 | if(updatePath[keyA]){ 224 | return true 225 | } 226 | for(let keyB in updatePath){ 227 | if(includePath(keyA, keyB)){ 228 | return true 229 | } 230 | } 231 | } 232 | return false 233 | } 234 | 235 | function includePath(pathA, pathB){ 236 | if(pathA.indexOf(pathB)===0){ 237 | const next = pathA.substr(pathB.length, 1) 238 | if(next === '['||next === '.'){ 239 | return true 240 | } 241 | } 242 | return false 243 | } 244 | 245 | function rewriteUpdate(ctx) { 246 | ctx.update = update 247 | } 248 | 249 | function updateByPath(origin, path, value) { 250 | const arr = path.replace(/]/g, '').replace(/\[/g, '.').split('.') 251 | let current = origin 252 | for (let i = 0, len = arr.length; i < len; i++) { 253 | if (i === len - 1) { 254 | current[arr[i]] = value 255 | } else { 256 | current = current[arr[i]] 257 | } 258 | } 259 | } 260 | 261 | function pull(cn, where) { 262 | return new Promise(function (resolve) { 263 | globalStore.db.collection(cn).where(where || {}).get().then(res => { 264 | extend(res, cn) 265 | resolve(res) 266 | }) 267 | }) 268 | } 269 | 270 | function extend(res, cn) { 271 | res.data.forEach(item => { 272 | const mds = globalStore.methods[cn] 273 | mds && Object.keys(mds).forEach(key => { 274 | Object.defineProperty(item, key, { 275 | enumerable: true, 276 | get: () => { 277 | return mds[key].call(item) 278 | }, 279 | set: () => { 280 | //方法不能改写 281 | } 282 | }) 283 | }) 284 | }) 285 | } 286 | 287 | function add(cn, data) { 288 | return globalStore.db.collection(cn).add({ data }) 289 | } 290 | 291 | function remove(cn, id) { 292 | return globalStore.db.collection(cn).doc(id).remove() 293 | } 294 | 295 | function diffToPushObj(diffResult) { 296 | const result = {} 297 | Object.keys(diffResult).forEach(key => { 298 | diffItemToObj(key, diffResult[key], result) 299 | }) 300 | return result 301 | } 302 | 303 | function diffItemToObj(path, value, result) { 304 | const arr = path.replace(/]/g, '').replace(/\[/g, '.').split('.') 305 | const obj = {} 306 | let current = null 307 | const len = arr.length 308 | for (let i = 2; i < len; i++) { 309 | if (len === 3) { 310 | obj[arr[i]] = value 311 | } else { 312 | if (i === len - 1) { 313 | current[arr[i]] = value 314 | } else { 315 | const pre = current 316 | current = {} 317 | if (i === 2) { 318 | obj[arr[i]] = current 319 | } else { 320 | pre[arr[i]] = current 321 | } 322 | } 323 | } 324 | } 325 | const key = arr[0] + '-' + arr[1] 326 | result[key] = Object.assign(result[key] || {}, obj) 327 | } 328 | 329 | function extendStoreMethod() { 330 | globalStore.method = function (path, fn) { 331 | fnMapping[path] = fn 332 | let ok = getObjByPath(path) 333 | Object.defineProperty(ok.obj, ok.key, { 334 | enumerable: true, 335 | get: () => { 336 | return fnMapping[path].call(globalStore.data) 337 | }, 338 | set: () => { 339 | console.warn('Please using store.method to set method prop of data!') 340 | } 341 | }) 342 | } 343 | } 344 | 345 | function getObjByPath(path) { 346 | const arr = path.replace(/]/g, '').replace(/\[/g, '.').split('.') 347 | const len = arr.length 348 | if (len > 1) { 349 | let current = globalStore.data[arr[0]] 350 | for (let i = 1; i < len - 1; i++) { 351 | current = current[arr[i]] 352 | } 353 | return { obj: current, key: arr[len - 1] } 354 | } else { 355 | return { obj: globalStore.data, key: arr[0] } 356 | } 357 | } 358 | 359 | function walk(data) { 360 | Object.keys(data).forEach(key => { 361 | const obj = data[key] 362 | const tp = type(obj) 363 | if (tp == FUNCTIONTYPE) { 364 | setProp(key, obj) 365 | } else if (tp == OBJECTTYPE) { 366 | Object.keys(obj).forEach(subKey => { 367 | _walk(obj[subKey], key + '.' + subKey) 368 | }) 369 | 370 | } else if (tp == ARRAYTYPE) { 371 | obj.forEach((item, index) => { 372 | _walk(item, key + '[' + index + ']') 373 | }) 374 | 375 | } 376 | }) 377 | } 378 | 379 | function _walk(obj, path) { 380 | const tp = type(obj) 381 | if (tp == FUNCTIONTYPE) { 382 | setProp(path, obj) 383 | } else if (tp == OBJECTTYPE) { 384 | Object.keys(obj).forEach(subKey => { 385 | _walk(obj[subKey], path + '.' + subKey) 386 | }) 387 | 388 | } else if (tp == ARRAYTYPE) { 389 | obj.forEach((item, index) => { 390 | _walk(item, path + '[' + index + ']') 391 | }) 392 | 393 | } 394 | } 395 | 396 | function setProp(path, fn) { 397 | const ok = getObjByPath(path) 398 | fnMapping[path] = fn 399 | Object.defineProperty(ok.obj, ok.key, { 400 | enumerable: true, 401 | get: () => { 402 | return fnMapping[path].call(globalStore.data) 403 | }, 404 | set: () => { 405 | console.warn('Please using store.method to set method prop of data!') 406 | } 407 | }) 408 | } 409 | 410 | function type(obj) { 411 | return Object.prototype.toString.call(obj) 412 | } --------------------------------------------------------------------------------