瀏覽代碼

add wxstore

zjxpcyc 6 年之前
父節點
當前提交
cffddb4ca9
共有 8 個檔案被更改,包括 601 行新增91 行删除
  1. 8
    3
      app.js
  2. 18
    69
      pages/UserCenter/UserInfo/index.js
  3. 7
    18
      pages/UserCenter/UserInfo/index.wxml
  4. 5
    1
      pages/UserCenter/UserInfo/index.wxss
  5. 2
    0
      project.config.json
  6. 6
    0
      store.js
  7. 449
    0
      utils/create.js
  8. 106
    0
      utils/diff.js

+ 8
- 3
app.js 查看文件

13
   },
13
   },
14
   globalData: {
14
   globalData: {
15
     UserInfo: {
15
     UserInfo: {
16
-      UserIcon: '/assets/images/img4.jpg',
17
-      UserName: '用户名',
18
-      UserPhone: '18267901393'
16
+      customerId: 1,
17
+      customerName: '',
18
+      name: '',
19
+      phone: '',
20
+      idNum: '',
21
+      remark: '',
22
+      openid: '',
23
+      avatar: '',
19
     },
24
     },
20
     ScreenBottomHeight: 0
25
     ScreenBottomHeight: 0
21
   }
26
   }

+ 18
- 69
pages/UserCenter/UserInfo/index.js 查看文件

1
-//index.js
2
-//获取应用实例
1
+import store from '../../../store'
2
+import create from '../../../utils/create'
3
+
3
 const app = getApp()
4
 const app = getApp()
4
 
5
 
5
-Page({
6
+create(store, {
7
+  data: {
8
+    UserInfo: app.globalData.UserInfo, // 用户信息
9
+    loadding: false, // 表单验重提交开关
10
+  },
6
   onReady() {
11
   onReady() {
7
     wx.setNavigationBarTitle({
12
     wx.setNavigationBarTitle({
8
       title: '个人资料'
13
       title: '个人资料'
9
     })
14
     })
10
   },
15
   },
11
-  data: {
12
-    UserInfo: app.globalData.UserInfo, // 用户信息
13
-    FormOff: true, // 表单验重提交开关
14
-    FormData: { // 提交数据
15
-      UserIcon: '/assets/images/img1.jpg', // 用户头像
16
-      NickName: '示例昵称', // 昵称
17
-      PhoneNum: '18267901393', // 绑定手机号
18
-      CardNum: '346555212451214544', // 证件号码
19
-      CityId: '1' // 所属城市id
20
-    },
21
-    TriggerSelectCity: false, // 显隐选择城市控件
22
-    CityName: '南京', // 所属城市名称
23
-    CityList: [{
24
-      value: '南京',
25
-      id: '1'
26
-    }, {
27
-      value: '上海',
28
-      id: '2'
29
-    }, {
30
-      value: '苏州',
31
-      id: '3'
32
-    }]
33
-  },
34
-  SaveForm() { // 提交表单数据
35
-    if (this.data.FormOff) {
16
+  SaveUserInfo() { // 提交表单数据
17
+    if (!this.data.loadding) {
36
       this.setData({
18
       this.setData({
37
-        FormOff: false
19
+        loadding: true
38
       })
20
       })
39
     }
21
     }
40
   },
22
   },
41
-  SelectCityConfirm(e) { // 确认选择城市
42
-    this.setData({
43
-      FormData: {
44
-        ...this.data.FormData,
45
-        CityId: e.detail.value.id
46
-      },
47
-      CityName: e.detail.value.value,
48
-      TriggerSelectCity: false
49
-    })
50
-  },
51
-  SelectCityCancel() { // 取消选择城市
52
-    this.setData({
53
-      TriggerSelectCity: false
54
-    })
55
-  },
56
-  SelectCity() { // 打开城市选择器
57
-    this.setData({
58
-      TriggerSelectCity: true
59
-    })
60
-  },
61
   FormInput(e) { // 表单输入数据绑定
23
   FormInput(e) { // 表单输入数据绑定
24
+    const key = e.target.dataset.name
25
+    const val = e.detail.value
26
+    
62
     this.setData({
27
     this.setData({
63
-      FormData: {
64
-        ...this.data.FormData,
65
-        [e.target.dataset.name]: e.detail.value
66
-      }
67
-    })
68
-  },
69
-  UpdateIcon() { // 更换头像
70
-    let _self = this
71
-    wx.chooseImage({
72
-      count: 1,
73
-      sizeType: ['original', 'compressed'],
74
-      sourceType: ['album', 'camera'],
75
-      success(res) {
76
-        _self.setData({
77
-          FormData: {
78
-            ..._self.data.FormData,
79
-            UserIcon: res.tempFilePaths
80
-          }
81
-        })
28
+      UserInfo: {
29
+        ...this.data.UserInfo,
30
+        [`${key}`]: val,
82
       }
31
       }
83
     })
32
     })
84
   }
33
   }
85
-})
34
+})

