github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/public/libs/vue-1.0.24/src/compiler/transclude.js (about) 1 import { parseText } from '../parsers/text' 2 import { parseTemplate } from '../parsers/template' 3 import { 4 warn, 5 isTemplate, 6 isFragment, 7 prepend, 8 extractContent, 9 createAnchor, 10 resolveAsset, 11 toArray, 12 addClass, 13 hasBindAttr 14 } from '../util/index' 15 16 const specialCharRE = /[^\w\-:\.]/ 17 18 /** 19 * Process an element or a DocumentFragment based on a 20 * instance option object. This allows us to transclude 21 * a template node/fragment before the instance is created, 22 * so the processed fragment can then be cloned and reused 23 * in v-for. 24 * 25 * @param {Element} el 26 * @param {Object} options 27 * @return {Element|DocumentFragment} 28 */ 29 30 export function transclude (el, options) { 31 // extract container attributes to pass them down 32 // to compiler, because they need to be compiled in 33 // parent scope. we are mutating the options object here 34 // assuming the same object will be used for compile 35 // right after this. 36 if (options) { 37 options._containerAttrs = extractAttrs(el) 38 } 39 // for template tags, what we want is its content as 40 // a documentFragment (for fragment instances) 41 if (isTemplate(el)) { 42 el = parseTemplate(el) 43 } 44 if (options) { 45 if (options._asComponent && !options.template) { 46 options.template = '<slot></slot>' 47 } 48 if (options.template) { 49 options._content = extractContent(el) 50 el = transcludeTemplate(el, options) 51 } 52 } 53 if (isFragment(el)) { 54 // anchors for fragment instance 55 // passing in `persist: true` to avoid them being 56 // discarded by IE during template cloning 57 prepend(createAnchor('v-start', true), el) 58 el.appendChild(createAnchor('v-end', true)) 59 } 60 return el 61 } 62 63 /** 64 * Process the template option. 65 * If the replace option is true this will swap the $el. 66 * 67 * @param {Element} el 68 * @param {Object} options 69 * @return {Element|DocumentFragment} 70 */ 71 72 function transcludeTemplate (el, options) { 73 var template = options.template 74 var frag = parseTemplate(template, true) 75 if (frag) { 76 var replacer = frag.firstChild 77 var tag = replacer.tagName && replacer.tagName.toLowerCase() 78 if (options.replace) { 79 /* istanbul ignore if */ 80 if (el === document.body) { 81 process.env.NODE_ENV !== 'production' && warn( 82 'You are mounting an instance with a template to ' + 83 '<body>. This will replace <body> entirely. You ' + 84 'should probably use `replace: false` here.' 85 ) 86 } 87 // there are many cases where the instance must 88 // become a fragment instance: basically anything that 89 // can create more than 1 root nodes. 90 if ( 91 // multi-children template 92 frag.childNodes.length > 1 || 93 // non-element template 94 replacer.nodeType !== 1 || 95 // single nested component 96 tag === 'component' || 97 resolveAsset(options, 'components', tag) || 98 hasBindAttr(replacer, 'is') || 99 // element directive 100 resolveAsset(options, 'elementDirectives', tag) || 101 // for block 102 replacer.hasAttribute('v-for') || 103 // if block 104 replacer.hasAttribute('v-if') 105 ) { 106 return frag 107 } else { 108 options._replacerAttrs = extractAttrs(replacer) 109 mergeAttrs(el, replacer) 110 return replacer 111 } 112 } else { 113 el.appendChild(frag) 114 return el 115 } 116 } else { 117 process.env.NODE_ENV !== 'production' && warn( 118 'Invalid template option: ' + template 119 ) 120 } 121 } 122 123 /** 124 * Helper to extract a component container's attributes 125 * into a plain object array. 126 * 127 * @param {Element} el 128 * @return {Array} 129 */ 130 131 function extractAttrs (el) { 132 if (el.nodeType === 1 && el.hasAttributes()) { 133 return toArray(el.attributes) 134 } 135 } 136 137 /** 138 * Merge the attributes of two elements, and make sure 139 * the class names are merged properly. 140 * 141 * @param {Element} from 142 * @param {Element} to 143 */ 144 145 function mergeAttrs (from, to) { 146 var attrs = from.attributes 147 var i = attrs.length 148 var name, value 149 while (i--) { 150 name = attrs[i].name 151 value = attrs[i].value 152 if (!to.hasAttribute(name) && !specialCharRE.test(name)) { 153 to.setAttribute(name, value) 154 } else if (name === 'class' && !parseText(value) && (value = value.trim())) { 155 value.split(/\s+/).forEach(function (cls) { 156 addClass(to, cls) 157 }) 158 } 159 } 160 }