render.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. import createElement from '../vdom/create-element'
  2. import { flatten } from '../vdom/helpers'
  3. import { bind, resolveAsset, isArray, isObject } from '../util/index'
  4. export const renderState = {
  5. activeInstance: null
  6. }
  7. export function initRender (vm) {
  8. vm._vnode = null
  9. vm._mounted = false
  10. vm.$slots = {}
  11. // bind the public createElement fn to this instance
  12. // so that we get proper render context inside it.
  13. vm.$createElement = bind(createElement, vm)
  14. if (vm.$options.el) {
  15. vm.$mount(vm.$options.el)
  16. }
  17. }
  18. export function renderMixin (Vue) {
  19. Vue.prototype._render = function () {
  20. const prev = renderState.activeInstance
  21. renderState.activeInstance = this
  22. const { render, _renderChildren } = this.$options
  23. // resolve slots. becaues slots are rendered in parent scope,
  24. // we set the activeInstance to parent.
  25. if (_renderChildren) {
  26. resolveSlots(this, _renderChildren)
  27. }
  28. // render self
  29. const vnode = render.call(this._renderProxy)
  30. // restore render state
  31. renderState.activeInstance = prev
  32. return vnode
  33. }
  34. // shorthands used in render functions
  35. Vue.prototype.__h__ = createElement
  36. // resolve directive
  37. Vue.prototype.__resolveDirective__ = function (id) {
  38. return resolveAsset(this.$options, 'directives', id, true)
  39. }
  40. // resolve transition
  41. Vue.prototype.__resolveTransition__ = function (id) {
  42. return id && typeof id === 'string'
  43. ? resolveAsset(this.$options, 'transitions', id) || id
  44. : id
  45. }
  46. // toString for mustaches
  47. Vue.prototype.__toString__ = function (val) {
  48. return val == null
  49. ? ''
  50. : typeof val === 'object'
  51. ? JSON.stringify(val, null, 2)
  52. : val
  53. }
  54. // render v-for
  55. Vue.prototype.__renderList__ = function (val, render) {
  56. let ret, i, l, keys, key
  57. if (isArray(val)) {
  58. ret = new Array(val.length)
  59. for (i = 0, l = val.length; i < l; i++) {
  60. ret[i] = render(val[i], i, i)
  61. }
  62. } else if (typeof val === 'number') {
  63. ret = new Array(val)
  64. for (i = 0; i < val; i++) {
  65. ret[i] = render(i + 1, i, i)
  66. }
  67. } else if (isObject(val)) {
  68. keys = Object.keys(val)
  69. ret = new Array(keys.length)
  70. for (i = 0, l = keys.length; i < l; i++) {
  71. key = keys[i]
  72. ret[i] = render(val[key], i, key)
  73. }
  74. }
  75. return ret
  76. }
  77. // register ref
  78. Vue.prototype.__registerRef__ = function (key, ref, vFor, remove) {
  79. const refs = this.$refs
  80. if (remove) {
  81. if (vFor) {
  82. refs[key].$remove(ref)
  83. } else {
  84. refs[key] = undefined
  85. }
  86. } else {
  87. if (vFor) {
  88. if (refs[key]) {
  89. refs[key].push(ref)
  90. } else {
  91. refs[key] = [ref]
  92. }
  93. } else {
  94. refs[key] = ref
  95. }
  96. }
  97. }
  98. }
  99. function resolveSlots (vm, children) {
  100. if (children) {
  101. children = flatten(isArray(children) ? children : children())
  102. const slots = { default: children }
  103. let i = children.length
  104. let name, child
  105. while (i--) {
  106. child = children[i]
  107. if ((name = child.data && child.data.slot)) {
  108. let slot = (slots[name] || (slots[name] = []))
  109. if (child.tag === 'template') {
  110. slot.push.apply(slot, child.children)
  111. } else {
  112. slot.push(child)
  113. }
  114. children.splice(i, 1)
  115. }
  116. }
  117. vm.$slots = slots
  118. }
  119. }