github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/public/libs/vue-1.0.24/src/util/dom.js (about) 1 import config from '../config' 2 import { isIE9 } from './env' 3 import { warn } from './debug' 4 import { camelize } from './lang' 5 import { removeWithTransition } from '../transition/index' 6 7 /** 8 * Query an element selector if it's not an element already. 9 * 10 * @param {String|Element} el 11 * @return {Element} 12 */ 13 14 export function query (el) { 15 if (typeof el === 'string') { 16 var selector = el 17 el = document.querySelector(el) 18 if (!el) { 19 process.env.NODE_ENV !== 'production' && warn( 20 'Cannot find element: ' + selector 21 ) 22 } 23 } 24 return el 25 } 26 27 /** 28 * Check if a node is in the document. 29 * Note: document.documentElement.contains should work here 30 * but always returns false for comment nodes in phantomjs, 31 * making unit tests difficult. This is fixed by doing the 32 * contains() check on the node's parentNode instead of 33 * the node itself. 34 * 35 * @param {Node} node 36 * @return {Boolean} 37 */ 38 39 export function inDoc (node) { 40 if (!node) return false 41 var doc = node.ownerDocument.documentElement 42 var parent = node.parentNode 43 return doc === node || 44 doc === parent || 45 !!(parent && parent.nodeType === 1 && (doc.contains(parent))) 46 } 47 48 /** 49 * Get and remove an attribute from a node. 50 * 51 * @param {Node} node 52 * @param {String} _attr 53 */ 54 55 export function getAttr (node, _attr) { 56 var val = node.getAttribute(_attr) 57 if (val !== null) { 58 node.removeAttribute(_attr) 59 } 60 return val 61 } 62 63 /** 64 * Get an attribute with colon or v-bind: prefix. 65 * 66 * @param {Node} node 67 * @param {String} name 68 * @return {String|null} 69 */ 70 71 export function getBindAttr (node, name) { 72 var val = getAttr(node, ':' + name) 73 if (val === null) { 74 val = getAttr(node, 'v-bind:' + name) 75 } 76 return val 77 } 78 79 /** 80 * Check the presence of a bind attribute. 81 * 82 * @param {Node} node 83 * @param {String} name 84 * @return {Boolean} 85 */ 86 87 export function hasBindAttr (node, name) { 88 return node.hasAttribute(name) || 89 node.hasAttribute(':' + name) || 90 node.hasAttribute('v-bind:' + name) 91 } 92 93 /** 94 * Insert el before target 95 * 96 * @param {Element} el 97 * @param {Element} target 98 */ 99 100 export function before (el, target) { 101 target.parentNode.insertBefore(el, target) 102 } 103 104 /** 105 * Insert el after target 106 * 107 * @param {Element} el 108 * @param {Element} target 109 */ 110 111 export function after (el, target) { 112 if (target.nextSibling) { 113 before(el, target.nextSibling) 114 } else { 115 target.parentNode.appendChild(el) 116 } 117 } 118 119 /** 120 * Remove el from DOM 121 * 122 * @param {Element} el 123 */ 124 125 export function remove (el) { 126 el.parentNode.removeChild(el) 127 } 128 129 /** 130 * Prepend el to target 131 * 132 * @param {Element} el 133 * @param {Element} target 134 */ 135 136 export function prepend (el, target) { 137 if (target.firstChild) { 138 before(el, target.firstChild) 139 } else { 140 target.appendChild(el) 141 } 142 } 143 144 /** 145 * Replace target with el 146 * 147 * @param {Element} target 148 * @param {Element} el 149 */ 150 151 export function replace (target, el) { 152 var parent = target.parentNode 153 if (parent) { 154 parent.replaceChild(el, target) 155 } 156 } 157 158 /** 159 * Add event listener shorthand. 160 * 161 * @param {Element} el 162 * @param {String} event 163 * @param {Function} cb 164 * @param {Boolean} [useCapture] 165 */ 166 167 export function on (el, event, cb, useCapture) { 168 el.addEventListener(event, cb, useCapture) 169 } 170 171 /** 172 * Remove event listener shorthand. 173 * 174 * @param {Element} el 175 * @param {String} event 176 * @param {Function} cb 177 */ 178 179 export function off (el, event, cb) { 180 el.removeEventListener(event, cb) 181 } 182 183 /** 184 * For IE9 compat: when both class and :class are present 185 * getAttribute('class') returns wrong value... 186 * 187 * @param {Element} el 188 * @return {String} 189 */ 190 191 function getClass (el) { 192 var classname = el.className 193 if (typeof classname === 'object') { 194 classname = classname.baseVal || '' 195 } 196 return classname 197 } 198 199 /** 200 * In IE9, setAttribute('class') will result in empty class 201 * if the element also has the :class attribute; However in 202 * PhantomJS, setting `className` does not work on SVG elements... 203 * So we have to do a conditional check here. 204 * 205 * @param {Element} el 206 * @param {String} cls 207 */ 208 209 export function setClass (el, cls) { 210 /* istanbul ignore if */ 211 if (isIE9 && !/svg$/.test(el.namespaceURI)) { 212 el.className = cls 213 } else { 214 el.setAttribute('class', cls) 215 } 216 } 217 218 /** 219 * Add class with compatibility for IE & SVG 220 * 221 * @param {Element} el 222 * @param {String} cls 223 */ 224 225 export function addClass (el, cls) { 226 if (el.classList) { 227 el.classList.add(cls) 228 } else { 229 var cur = ' ' + getClass(el) + ' ' 230 if (cur.indexOf(' ' + cls + ' ') < 0) { 231 setClass(el, (cur + cls).trim()) 232 } 233 } 234 } 235 236 /** 237 * Remove class with compatibility for IE & SVG 238 * 239 * @param {Element} el 240 * @param {String} cls 241 */ 242 243 export function removeClass (el, cls) { 244 if (el.classList) { 245 el.classList.remove(cls) 246 } else { 247 var cur = ' ' + getClass(el) + ' ' 248 var tar = ' ' + cls + ' ' 249 while (cur.indexOf(tar) >= 0) { 250 cur = cur.replace(tar, ' ') 251 } 252 setClass(el, cur.trim()) 253 } 254 if (!el.className) { 255 el.removeAttribute('class') 256 } 257 } 258 259 /** 260 * Extract raw content inside an element into a temporary 261 * container div 262 * 263 * @param {Element} el 264 * @param {Boolean} asFragment 265 * @return {Element|DocumentFragment} 266 */ 267 268 export function extractContent (el, asFragment) { 269 var child 270 var rawContent 271 /* istanbul ignore if */ 272 if (isTemplate(el) && isFragment(el.content)) { 273 el = el.content 274 } 275 if (el.hasChildNodes()) { 276 trimNode(el) 277 rawContent = asFragment 278 ? document.createDocumentFragment() 279 : document.createElement('div') 280 /* eslint-disable no-cond-assign */ 281 while (child = el.firstChild) { 282 /* eslint-enable no-cond-assign */ 283 rawContent.appendChild(child) 284 } 285 } 286 return rawContent 287 } 288 289 /** 290 * Trim possible empty head/tail text and comment 291 * nodes inside a parent. 292 * 293 * @param {Node} node 294 */ 295 296 export function trimNode (node) { 297 var child 298 /* eslint-disable no-sequences */ 299 while (child = node.firstChild, isTrimmable(child)) { 300 node.removeChild(child) 301 } 302 while (child = node.lastChild, isTrimmable(child)) { 303 node.removeChild(child) 304 } 305 /* eslint-enable no-sequences */ 306 } 307 308 function isTrimmable (node) { 309 return node && ( 310 (node.nodeType === 3 && !node.data.trim()) || 311 node.nodeType === 8 312 ) 313 } 314 315 /** 316 * Check if an element is a template tag. 317 * Note if the template appears inside an SVG its tagName 318 * will be in lowercase. 319 * 320 * @param {Element} el 321 */ 322 323 export function isTemplate (el) { 324 return el.tagName && 325 el.tagName.toLowerCase() === 'template' 326 } 327 328 /** 329 * Create an "anchor" for performing dom insertion/removals. 330 * This is used in a number of scenarios: 331 * - fragment instance 332 * - v-html 333 * - v-if 334 * - v-for 335 * - component 336 * 337 * @param {String} content 338 * @param {Boolean} persist - IE trashes empty textNodes on 339 * cloneNode(true), so in certain 340 * cases the anchor needs to be 341 * non-empty to be persisted in 342 * templates. 343 * @return {Comment|Text} 344 */ 345 346 export function createAnchor (content, persist) { 347 var anchor = config.debug 348 ? document.createComment(content) 349 : document.createTextNode(persist ? ' ' : '') 350 anchor.__v_anchor = true 351 return anchor 352 } 353 354 /** 355 * Find a component ref attribute that starts with $. 356 * 357 * @param {Element} node 358 * @return {String|undefined} 359 */ 360 361 var refRE = /^v-ref:/ 362 export function findRef (node) { 363 if (node.hasAttributes()) { 364 var attrs = node.attributes 365 for (var i = 0, l = attrs.length; i < l; i++) { 366 var name = attrs[i].name 367 if (refRE.test(name)) { 368 return camelize(name.replace(refRE, '')) 369 } 370 } 371 } 372 } 373 374 /** 375 * Map a function to a range of nodes . 376 * 377 * @param {Node} node 378 * @param {Node} end 379 * @param {Function} op 380 */ 381 382 export function mapNodeRange (node, end, op) { 383 var next 384 while (node !== end) { 385 next = node.nextSibling 386 op(node) 387 node = next 388 } 389 op(end) 390 } 391 392 /** 393 * Remove a range of nodes with transition, store 394 * the nodes in a fragment with correct ordering, 395 * and call callback when done. 396 * 397 * @param {Node} start 398 * @param {Node} end 399 * @param {Vue} vm 400 * @param {DocumentFragment} frag 401 * @param {Function} cb 402 */ 403 404 export function removeNodeRange (start, end, vm, frag, cb) { 405 var done = false 406 var removed = 0 407 var nodes = [] 408 mapNodeRange(start, end, function (node) { 409 if (node === end) done = true 410 nodes.push(node) 411 removeWithTransition(node, vm, onRemoved) 412 }) 413 function onRemoved () { 414 removed++ 415 if (done && removed >= nodes.length) { 416 for (var i = 0; i < nodes.length; i++) { 417 frag.appendChild(nodes[i]) 418 } 419 cb && cb() 420 } 421 } 422 } 423 424 /** 425 * Check if a node is a DocumentFragment. 426 * 427 * @param {Node} node 428 * @return {Boolean} 429 */ 430 431 export function isFragment (node) { 432 return node && node.nodeType === 11 433 } 434 435 /** 436 * Get outerHTML of elements, taking care 437 * of SVG elements in IE as well. 438 * 439 * @param {Element} el 440 * @return {String} 441 */ 442 443 export function getOuterHTML (el) { 444 if (el.outerHTML) { 445 return el.outerHTML 446 } else { 447 var container = document.createElement('div') 448 container.appendChild(el.cloneNode(true)) 449 return container.innerHTML 450 } 451 }