github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/public/libs/vue-1.0.24/test/unit/specs/directives/element/slot_spec.js (about) 1 var Vue = require('src') 2 var nextTick = Vue.nextTick 3 4 describe('Slot Distribution', function () { 5 var el, vm, options 6 beforeEach(function () { 7 el = document.createElement('div') 8 options = { 9 el: el, 10 data: { 11 msg: 'self' 12 } 13 } 14 }) 15 16 function mount () { 17 vm = new Vue(options) 18 } 19 20 it('no content', function () { 21 options.template = '<div><slot></slot></div>' 22 mount() 23 expect(el.firstChild.childNodes.length).toBe(0) 24 }) 25 26 it('default content', function () { 27 el.innerHTML = '<p>foo</p>' 28 options.template = '<div><slot></slot></div>' 29 mount() 30 expect(el.firstChild.tagName).toBe('DIV') 31 expect(el.firstChild.firstChild.tagName).toBe('P') 32 expect(el.firstChild.firstChild.textContent).toBe('foo') 33 }) 34 35 it('no template auto content', function () { 36 el.innerHTML = '<p>foo</p>' 37 options._asComponent = true 38 mount() 39 expect(el.firstChild.tagName).toBe('P') 40 expect(el.firstChild.textContent).toBe('foo') 41 }) 42 43 it('fallback content', function () { 44 options.template = '<slot><p>{{msg}}</p></slot>' 45 mount() 46 expect(el.firstChild.tagName).toBe('P') 47 expect(el.firstChild.textContent).toBe('self') 48 }) 49 50 it('fallback content with multiple named slots', function () { 51 el.innerHTML = '<p slot="b">slot b</p>' 52 options.template = 53 '<slot name="a"><p>fallback a</p></slot>' + 54 '<slot name="b">fallback b</slot>' 55 mount() 56 expect(el.childNodes.length).toBe(2) 57 expect(el.firstChild.textContent).toBe('fallback a') 58 expect(el.lastChild.textContent).toBe('slot b') 59 }) 60 61 it('fallback content with mixed named/unnamed slots', function () { 62 el.innerHTML = '<p slot="b">slot b</p>' 63 options.template = 64 '<slot><p>fallback a</p></slot>' + 65 '<slot name="b">fallback b</slot>' 66 mount() 67 expect(el.childNodes.length).toBe(2) 68 expect(el.firstChild.textContent).toBe('fallback a') 69 expect(el.lastChild.textContent).toBe('slot b') 70 }) 71 72 it('selector matching multiple elements', function () { 73 el.innerHTML = '<p slot="t">1</p><div></div><p slot="t">2</p>' 74 options.template = '<slot name="t"></slot>' 75 mount() 76 expect(el.innerHTML).toBe('<p slot="t">1</p><p slot="t">2</p>') 77 }) 78 79 it('default content should only render parts not selected', function () { 80 el.innerHTML = '<div>foo</div><p slot="a">1</p><p slot="b">2</p>' 81 options.template = 82 '<slot name="a"></slot>' + 83 '<slot></slot>' + 84 '<slot name="b"></slot>' 85 mount() 86 expect(el.innerHTML).toBe('<p slot="a">1</p><div>foo</div><p slot="b">2</p>') 87 }) 88 89 it('content transclusion with replace', function () { 90 el.innerHTML = '<p>foo</p>' 91 options.template = '<div><div><slot></slot></div></div>' 92 options.replace = true 93 mount() 94 var res = vm.$el 95 expect(res).not.toBe(el) 96 expect(res.firstChild.tagName).toBe('DIV') 97 expect(res.firstChild.firstChild.tagName).toBe('P') 98 expect(res.firstChild.firstChild.textContent).toBe('foo') 99 }) 100 101 it('block instance content transclusion', function () { 102 el.innerHTML = '<p slot="p">foo</p><span slot="span">ho</span>' 103 options.template = '<div></div><slot name="p"></slot><slot name="span"></slot>' 104 options.replace = true 105 mount() 106 expect(getChild(1).tagName).toBe('DIV') 107 expect(getChild(2).tagName).toBe('P') 108 expect(getChild(3).tagName).toBe('SPAN') 109 110 function getChild (n) { 111 var el = vm._fragmentStart 112 while (n--) { 113 el = el.nextSibling 114 } 115 return el 116 } 117 }) 118 119 it('name should only match children', function () { 120 el.innerHTML = 121 '<p slot="b">select b</p>' + 122 '<span><p slot="b">nested b</p></span>' + 123 '<span><p slot="c">nested c</p></span>' 124 options.template = 125 '<slot name="a"><p>fallback a</p></slot>' + 126 '<slot name="b">fallback b</slot>' + 127 '<slot name="c">fallback c</slot>' 128 mount() 129 expect(el.childNodes.length).toBe(3) 130 expect(el.firstChild.textContent).toBe('fallback a') 131 expect(el.childNodes[1].textContent).toBe('select b') 132 expect(el.lastChild.textContent).toBe('fallback c') 133 }) 134 135 it('should accept expressions in selectors', function () { 136 el.innerHTML = '<p>one</p><p slot="two">two</p>' 137 options.template = '<slot :name="theName"></slot>' 138 options.data = { 139 theName: 'two' 140 } 141 mount() 142 expect(el.innerHTML).toBe('<p slot="two">two</p>') 143 }) 144 145 it('content should be dynamic and compiled in parent scope', function (done) { 146 var vm = new Vue({ 147 el: el, 148 data: { 149 msg: 'foo' 150 }, 151 template: '<test>{{msg}}</test>', 152 components: { 153 test: { 154 template: '<slot></slot>' 155 } 156 } 157 }) 158 expect(el.innerHTML).toBe('<test>foo</test>') 159 vm.msg = 'bar' 160 nextTick(function () { 161 expect(el.innerHTML).toBe('<test>bar</test>') 162 done() 163 }) 164 }) 165 166 it('v-if with content transclusion', function (done) { 167 var vm = new Vue({ 168 el: el, 169 data: { 170 a: 1, 171 b: 2, 172 show: true 173 }, 174 template: '<test :show="show"><p slot="b">{{b}}</a><p>{{a}}</p></test>', 175 components: { 176 test: { 177 props: ['show'], 178 template: '<div v-if="show"><slot></slot><slot name="b"></slot></div>' 179 } 180 } 181 }) 182 expect(el.textContent).toBe('12') 183 vm.a = 2 184 nextTick(function () { 185 expect(el.textContent).toBe('22') 186 vm.show = false 187 nextTick(function () { 188 expect(el.textContent).toBe('') 189 vm.show = true 190 vm.a = 3 191 nextTick(function () { 192 expect(el.textContent).toBe('32') 193 done() 194 }) 195 }) 196 }) 197 }) 198 199 it('inline v-for', function () { 200 el.innerHTML = '<p slot="1">1</p><p slot="2">2</p><p slot="3">3</p>' 201 new Vue({ 202 el: el, 203 template: '<div v-for="n in list"><slot :name="$index + 1"></slot></div>', 204 data: { 205 list: 0 206 }, 207 beforeCompile: function () { 208 this.list = this.$options._content.querySelectorAll('p').length 209 } 210 }) 211 expect(el.innerHTML).toBe('<div><p slot="1">1</p></div><div><p slot="2">2</p></div><div><p slot="3">3</p></div>') 212 }) 213 214 it('v-for + component + parent directive + transclusion', function (done) { 215 var vm = new Vue({ 216 el: el, 217 template: '<test v-for="n in list" :class="cls" :a="n.a">{{msg}}</test>', 218 data: { 219 cls: 'parent', 220 msg: 'foo', 221 list: [{a: 1}, {a: 2}, {a: 3}] 222 }, 223 components: { 224 test: { 225 replace: true, 226 props: ['a'], 227 template: '<div class="child">{{a}} <slot></slot></div>' 228 } 229 } 230 }) 231 var markup = vm.list.map(function (item) { 232 return '<div class="child parent">' + item.a + ' foo</div>' 233 }).join('') 234 expect(el.innerHTML).toBe(markup) 235 vm.msg = 'bar' 236 markup = vm.list.map(function (item) { 237 return '<div class="child parent">' + item.a + ' bar</div>' 238 }).join('') 239 nextTick(function () { 240 expect(el.innerHTML).toBe(markup) 241 done() 242 }) 243 }) 244 245 it('nested transclusions', function (done) { 246 vm = new Vue({ 247 el: el, 248 template: 249 '<testa>' + 250 '<testb>' + 251 '<div v-for="n in list">{{n}}</div>' + 252 '</testb>' + 253 '</testa>', 254 data: { 255 list: [1, 2] 256 }, 257 components: { 258 testa: { template: '<slot></slot>' }, 259 testb: { template: '<slot></slot>' } 260 } 261 }) 262 expect(el.innerHTML).toBe( 263 '<testa><testb>' + 264 '<div>1</div><div>2</div>' + 265 '</testb></testa>' 266 ) 267 vm.list.push(3) 268 nextTick(function () { 269 expect(el.innerHTML).toBe( 270 '<testa><testb>' + 271 '<div>1</div><div>2</div><div>3</div>' + 272 '</testb></testa>' 273 ) 274 done() 275 }) 276 }) 277 278 it('nested transclusion, container dirs & props', function (done) { 279 vm = new Vue({ 280 el: el, 281 template: 282 '<testa>' + 283 '<testb v-if="ok" :msg="msg"></testb>' + 284 '</testa>', 285 data: { 286 ok: false, 287 msg: 'hello' 288 }, 289 components: { 290 testa: { template: '<slot></slot>' }, 291 testb: { 292 props: ['msg'], 293 template: '{{msg}}' 294 } 295 } 296 }) 297 expect(el.innerHTML).toBe('<testa></testa>') 298 vm.ok = true 299 nextTick(function () { 300 expect(el.innerHTML).toBe('<testa><testb>hello</testb></testa>') 301 done() 302 }) 303 }) 304 305 // #1010 306 it('v-for inside transcluded content', function () { 307 vm = new Vue({ 308 el: el, 309 template: 310 '<testa>' + 311 '{{inner}} {{outer}}' + 312 '<div v-for="item in list"> {{item.inner}} {{outer}}</div>' + 313 '</testa>', 314 data: { 315 outer: 'outer', 316 inner: 'parent-inner', 317 list: [ 318 { inner: 'list-inner' } 319 ] 320 }, 321 components: { 322 testa: { 323 data: function () { 324 return { 325 inner: 'component-inner' 326 } 327 }, 328 template: '<slot></slot>' 329 } 330 } 331 }) 332 expect(el.textContent).toBe('parent-inner outer list-inner outer') 333 }) 334 335 it('single content outlet with replace: true', function () { 336 vm = new Vue({ 337 el: el, 338 template: 339 '<test><p>1</p><p>2</p></test>', 340 components: { 341 test: { 342 template: '<slot></slot>', 343 replace: true 344 } 345 } 346 }) 347 expect(el.innerHTML).toBe('<p>1</p><p>2</p>') 348 }) 349 350 it('template slot', function () { 351 vm = new Vue({ 352 el: el, 353 template: 354 '<test><template slot="test">hello</template></test>', 355 components: { 356 test: { 357 template: '<slot name="test"></slot> world', 358 replace: true 359 } 360 } 361 }) 362 expect(el.innerHTML).toBe('hello world') 363 }) 364 365 it('inside v-for', function () { 366 new Vue({ 367 el: el, 368 template: '<comp v-for="item in items">{{item.value}}</comp>', 369 data: { 370 items: [{value: 123}, {value: 234}] 371 }, 372 components: { 373 comp: { 374 tempalte: '<div><slot></slot></div>' 375 } 376 } 377 }) 378 expect(el.textContent).toBe('123234') 379 }) 380 381 it('fallback inside v-for', function () { 382 new Vue({ 383 el: el, 384 template: '<div v-for="n in 3"><comp></comp></div>', 385 components: { 386 comp: { 387 template: '<div><slot>{{foo}}</slot></div>', 388 data: function () { 389 return { 390 foo: 'bar' 391 } 392 } 393 } 394 } 395 }) 396 expect(el.textContent).toBe('barbarbar') 397 }) 398 399 it('fallback for slot with v-if', function (done) { 400 var vm = new Vue({ 401 el: el, 402 data: { 403 ok: false, 404 msg: 'inserted' 405 }, 406 template: '<div><comp><div v-if="ok">{{ msg }}</div></comp></div>', 407 components: { 408 comp: { 409 data: function () { 410 return { msg: 'fallback' } 411 }, 412 template: '<div><slot>{{ msg }}</slot></div>' 413 } 414 } 415 }) 416 expect(el.textContent).toBe('fallback') 417 vm.ok = true 418 nextTick(function () { 419 expect(el.textContent).toBe('inserted') 420 done() 421 }) 422 }) 423 424 // #2435 425 it('slot inside template', function () { 426 var vm = new Vue({ 427 el: el, 428 template: '<test>foo</test>', 429 components: { 430 test: { 431 data: function () { 432 return { ok: true } 433 }, 434 template: 435 '<div>' + 436 '<template v-if="ok">' + 437 '<template v-if="ok">' + 438 '<slot>{{ msg }}</slot>' + 439 '</template>' + 440 '</template>' + 441 '</div>' 442 } 443 } 444 }) 445 expect(vm.$el.textContent).toBe('foo') 446 }) 447 448 it('warn dynamic slot attribute', function () { 449 new Vue({ 450 el: el, 451 template: '<test><div :slot="1"></div></test>', 452 components: { 453 test: { 454 template: '<div><slot></slot></div>' 455 } 456 } 457 }) 458 expect('"slot" attribute must be static').toHaveBeenWarned() 459 }) 460 461 it('default slot should use fallback content if has only whitespace', function () { 462 new Vue({ 463 el: el, 464 template: '<test><div slot="first">1</div> <div slot="second">2</div></test>', 465 components: { 466 test: { 467 replace: true, 468 template: 469 '<div class="wrapper">' + 470 '<slot name="first"><p>first slot</p></slot>' + 471 '<slot><p>this is the default slot</p></slot>' + 472 '<slot name="second"><p>second named slot</p></slot>' + 473 '</div>' 474 } 475 } 476 }) 477 expect(el.children[0].innerHTML).toBe('<div slot="first">1</div><p>this is the default slot</p><div slot="second">2</div>') 478 }) 479 })