+ 7
- 18
pages/UserCenter/UserInfo/index.wxml 查看文件

4
     <view class="flex-h" style="padding: 16rpx 50rpx;">
4
     <view class="flex-h" style="padding: 16rpx 50rpx;">
5
       <text>头像</text>
5
       <text>头像</text>
6
       <view class="flex-item"></view>
6
       <view class="flex-item"></view>
7
-      <view class="userIcon" bindtap="UpdateIcon">
8
-        <image mode="aspectFill" src="{{FormData.UserIcon}}" class="centerLabel cover"></image>
7
+      <view class="userIcon">
8
+        <image mode="aspectFill" src="{{UserInfo.avatar}}" class="centerLabel cover"></image>
9
       </view>
9
       </view>
10
     </view>
10
     </view>
11
     <view class="flex-h">
11
     <view class="flex-h">
12
       <text>昵称</text>
12
       <text>昵称</text>
13
       <view class="flex-item">
13
       <view class="flex-item">
14
-        <input value="{{FormData.NickName}}" data-name="NickName" bindinput="FormInput"></input>
14
+        <input value="{{UserInfo.name}}" data-name="name" bindinput="FormInput"></input>
15
       </view>
15
       </view>
16
     </view>
16
     </view>
17
   </view>
17
   </view>
19
     <view class="flex-h">
19
     <view class="flex-h">
20
       <text>绑定手机号</text>
20
       <text>绑定手机号</text>
21
       <view class="flex-item">
21
       <view class="flex-item">
22
-        <input type="number" value="{{FormData.PhoneNum}}" data-name="PhoneNum" bindinput="FormInput"></input>
22
+        <input type="number" value="{{UserInfo.phone}}" data-name="phone" bindinput="FormInput"></input>
23
       </view>
23
       </view>
24
     </view>
24
     </view>
25
     <view class="flex-h">
25
     <view class="flex-h">
26
       <text>证件号码</text>
26
       <text>证件号码</text>
27
       <view class="flex-item">
27
       <view class="flex-item">
28
-        <input type="idcard" value="{{FormData.CardNum}}" data-name="CardNum" bindinput="FormInput"></input>
28
+        <input type="idcard" value="{{UserInfo.idNum}}" data-name="idNum" bindinput="FormInput"></input>
29
       </view>
29
       </view>
30
     </view>
30
     </view>
31
-    <view class="flex-h" bindtap="SelectCity">
32
-      <text>城市</text>
33
-      <view class="flex-item"></view>
34
-      <text>{{CityName}}</text>
35
-      <image mode="widthFix" src="/assets/images/icon11.png" style="width: 16rpx;"></image>
36
-    </view>
37
   </view>
31
   </view>
38
-  <view class="btn" bindtap="SaveUserInfo">
39
-    <text bindtap="SaveForm">保存</text>
40
-  </view>
41
-  <view class="popup" hidden="{{!TriggerSelectCity}}">
42
-    <view>
43
-      <van-picker show-toolbar columns="{{ CityList }}" value-key="value" bind:cancel="SelectCityCancel" bind:confirm="SelectCityConfirm" />
44
-    </view>
32
+  <view class="btn {{ !loadding && 'active' }}" bindtap="SaveUserInfo">
33
+    <text>保存</text>
45
   </view>
34
   </view>
46
 </view>
35
 </view>

+ 5
- 1
pages/UserCenter/UserInfo/index.wxss 查看文件

68
   color: #fff;
