watch.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. class Watch {
  2. constructor(that, watchData) {
  3. // watch函数回调集合
  4. that.$_watchCallBack = {}
  5. // 绑定到指定对象
  6. that.$watch = this.$watch;
  7. that.$emit = this.$emit;
  8. that.$get = this.$get;
  9. that.$behavior = this.$behavior();
  10. that.$_watch = this.$_watch;
  11. that.$_remove = this.$_remove;
  12. that.$_autoRemove = this.$_autoRemove;
  13. // 设置监听对象
  14. this._setWatchData(that, watchData);
  15. }
  16. /**
  17. * 设置被监听的对象
  18. * @that {Object} this对象
  19. * @watchData {object} 被监听的对象
  20. */
  21. _setWatchData(that, watchData) {
  22. if (that && watchData) {
  23. that.$watchData = Object.assign({}, watchData)
  24. } else {
  25. throw new Error('请输入正确的初始值')
  26. }
  27. }
  28. /**
  29. * 设置监听
  30. * @obj {Object} 将要监听的对象
  31. * @callbackArray {Array} 回调函数集合
  32. *
  33. */
  34. $_watch(key, value, callback) {
  35. const obj = this.$watchData;
  36. let _oldValue = obj[key];
  37. obj[key] = value;
  38. // 确认回调函数存在 循环执行回调数组的方法集合
  39. if (typeof _oldValue === 'object' && typeof value === 'object') {
  40. this.$_watchCallBack[key] && this.$_watchCallBack[key].forEach(val => val && val.cb && val.cb.call(val.page, value, _oldValue))
  41. } else {
  42. // 两次相同的值不执行
  43. _oldValue !== value && this.$_watchCallBack[key] && this.$_watchCallBack[key].forEach(val => val && val.cb && val.cb.call(val.page, value, _oldValue))
  44. }
  45. callback && callback()
  46. }
  47. /**
  48. * 提交值
  49. * @key {String} 提交的键值
  50. * @value {any} 提交的值
  51. * @callback {function} 执行之后完成回调
  52. */
  53. $emit(key, value, callback) {
  54. // 不提交未设置字段 减少消耗
  55. if (!this.$watchData.hasOwnProperty(key)) {
  56. throw new Error('未设置此字段')
  57. }
  58. // 不可传值为function、null、undefined以及NaN
  59. if (typeof value === 'function' || typeof value === 'undefined' || value === null || Number.isNaN(value)) {
  60. throw new Error(`${key}-${value}为非法参数传值`)
  61. }
  62. this.$_watch(key, value, callback);
  63. }
  64. /**
  65. * 获取值
  66. * @key {String} 获取的键值
  67. * @callback {function} 获取之后执行回调函数
  68. */
  69. $get(key, callback) {
  70. callback && callback(this.$watchData[key]);
  71. return this.$watchData[key]
  72. }
  73. /**
  74. * 添加watch方法
  75. * @key {String} 要观察的键值
  76. * @page {Object} 需监听的页面
  77. * @callback {function} 需要执行的回调函数
  78. *
  79. */
  80. $watch(key, page, callback) {
  81. // 首先检测 $_watchCallBack 中对应的值是否存在 如果存在就推入方法
  82. this.$_watchCallBack = Object.assign({}, this.$_watchCallBack, {
  83. [key]: this.$_watchCallBack[key] || []
  84. });
  85. // 判断页面是否存入过该方法 若存入过则更改回调方法 否则推入函数
  86. let _index = this.$_watchCallBack[key].findIndex(val => val.name === page.__wxExparserNodeId__);
  87. if (_index === -1) {
  88. console.info(`${page.is} watch=>`, key)
  89. // 添加自动移除的方法
  90. page = this.$_autoRemove(key, page)
  91. // 推入新的监听事件
  92. this.$_watchCallBack[key].push({
  93. name: page.__wxExparserNodeId__,
  94. page,
  95. cb: callback
  96. })
  97. } else {
  98. // 存在则改写回调函数
  99. this.$_watchCallBack[key][_index].cb = callback;
  100. }
  101. }
  102. /**
  103. * 移除监听事件
  104. * @key {String} 需要移除监听的键值
  105. * @page {Object} 需移除监听的页面
  106. * @callback {function} 移除监听完成的回调函数
  107. */
  108. $_remove(key, page, callback) {
  109. // 获取索引
  110. let _index = this.$_watchCallBack[key].findIndex(val => val.name === page.__wxExparserNodeId__);
  111. if (_index !== -1) {
  112. // 移除监听
  113. let _item = this.$_watchCallBack[key].splice(_index, 1);
  114. if (_item) {
  115. // console.log('remove', key, page)
  116. // 确认函数存在 执行回调函数
  117. callback && callback.call(page)
  118. }
  119. }
  120. }
  121. /**
  122. * 自动移除监听
  123. * @key {String} 移除的键值
  124. * @page {Object} 移除的页面
  125. */
  126. $_autoRemove(key, page) {
  127. // 如果是页面则重载onUnload 函数
  128. if (page.route) {
  129. let _onUnload = page.onUnload;
  130. page.onUnload = () => {
  131. this.$_remove(key, page, () => {
  132. console.info(`${page.is} remove=>`, key)
  133. _onUnload()
  134. })
  135. };
  136. return page;
  137. } else {
  138. // 自定义组件使用behaviors移除 将监听字段赋值给$$_watch
  139. page.$$_watch = key;
  140. return page;
  141. }
  142. }
  143. /**
  144. * 组件Behavior方法 需自行引入组件的behaviors
  145. */
  146. $behavior() {
  147. return Behavior({
  148. detached() {
  149. let key = this.$$_watch;
  150. wx.$_remove(this.$$_watch, this, () => {
  151. console.info(`${this.is} remove=>`, key)
  152. })
  153. },
  154. })
  155. }
  156. }
  157. module.exports = {
  158. Watch: Watch
  159. }