relationsBehavior.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. import { debounce } from '../shared/debounce'
  2. import { throttle } from '../shared/throttle'
  3. import { isEmpty } from '../shared/isEmpty'
  4. /**
  5. * bind func to obj
  6. */
  7. function bindFunc(obj, method, observer) {
  8. const oldFn = obj[method]
  9. obj[method] = function(target) {
  10. if (observer) {
  11. observer.call(this, target, {
  12. [method]: true,
  13. })
  14. }
  15. if (oldFn) {
  16. oldFn.call(this, target)
  17. }
  18. }
  19. }
  20. // default methods
  21. const methods = ['linked', 'linkChanged', 'unlinked']
  22. // extra props
  23. const extProps = ['observer']
  24. const isNamePath = (name) => /^..\//.test(name)
  25. export default Behavior({
  26. lifetimes: {
  27. created() {
  28. this.useThrottleFn = function (fn, wait = 0, options) {
  29. const throttled = throttle(fn.bind(this), wait, options)
  30. this._throttledFns.push(throttled)
  31. return {
  32. run: throttled,
  33. cancel: throttled.cancel,
  34. flush: throttled.flush,
  35. }
  36. }
  37. this._throttledFns = []
  38. this.callDebounceFn = function(fn, wait = 0, options) {
  39. return (this._debounced = this._debounced || debounce(fn.bind(this), wait, options)).call(this)
  40. }
  41. this._debounced = null
  42. },
  43. detached() {
  44. if (this._debounced && this._debounced.cancel) {
  45. this._debounced.cancel()
  46. }
  47. if (this._throttledFns.length > 0) {
  48. this._throttledFns.forEach((throttled) => {
  49. throttled.cancel()
  50. })
  51. this._throttledFns = []
  52. }
  53. },
  54. },
  55. definitionFilter(defFields) {
  56. const { relations } = defFields
  57. if (!isEmpty(relations)) {
  58. for (const key in relations) {
  59. const relation = relations[key]
  60. // bind func
  61. methods.forEach((method) => bindFunc(relation, method, relation.observer))
  62. // delete extProps
  63. extProps.forEach((prop) => delete relation[prop])
  64. }
  65. }
  66. Object.assign(defFields.methods = (defFields.methods || {}), {
  67. getRelations: function(types = ['parent', 'child', 'ancestor', 'descendant']) {
  68. if (!isEmpty(relations)) {
  69. return Object.keys(relations)
  70. .map((key) => {
  71. if (relations[key] && types.includes(relations[key].type)) {
  72. return key
  73. }
  74. return null
  75. })
  76. .filter((name) => !!name)
  77. .map((name) => this.getRelationsByName(name)[0])
  78. .filter((node) => !!node)
  79. }
  80. return []
  81. },
  82. getRelationsByName(name) {
  83. return this.getRelationNodes(isNamePath(name) ? name : `../${name}/index`)
  84. },
  85. getRelationsByType(type) {
  86. return this.getRelations([type])
  87. },
  88. querySelector(selector) {
  89. return this.selectComponent(selector)
  90. },
  91. querySelectorAll(selector) {
  92. return this.selectAllComponents(selector)
  93. },
  94. })
  95. },
  96. })