github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/public/libs/vue-1.0.24/src/fragment/fragment.js (about) 1 import { 2 createAnchor, 3 before, 4 prepend, 5 inDoc, 6 mapNodeRange, 7 removeNodeRange 8 } from '../util/index' 9 10 import { 11 beforeWithTransition, 12 removeWithTransition 13 } from '../transition/index' 14 15 /** 16 * Abstraction for a partially-compiled fragment. 17 * Can optionally compile content with a child scope. 18 * 19 * @param {Function} linker 20 * @param {Vue} vm 21 * @param {DocumentFragment} frag 22 * @param {Vue} [host] 23 * @param {Object} [scope] 24 * @param {Fragment} [parentFrag] 25 */ 26 27 export default function Fragment (linker, vm, frag, host, scope, parentFrag) { 28 this.children = [] 29 this.childFrags = [] 30 this.vm = vm 31 this.scope = scope 32 this.inserted = false 33 this.parentFrag = parentFrag 34 if (parentFrag) { 35 parentFrag.childFrags.push(this) 36 } 37 this.unlink = linker(vm, frag, host, scope, this) 38 var single = this.single = 39 frag.childNodes.length === 1 && 40 // do not go single mode if the only node is an anchor 41 !(frag.childNodes[0].__v_anchor) 42 if (single) { 43 this.node = frag.childNodes[0] 44 this.before = singleBefore 45 this.remove = singleRemove 46 } else { 47 this.node = createAnchor('fragment-start') 48 this.end = createAnchor('fragment-end') 49 this.frag = frag 50 prepend(this.node, frag) 51 frag.appendChild(this.end) 52 this.before = multiBefore 53 this.remove = multiRemove 54 } 55 this.node.__v_frag = this 56 } 57 58 /** 59 * Call attach/detach for all components contained within 60 * this fragment. Also do so recursively for all child 61 * fragments. 62 * 63 * @param {Function} hook 64 */ 65 66 Fragment.prototype.callHook = function (hook) { 67 var i, l 68 for (i = 0, l = this.childFrags.length; i < l; i++) { 69 this.childFrags[i].callHook(hook) 70 } 71 for (i = 0, l = this.children.length; i < l; i++) { 72 hook(this.children[i]) 73 } 74 } 75 76 /** 77 * Insert fragment before target, single node version 78 * 79 * @param {Node} target 80 * @param {Boolean} withTransition 81 */ 82 83 function singleBefore (target, withTransition) { 84 this.inserted = true 85 var method = withTransition !== false 86 ? beforeWithTransition 87 : before 88 method(this.node, target, this.vm) 89 if (inDoc(this.node)) { 90 this.callHook(attach) 91 } 92 } 93 94 /** 95 * Remove fragment, single node version 96 */ 97 98 function singleRemove () { 99 this.inserted = false 100 var shouldCallRemove = inDoc(this.node) 101 var self = this 102 this.beforeRemove() 103 removeWithTransition(this.node, this.vm, function () { 104 if (shouldCallRemove) { 105 self.callHook(detach) 106 } 107 self.destroy() 108 }) 109 } 110 111 /** 112 * Insert fragment before target, multi-nodes version 113 * 114 * @param {Node} target 115 * @param {Boolean} withTransition 116 */ 117 118 function multiBefore (target, withTransition) { 119 this.inserted = true 120 var vm = this.vm 121 var method = withTransition !== false 122 ? beforeWithTransition 123 : before 124 mapNodeRange(this.node, this.end, function (node) { 125 method(node, target, vm) 126 }) 127 if (inDoc(this.node)) { 128 this.callHook(attach) 129 } 130 } 131 132 /** 133 * Remove fragment, multi-nodes version 134 */ 135 136 function multiRemove () { 137 this.inserted = false 138 var self = this 139 var shouldCallRemove = inDoc(this.node) 140 this.beforeRemove() 141 removeNodeRange(this.node, this.end, this.vm, this.frag, function () { 142 if (shouldCallRemove) { 143 self.callHook(detach) 144 } 145 self.destroy() 146 }) 147 } 148 149 /** 150 * Prepare the fragment for removal. 151 */ 152 153 Fragment.prototype.beforeRemove = function () { 154 var i, l 155 for (i = 0, l = this.childFrags.length; i < l; i++) { 156 // call the same method recursively on child 157 // fragments, depth-first 158 this.childFrags[i].beforeRemove(false) 159 } 160 for (i = 0, l = this.children.length; i < l; i++) { 161 // Call destroy for all contained instances, 162 // with remove:false and defer:true. 163 // Defer is necessary because we need to 164 // keep the children to call detach hooks 165 // on them. 166 this.children[i].$destroy(false, true) 167 } 168 var dirs = this.unlink.dirs 169 for (i = 0, l = dirs.length; i < l; i++) { 170 // disable the watchers on all the directives 171 // so that the rendered content stays the same 172 // during removal. 173 dirs[i]._watcher && dirs[i]._watcher.teardown() 174 } 175 } 176 177 /** 178 * Destroy the fragment. 179 */ 180 181 Fragment.prototype.destroy = function () { 182 if (this.parentFrag) { 183 this.parentFrag.childFrags.$remove(this) 184 } 185 this.node.__v_frag = null 186 this.unlink() 187 } 188 189 /** 190 * Call attach hook for a Vue instance. 191 * 192 * @param {Vue} child 193 */ 194 195 function attach (child) { 196 if (!child._isAttached && inDoc(child.$el)) { 197 child._callHook('attached') 198 } 199 } 200 201 /** 202 * Call detach hook for a Vue instance. 203 * 204 * @param {Vue} child 205 */ 206 207 function detach (child) { 208 if (child._isAttached && !inDoc(child.$el)) { 209 child._callHook('detached') 210 } 211 }