68
   color: #fff;
69
   line-height: 88rpx;
69
   line-height: 88rpx;
70
   font-size: 28rpx;
70
   font-size: 28rpx;
71
-  background: #bb9c79;
71
+  background-color: #ccc;
72
   border-radius: 10rpx;
72
   border-radius: 10rpx;
73
 }
73
 }
74
 
74
 
75
+.btn.active text {
76
+  background: #bb9c79;
77
+}
78
+
75
 .popup {
79
 .popup {
76
   width: 100%;
80
   width: 100%;
77
   position: absolute;
81
   position: absolute;

+ 2
- 0
project.config.json 查看文件

19
 		"hidedInDevtools": []
19
 		"hidedInDevtools": []
20
 	},
20
 	},
21
 	"isGameTourist": false,
21
 	"isGameTourist": false,
22
+	"simulatorType": "wechat",
23
+	"simulatorPluginLibVersion": {},
22
 	"condition": {
24
 	"condition": {
23
 		"search": {
25
 		"search": {
24
 			"current": -1,
26
 			"current": -1,

+ 6
- 0
store.js 查看文件

1
+// 本文件不要删除
2
+
3
+export default {
4
+  data: {},
5
+  globalData: {},
6
+}

+ 449
- 0
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 (!originData) {
15
+            originData = JSON.parse(JSON.stringify(store.data))
16
+            globalStore = store
17
+            store.instances = {}
18
+            store.update = update
19
+            store.push = push
20
+            store.pull = pull
21
+            store.add = add
22
+            store.remove = remove
23
+            store.originData = originData
24
+            store.env && initCloud(store.env)
25
+            extendStoreMethod(store)
26
+        }
27
+        getApp().globalData && (getApp().globalData.store = store)
28
+        //option.data = store.data
29
+        const onLoad = option.onLoad
30
+        walk(store.data)
31
+        // 解决函数属性初始化不能显示的问题,要求必须在data中声明使用
32
+        // 这段代码是同步store.data到option.data,只有经过walk方法后store.data中的函数才能变成属性,才能被小程序page方法渲染
33
+        if (option.data && Object.keys(option.data).length > 0) {
34
+            updatePath = getUpdatePath(option.data)
35
+            syncValues(store.data, option.data)
36
+        }
37
+        option.onLoad = function (e) {
38
+            this.store = store
39
+            this._updatePath = updatePath
40
+            rewriteUpdate(this)
41
+            store.instances[this.route] = []
42
+            store.instances[this.route].push(this)
43
+            onLoad && onLoad.call(this, e)
44
+            syncValues(store.data, this.data)
45
+            this.setData(this.data)
46
+        }
47
+	
48
+	// 解决执行navigateBack或reLaunch时清除store.instances对应页面的实例
49
+	const onUnload = option.onUnload
50
+        option.onUnload = function () {
51
+            onUnload && onUnload.call(this)
52
+            store.instances[this.route] = []
53
+        }
54
+
55
+        Page(option)
56
+    } else {
57
+        const ready = store.ready
58
+        const pure = store.pure
59
+        const componentUpdatePath = getUpdatePath(store.data)
60
+        store.ready = function () {
61
+            if (pure) {
62
+                this.store = { data: store.data || {} }
63
+                this.store.originData = store.data ? JSON.parse(JSON.stringify(store.data)) : {}
64
+                walk(store.data || {})
65
+                rewritePureUpdate(this)
66
+            } else {
67
+                this.page = getCurrentPages()[getCurrentPages().length - 1]
68
+                this.store = this.page.store
69
+                this._updatePath = componentUpdatePath
70
+                syncValues(this.store.data, store.data)
71
+                walk(store.data || {})
72
+                this.setData.call(this, this.store.data)
73
+                rewriteUpdate(this)
74
+                this.store.instances[this.page.route].push(this)
75
+            }
76
+            ready && ready.call(this)
77
+        }
78
+        Component(store)
79
+    }
80
+}
81
+
82
+function syncValues(from, to){
83
+    Object.keys(to).forEach(key=>{
84
+        if(from.hasOwnProperty(key)){
85
+            to[key] = from[key]
86
+        }
87
+    })
88
+}
89
+
90
+
91
+function getUpdatePath(data) {
92
+	const result = {}
93
+    dataToPath(data, result)
94
+	return result
95
+}
96
+
97
+function dataToPath(data, result) {
98
+	Object.keys(data).forEach(key => {
99
+		result[key] = true
100
+		const type = Object.prototype.toString.call(data[key])
101
+		if (type === OBJECTTYPE) {
102
+			_objToPath(data[key], key, result)
103
+		} else if (type === ARRAYTYPE) {
104
+			_arrayToPath(data[key], key, result)
105
+		}
106
+	})
107
+}
108
+
109
+function _objToPath(data, path, result) {
110
+	Object.keys(data).forEach(key => {
111
+		result[path + '.' + key] = true
112
+		delete result[path]
113
+		const type = Object.prototype.toString.call(data[key])
114
+		if (type === OBJECTTYPE) {
115
+			_objToPath(data[key], path + '.' + key, result)
116
+		} else if (type === ARRAYTYPE) {
117
+			_arrayToPath(data[key], path + '.' + key, result)
118
+		}
119
+	})
120
+}
121
+
122
+function _arrayToPath(data, path, result) {
123
+	data.forEach((item, index) => {
124
+		result[path + '[' + index + ']'] = true
125
+		delete result[path]
126
+		const type = Object.prototype.toString.call(item)
127
+		if (type === OBJECTTYPE) {
128
+			_objToPath(item, path + '[' + index + ']', result)
129
+		} else if (type === ARRAYTYPE) {
130
+			_arrayToPath(item, path + '[' + index + ']', result)
131
+		}
132
+	})
133
+}
134
+
135
+function rewritePureUpdate(ctx) {
136
+    ctx.update = function (patch) {
137
+        const store = this.store
138
+        const that = this
139
+        return new Promise(resolve => {
140
+            //defineFnProp(store.data)
141
+            if (patch) {
142
+                for (let key in patch) {
143
+                    updateByPath(store.data, key, patch[key])
144
+                }
145
+            }
146
+            let diffResult = diff(store.data, store.originData)
147
+            let array = []
148
+            if (Object.keys(diffResult)[0] == '') {
149
+                diffResult = diffResult['']
150
+            }
151
+            if (Object.keys(diffResult).length > 0) {
152
+                array.push( new Promise( cb => that.setData(diffResult, cb) ) )
153
+                store.onChange && store.onChange(diffResult)
154
+                for (let key in diffResult) {
155
+                    updateByPath(store.originData, key, typeof diffResult[key] === 'object' ? JSON.parse(JSON.stringify(diffResult[key])) : diffResult[key])
156
+                }
157
+            }
158
+            Promise.all(array).then( e => resolve(diffResult) )
159
+        })
160
+    }
161
+}
162
+
163
+function initCloud(env) {
164
+    wx.cloud.init()
165
+    globalStore.db = wx.cloud.database({
166
+        env: env
167
+    })
168
+}
169
+
170
+function push(patch) {
171
+    return new Promise(function (resolve, reject) {
172
+        _push(update(patch), resolve, reject)
173
+    })
174
+}
175
+
176
+function _push(diffResult, resolve) {
177
+    const objs = diffToPushObj(diffResult)
178
+    Object.keys(objs).forEach((path) => {
179
+        const arr = path.split('-')
180
+        const id = globalStore.data[arr[0]][parseInt(arr[1])]._id
181
+        const obj = objs[path]
182
+        if (globalStore.methods && globalStore.methods[arr[0]]) {
183
+            Object.keys(globalStore.methods[arr[0]]).forEach(key => {
184
+                if (obj.hasOwnProperty(key)) {
185
+                    delete obj[key]
186
+                }
187
+            })
188
+        }
189
+        globalStore.db.collection(arr[0]).doc(id).update({
190
+            data: obj
191
+        }).then((res) => {
192
+            resolve(res)
193
+        })
194
+    })
195
+}
196
+
197
+function update(patch) {
198
+    return new Promise(resolve => {
199
+        //defineFnProp(globalStore.data)
200
+        if (patch) {
201
+            for (let key in patch) {
202
+                updateByPath(globalStore.data, key, patch[key])
203
+            }
204
+        }
205
+        let diffResult = diff(globalStore.data, originData)
206
+        if (Object.keys(diffResult)[0] == '') {
207
+            diffResult = diffResult['']
208
+        }
209
+        const updateAll = matchGlobalData(diffResult)
210
+        let array = []
211
+        if (Object.keys(diffResult).length > 0) {
212
+            for (let key in globalStore.instances) {
213
+                globalStore.instances[key].forEach(ins => {
214
+                    if(updateAll || globalStore.updateAll || ins._updatePath){
215
+                        // 获取需要更新的字段
216
+                        const needUpdatePathList = getNeedUpdatePathList(diffResult, ins._updatePath)
217
+                        if (needUpdatePathList.length) {
218
+                            const _diffResult = {}
219
+                            for (let _path in diffResult) {
220
+                                if (needUpdatePathList.includes(_path)) {
221
+                                    _diffResult[_path] = diffResult[_path]
222
+                                }
223
+                            }
224
+                            array.push( new Promise(cb => {
225
+                                ins.setData.call(ins, _diffResult, cb)
226
+                            }) )
227
+                        }
228
+                    }
229
+                })
230
+            }
231
+            globalStore.onChange && globalStore.onChange(diffResult)
232
+            for (let key in diffResult) {
233
+                updateByPath(originData, key, typeof diffResult[key] === 'object' ? JSON.parse(JSON.stringify(diffResult[key])) : diffResult[key])
234
+            }
235
+        }
236
+        Promise.all(array).then(e=>{
237
+            resolve(diffResult)
238
+        })
239
+    })
240
+}
241
+
242
+function matchGlobalData(diffResult) {
243
+    if(!globalStore.globalData) return false
244
+    for (let keyA in diffResult) {
245
+        if (globalStore.globalData.indexOf(keyA) > -1) {
246
+            return true
247
+        }
248
+        for (let i = 0, len = globalStore.globalData.length; i < len; i++) {
249
+            if (includePath(keyA, globalStore.globalData[i])) {
250
+                return true
251
+            }
252
+        }
253
+    }
254
+    return false
255
+}
256
+
257
+function getNeedUpdatePathList(diffResult, updatePath){
258
+    const paths = []
259
+    for(let keyA in diffResult){
260
+        if(updatePath[keyA]){
261
+            paths.push(keyA)
262
+        }
263
+        for(let keyB in updatePath){
264
+            if(includePath(keyA, keyB)){
265
+                paths.push(keyA)
266
+            }
267
+        }
268
+    }
269
+    return paths
270
+}
271
+
272
+function includePath(pathA, pathB){
273
+    if(pathA.indexOf(pathB)===0){
274
+        const next = pathA.substr(pathB.length, 1)
275
+        if(next === '['||next === '.'){
276
+            return true
277
+        }
278
+    }
279
+    return false
280
+}
281
+
282
+function rewriteUpdate(ctx) {
283
+    ctx.update = update
284
+}
285
+
286
+function updateByPath(origin, path, value) {
287
+    const arr = path.replace(/]/g, '').replace(/\[/g, '.').split('.')
288
+    let current = origin
289
+    for (let i = 0, len = arr.length; i < len; i++) {
290
+        if (i === len - 1) {
291
+            current[arr[i]] = value
292
+        } else {
293
+            current = current[arr[i]]
294
+        }
295
+    }
296
+}
297
+
298
+function pull(cn, where) {
299
+    return new Promise(function (resolve) {
300
+        globalStore.db.collection(cn).where(where || {}).get().then(res => {
301
+            extend(res, cn)
302
+            resolve(res)
303
+        })
304
+    })
305
+}
306
+
307
+function extend(res, cn) {
308
+    res.data.forEach(item => {
309
+        const mds = globalStore.methods[cn]
310
+        mds && Object.keys(mds).forEach(key => {
311
+            Object.defineProperty(item, key, {
312
+                enumerable: true,
313
+                get: () => {
314
+                    return mds[key].call(item)
315
+                },
316
+                set: () => {
317
+                    //方法不能改写
318
+                }
319
+            })
320
+        })
321
+    })
322
+}
323
+
324
+function add(cn, data) {
325
+    return globalStore.db.collection(cn).add({ data })
326
+}
327
+
328
+function remove(cn, id) {
329
+    return globalStore.db.collection(cn).doc(id).remove()
330
+}
331
+
332
+function diffToPushObj(diffResult) {
333
+    const result = {}
334
+    Object.keys(diffResult).forEach(key => {
335
+        diffItemToObj(key, diffResult[key], result)
336
+    })
337
+    return result
338
+}
339
+
340
+function diffItemToObj(path, value, result) {
341
+    const arr = path.replace(/]/g, '').replace(/\[/g, '.').split('.')
342
+    const obj = {}
343
+    let current = null
344
+    const len = arr.length
345
+    for (let i = 2; i < len; i++) {
346
+        if (len === 3) {
347
+            obj[arr[i]] = value
348
+        } else {
349
+            if (i === len - 1) {
350
+                current[arr[i]] = value
351
+            } else {
352
+                const pre = current
353
+                current = {}
354
+                if (i === 2) {
355
+                    obj[arr[i]] = current
356
+                } else {
357
+                    pre[arr[i]] = current
358
+                }
359
+            }
360
+        }
361
+    }
362
+    const key = arr[0] + '-' + arr[1]
363
+    result[key] = Object.assign(result[key] || {}, obj)
364
+}
365
+
366
+function extendStoreMethod() {
367
+    globalStore.method = function (path, fn) {
368
+        fnMapping[path] = fn
369
+        let ok = getObjByPath(path)
370
+        Object.defineProperty(ok.obj, ok.key, {
371
+            enumerable: true,
372
+            get: () => {
373
+                return fnMapping[path].call(globalStore.data)
374
+            },
375
+            set: () => {
376
+                console.warn('Please using store.method to set method prop of data!')
377
+            }
378
+        })
379
+    }
380
+}
381
+
382
+function getObjByPath(path) {
383
+    const arr = path.replace(/]/g, '').replace(/\[/g, '.').split('.')
384
+    const len = arr.length
385
+    if (len > 1) {
386
+        let current = globalStore.data[arr[0]]
387
+        for (let i = 1; i < len - 1; i++) {
388
+            current = current[arr[i]]
389
+        }
390
+        return { obj: current, key: arr[len - 1] }
391
+    } else {
392
+        return { obj: globalStore.data, key: arr[0] }
393
+    }
394
+}
395
+
396
+function walk(data) {
397
+    Object.keys(data).forEach(key => {
398
+        const obj = data[key]
399
+        const tp = type(obj)
400
+        if (tp == FUNCTIONTYPE) {
401
+            setProp(key, obj)
402
+        } else if (tp == OBJECTTYPE) {
403
+            Object.keys(obj).forEach(subKey => {
404
+                _walk(obj[subKey], key + '.' + subKey)
405
+            })
406
+
407
+        } else if (tp == ARRAYTYPE) {
408
+            obj.forEach((item, index) => {
409
+                _walk(item, key + '[' + index + ']')
410
+            })
411
+
412
+        }
413
+    })
414
+}
415
+
416
+function _walk(obj, path) {
417
+    const tp = type(obj)
418
+    if (tp == FUNCTIONTYPE) {
419
+        setProp(path, obj)
420
+    } else if (tp == OBJECTTYPE) {
421
+        Object.keys(obj).forEach(subKey => {
422
+            _walk(obj[subKey], path + '.' + subKey)
423
+        })
424
+
425
+    } else if (tp == ARRAYTYPE) {
426
+        obj.forEach((item, index) => {
427
+            _walk(item, path + '[' + index + ']')
428
+        })
429
+
430
+    }
431
+}
432
+
433
+function setProp(path, fn) {
434
+    const ok = getObjByPath(path)
435
+    fnMapping[path] = fn
436
+    Object.defineProperty(ok.obj, ok.key, {
437
+        enumerable: true,
438
+        get: () => {
439
+            return fnMapping[path].call(globalStore.data)
440
+        },
441
+        set: () => {
442
+            console.warn('Please using store.method to set method prop of data!')
443
+        }
444
+    })
445
+}
446
+
447
+function type(obj) {
448
+    return Object.prototype.toString.call(obj)
449
+}

+ 106
- 0
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 && path !== '') {
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
+}