-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcomponents.html
771 lines (723 loc) · 30.3 KB
/
components.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Form Input Bindings</title>
<link rel="stylesheet" href="./style.css">
<link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/obsidian.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
</head>
<body>
<h1>Form Input Bindings</h1>
<h2>Components</h2>
<b>What are Components?</b>
<p>就是Vuejs最強大的功能之一!!!讓HTML有更豐富並保有原生的特色,也可以使用<code>is</code>擴充</p>
<p>如果你有物件的概念,那<code>component</code>可以視為一個<code>class</code>(of OO)的概念</p>
<h2>Using Components</h2>
<h3>Registration</h3>
<p>要使用<code>components</code>,就要先註冊。在這裡先介紹「全域註冊」,這種註冊方式可以提供一個元件給所有的Vue物件使用。</p>
<b>HTML</b>
<p><code>component</code>只有一個靜態字串。</p>
<pre><code class="html">< div id = "example" >
< my-component > </ my-component >
< /div ></code></pre>
<b>Javascript</b>
<p>註冊元件,在<code>HTML</code>有一樣名稱的tag name就可以改成<code>template</code>的內容</p>
<pre><code class="javascript">Vue.component('my-component', {
template: '< div >A custom component!< /div >'
})</code></pre>
<p>Vue物件實體,在<code>HTML</code>有一樣<code>id</code>,對應到Vue物件實體的<code>el</code>,就會進行Vue的渲染。<br />
也就是因為有讓Vue實體物件對應上,<code>component</code>自訂義的HTML tag才會渲染成<code>component.template</code>。</p>
<pre><code class="javascript">new Vue({
el: '#example'
})</code></pre>
<b>Rendered</b>
<pre><code class="html">< div id="example" >
< div >A custom component!< /div >
< /div ></code></pre>
<b>Result</b>
<div id = "example">
<my-component> </my-component>
</div>
<h3>Local Registration</h3>
<p>區域註冊,就是「限定註冊域」,指定components給特定的Vue物件使用。</p>
<p>此例指定<code>local-component</code>給<code>local</code></p>
<b>HTML</b>
<p><code>component</code>只有一個靜態字串。</p>
<pre><code class="html">< div id="local" >
< local-component > < /local-component >
< /div ></code></pre>
<b>Javascript</b>
<pre><code class="javascript">var Child = {
template: '< div >A custom component!< /div >'
}
new Vue({
// ...
components: {
'local-component': Child
}
})</code></pre>
<b>Result</b>
<div id="local">
<local-component></local-component>
</div>
<h3>DOM Template Parsing Caveats</h3>
<p>在HTML渲染中,有存在著某些tag彼此有固定的相依關係<br />
<ul>
<li><code>ul</code>後面一定接<code>li</code></li>
<li><code>ol</code>後面一定接<code>li</code></li>
<li><code>table</code>裡面一定接<code>tbody, td, tr</code>...等</li>
<li class="question"><code>select</code>一定??怎麼搭配?</li>
<li><code>option</code>外面一定接<code>select</code></li>
<li>等等...很多例子</li>
</ul>
<p>自訂義組件使用這些元素,會有一些問題。</p>
<p class="question">這裡的實驗結果,看不出什麼太大的差別,就<code>差別比較大</code>其它的差別感覺不太出來。<br />
倒是有一種,在<code>is</code>上的<code>tag name</code>,當作<code>template</code>的味道。</p>
<b>HTML</b>
<pre><code class="html">< div id="dom-templae" >
< table >< table-cell >會搬出table,沒有渲染!!< /table-cell >< /table >
< ul >< ul-cell >ul沒有渲染!!< /ul-cell >< /ul >
< ol >< ol-cell >ol沒有渲染!!< /ol-cell >< /ol >
< section >< section-cell >section沒有渲染!!< /section-cell >< /section >
< !-- 使用is的效果 -- >
< table >< tr is="table-cell" >table只是搬出來,沒有渲染!!< /tr >< /table >
< ul >< li is="ul-cell" >ul沒有渲染!!< /li >< /ul >
< ol >< li is="ol-cell" >ol沒有渲染!!< /li >< /ol >
< section >< h5 is="section-cell" >section沒有渲染!!< /h5 >< /section >
< /div ></code></pre>
<b>渲染成</b>
<pre><code class="html">< div id="dom-templae" >
< tr >< td >有渲染,無is會搬出table< /td >< /tr >
< table >< /table >
< ul >< li >有渲染< /li >< /ul >
< ol >< li >有渲染< /li >< /ol >
< section >< h6 >有渲染< /h6 >< /section >
< !-- 使用is的效果 -- >
< table >< tbody >< tr >< td >有渲染,無is會搬出table< /td >< /tr >< /tbody >< /table >
< ul >< li >有渲染< /li >< /ul >
< ol >< li >有渲染< /li >< /ol >
< section >< h6 >有渲染< /h6 >< /section >
< /div ></code></pre>
<div id="dom-templae">
<b>Result</b><br />
<b>不使用<code>is</code>的效果</b>
<table><table-cell>會搬出table,沒有渲染!!</table-cell></table>
<ul><ul-cell>ul沒有渲染!!</ul-cell></ul>
<ol><ol-cell>ol沒有渲染!!</ol-cell></ol>
<section><section-cell>section沒有渲染!!</section-cell></section>
<b>使用<code>is</code>的效果</b>
<p>無論<code>is</code>所屬的tag name是什麼,會置換成<code>template</code>的第一層tag name</p>
<table><tr is="table-cell">table只是搬出來,沒有渲染!!</tr></table>
<ul><li is="ul-cell">ul沒有渲染!!</li></ul>
<ol><li is="ol-cell">ol沒有渲染!!</li></ol>
<section><h5 is="section-cell">section沒有渲染!!</h5></section>
</div>
<p class="question"><b>應當注意,如果您使用來自以下來源之一的字符串模板,這些限制將不適用:</b></p>
<ul>
<li>< script type="text/x-template" ></li>
<li>JavaScript 內聯模板字符串</li>
<li>.vue 組件</li>
</ul>
<p>因此,有必要的話請使用字符串模板。</p>
<h3><code>data</code> Must Be a Function</h3>
<p><code>components</code>的<code>data</code>必須是function。<br />
可以看一下<a href="https://www.talkingcoder.com/article/6421767197575348224">Vue 组件data为什么必须是函数?</a></p>
<b>Javascript</b>
<p>如果這麼做,<code>console</code>會發出警告告訴你「在組件中data必須是一個函數。」</p>
<pre><code class="javascript">Vue.component('my-component', {
template: '< span >{ { message } }< /span >',
data: {
message: 'hello' //被警告
}
})</code></pre>
<b>console錯誤訊息</b>
<p class="console-error"><i class="fa fa-times-circle"></i>vue.js:485 [Vue warn]: The "data" option should be a function that returns a per-instance value in component definitions.</p>
<p>理解這種規則的存在意義很有幫助,讓我們假設用如下方式來繞開Vue的警告:</p>
<b>HTML</b>
<pre><code class="html">< div id="example-2" >
< simple-counter >< /simple-counter >
< simple-counter >< /simple-counter >
< simple-counter >< /simple-counter >
< /div ></code></pre>
<b>Javascript</b>
<p> 技術上data 的確是一個函數了,因此Vue 不會警告,<br />
但是我們返回給每個組件的實例卻引用了同一個data 對象</p>
<pre><code class="javascript">var data = { counter: 0 } ---> 全域宣告data物件
Vue.component('simple-counter', {
template: '< button v-on:click="counter += 1" >{{ counter }}< /button >',
data: function () {
return data ---> 回傳 全域data物件
}
})
new Vue({
el: '#example-2'
})</code></pre>
<b>Result</b>
<div id="example-2">
<simple-counter></simple-counter>
<simple-counter></simple-counter>
<simple-counter></simple-counter>
</div>
<b>Javascript要修改成「回傳一個新物件」</b>
<b>Javascript</b>
<pre><code class="javascript">data: function () {
return {
counter : 0
}
}</code></pre>
<b>Result</b>
<div id="example-2right">
<simple-counter-right></simple-counter-right>
<simple-counter-right></simple-counter-right>
<simple-counter-right></simple-counter-right>
</div>
<h3>Composing Components</h3>
<p>在前面<code>components</code>的練習中,我們都只是在<code>component</code>的<code>template</code>寫靜態的字串,讓它顯示。<br />接下來會開始引進變數,並且介紹如何修改。</p>
<p>在Vue中,父子組件的關係可以總結為<code>props down</code>, <code>events up</code>。</p>
<ol>
<li>父組件(Vue物件)通過<code>props</code>向下傳遞數據給子組件</li>
<li>子組件(component)通過<code>events</code>給父組件發送消息</li>
</ol>
<img src="https://vuejs.org/images/props-events.png" alt="" width="300px">
<p>接下來就來看<code>props</code>和<code>events</code>的同作機制!</p>
<h2>Props</h2>
<p class="tip"><code>component</code>實例的作用域是獨立的。<br />這意味著無法直接將父組件的變數傳給子組件使用。<br />
除非,使用<code>props</code></p>
<h3>Passing Data with Props</h3>
<p>宣告一段自訂義tag name的<code>component</code></p>
<b>HTML</b>
<pre><code class="html">< div id="props">
< child message = "hello!" > < /child >
< /div></code></pre>
<b>Javascript</b>
<pre><code class="javascript">Vue.component( 'child' , { //父組件
props: [ 'message' ], // 宣告props
template: '< span >{ { message } }< /span >' // 子組件!! 就可以像data 一樣,prop 可以用在模板內
})</code></pre>
<p>在component中的用法,就像在vm實例中,直接呼叫data般<code>this.message</code>這樣使用。</p>
<pre><code class="javascript">Vue.component('child', {
props: ['message'],
template: '< span v-on:click="showit">{ { message } }< /span>',
methods: {
showit: function () {
setTimeout(() => console.log(this.message), 0);
}
}
}</code></pre>
<b>Result</b>
<div id="props">
<child message="hello!"></child>
<!-- <div>{{msg}}</div> -->
</div>
<h3>camelCase vs. kebab-case</h3>
<p>駝峰命名法=小寫分隔線命名法</p>
<p><code>component</code>指的是自訂tag name的HTML</p>
<p>HtmlElement.attr = component.props</p>
<b>HTML</b>
<pre><code class="html">< !-- kebab-case in HTML -- >
< child my-message="hello!" >< /child > ---> my-message(HTML) = myMessage(js): render
< child myMessage="hello!" >< /child > ---> myMessage(HTML) ≠ myMessage(js): not render</code></pre>
<b>Javascript</b>
<p class="question">如果你使用字符串模板,則沒有這些限制。??</p>
<pre><code class="javascript">Vue.component('child', {
// camelCase in JavaScript
props: ['myMessage'],
template: '< span >{ { myMessage } }< /span >'
})
new Vue({
el: '#my-message'
})</code></pre>
<b>Result</b>
<div id="my-message">
<!-- kebab-case in HTML -->
<child my-message="hello!"></child>
<!-- <child myMessage="hello!"></child> -->
</div>
<h3>Dynamic Props</h3>
<p>把Vue物件裡的<code>data</code>丟到組件裡。</p>
<p><code>:my-message="parentMsg"</code>中,若"parentMsg"是字串,則my-message就不用<code>v-bind</code>。但是,若它是變數,要v-bind</p>
<b>HTML</b>
<pre><code class="html">< div id="dynamic_prop" >
< input v-model="parentMsg" >
< br >
< child :my-message="parentMsg" >< /child >
< /div ></code></pre>
<b>Javascript</b>
<pre><code class="javascript">Vue.component('child', {
// camelCase in JavaScript
props: ['myMessage'],
template: '< span >{ { myMessage } }< /span >'
})
new Vue({
el: '#dynamic_prop',
data: {
parentMsg: 'aaaaaa'
}
})</code></pre>
<b>數值傳遞圖</b>
<img src="https://i.imgur.com/FeyFKYh.jpg" alt="" class="note-graph">
<b>Result</b>
<div id="dynamic_prop">
<input v-model="parentMsg">
<br>
<child :my-message="parentMsg"></child>
</div>
<h3>Literal vs. Dynamic</h3>
<p class="tip">初學常犯的問題。</p>
<pre><code class="html">< !-- this passes down a plain string "1" -- >
< comp some-prop="1" >< /comp ></code></pre>
<p>誤以為這樣的1是數字,但其實是文字。要數字要使<code>v-bind</code></p>
<pre><code class="html">< !-- this passes down an actual number -- >
< comp v-bind:some-prop="1" >< /comp ></code></pre>
<h3>One-Way Data Flow</h3>
<p><code>props</code>是父層組件和子層組件的溝通管道。但是它是單向資料流。<br />
所以,不該在子組件內部改變prop。如果你這麼做了,Vue會在控制台給出警告。<br />
那為什麼還會想改呢?有兩個常見的原因</p>
<ol>
<li><code>prop</code> 作為初始值傳入後,子組件想把它當作區域變數來用;</li>
<li><code>prop</code> 作為初始值傳入,由子組件處理成其它資料-輸出。</li>
</ol>
<p>區域變數: <code>component</code>需要<code>data function</code></p>
<pre><code class="javascript">props: [ 'initialCounter' ],
data : function () {
return { counter : this .initialCounter }
}</code></pre>
<p>初始化變數: <code>component</code>需要<code>computed function</code></p>
<pre><code class="javascript">props: [ 'size' ],
computed : {
normalizedSize : function () {
return this .size.trim().toLowerCase()
}
}</code></pre>
<p class="tip">注意在JavaScript中物件和陣列是<code>reference</code>,指向同一個記憶體空間,<br />如果<code>prop</code>是一個物件或陣列,在子組件內部改變它時,會影響父組件的狀態。</p>
<h3>Prop Validation</h3>
<p><code>components</code>的prop可以設計「資料驗證」。如果驗證NG,Vue會發出警告。有助於設計給別人使用時,別人可以正確的使用<code>props</code></p>
<b>HTML</b>
<pre><code class="html">< div id="validation" >
< label for="1" >propA: < /label >
< input id="1" v-model.number="inputA" placeholder="waring: empty string or string" >< br / >
< label for="2" >propB(number): < /label >
< input id="2" v-model.number="inputB" >< br / >
< label for="3" >propB(string): < /label >
< input id="3" v-model="inputB" >< br / >
< label for="4" >propC: < /label >
< input id="4" v-model.number="inputC" placeholder="waring: no default string" >< br / >
< label for="4" >propD(number, default 100, but not show): < /label >
< input id="4" v-model.number="inputD" placeholder="waring: no warning, default 100" >< br / >
< label for="5" >propD(string): < /label >
< input id="5" v-model="inputD" placeholder="waring: string, default 100" >< br / >
< label for="6" >propE: < /label >
< input id="6" v-model="inputE.message" >< br / >
< label for="7" >propF: < /label >
< input id="7" v-model.number="inputF" type="number" placeholder="warning: string" >< br / >
< vali :prop-a="inputA"
:prop-b="inputB"
:prop-c="inputC"
:prop-d="inputD"
:prop-e="inputE"
:prop-f="inputF" >
< /vali >
< /div ></code></pre>
<b>Javascript</b>
<pre><code class="javascript">new Vue({
el: '#validation',
data: {
inputA: 0,
inputB: 0,
inputC: 'chris',
inputD: 10,
inputE: { message: 0},
inputF: 11
},
components: {
'vali': {
props : {
propA: Number , // 基本資料型別檢查(`null` 意思是任何類型都可以)
propB: [ String , Number ], // 多種類型
propC: { // 必填字串
type : String ,
required : true
},
propD: { // 數字,設定預設值
type : Number ,
default : 100
},
propE: { // 陣列/物件 預設值,要由一個「工廠函數」回傳
type : Object ,
default : function () {
return { message : 'hello' }
}
},
propF: { // 自定邏輯函數 驗證
validator : function ( value ) {
return value > 10
}
}
},
template: `< ol >
< li >propA: {{propA}}< /li >
< li >propB: {{propB}}< /li >
< li >propC: {{propC}}< /li >
< li >propD: {{propD}}< /li >
< li >propE: {{propE}}< /li >
< li >propF: {{propF}}< /li >
< /ol >`
}
}
})</code></pre>
<b>Reault</b>
<div id="validation">
<b>Input</b><br />
<label for="1">propA: </label>
<input id="1" v-model.number="inputA" placeholder="waring: empty string or string"><br />
<label for="2">propB(number): </label>
<input id="2" v-model.number="inputB"><br />
<label for="3">propB(string): </label>
<input id="3" v-model="inputB"><br />
<label for="4">propC: </label>
<input id="4" v-model.number="inputC" placeholder="waring: no default string"><br />
<label for="4">propD(number, default 100, but not show): </label>
<input id="4" v-model.number="inputD" placeholder="waring: no warning, default 100"><br />
<label for="5">propD(string): </label>
<input id="5" v-model="inputD" placeholder="waring: string, default 100"><br />
<label for="6">propE: </label>
<input id="6" v-model="inputE.message"><br />
<label for="7">propF: </label>
<input id="7" v-model.number="inputF" type="number" placeholder="warning: string"><br />
<b>Output</b>
<vali :prop-a="inputA" :prop-b="inputB" :prop-c="inputC" :prop-d="inputD" :prop-e="inputE" :prop-f="inputF"></vali>
</div>
<h2>Non-Prop Attributes</h2>
<p>例子的練習,參考<a href="https://www.ruphi.cn/archives/218/#anchor10">Vue学习总结笔记(二):组件</a></p>
<p>非<code>prop</code>屬性的意思,指的是一般的屬性,要提供給「使用<code>component</code>的開發者」<br />在不修改<code>template</code>的情況,想修改<code>component</code>渲染完的根元屬性,該如何做?</p>
<b>HTML</b>
<pre><code class="html">< bs-date-input id="non-prop" data-3d-date-picker="true" >< /bs-date-input ></code></pre>
<b>Javascript</b>
<pre><code class="javascript">new Vue ({
el: '#non-prop',
components: {
'bs-date-input': {
template: `< div >component< /div >`
}
}
})</code></pre>
<b>Rendered</b>
<pre><code class="html">< div id="non-prop" data-3d-date-picker="true" >component /div ></code></pre>
<b>Result</b>
<bs-date-input id="non-prop" data-3d-date-picker="true"></bs-date-input>
<h3>Replacing/Merging with Existing Attributes</h3>
<p>在component的例子,HTML有<code>class="date-picker-theme-dark"</code>,<br />
在<code>component</code>的<code>template</code>有<code>class="form-control"</code></p>
<b>HTML</b>
<pre><code class="html">< bs-date-input id="merging-attri" data-3d-date-picker="true" class="date-picker-theme-dark" >< /bs-date-input ></code></pre>
<b>Javascript</b>
<pre><code class="javascript">new Vue ({
el: '#merging-attri',
components: {
'bs-date-input': {
template: `< input type="date" class="form-control" >`
}
}
})</code></pre>
<p>渲染完會長怎樣呢?</p>
<b>Rendered</b>
<pre><code class="html">< input type="date" class="form-control date-picker-theme-dark" id="merging-attri" data-3d-date-picker="true" ></code></pre>
<p>HTML的attri會取「聯集」的結果<code>class="form-control date-picker-theme-dark"</code></p>
<b>Result</b><br />
<bs-date-input id="merging-attri" data-3d-date-picker="true" class="date-picker-theme-dark" ></bs-date-input>
<h2>Custom Events</h2>
<p>我們前面學了 父對子 的變數值傳遞方式,接下來要說的是 子對父 的變數值傳遞方式</p>
<h3>Using v-on with Custom Events</h3>
<p>讓我們從熟悉的角度切入</p>
<p>每一個Vue物件本身,都擁有<code>event interface</code></p>
<ul>
<li>監聽 event 使用 <code>$on(eventName)</code></li>
<li>觸發 event 使用 <code>$emit(eventName)</code></li>
</ul>
<p class="tip"><code>$on</code>和<code>$emit</code>並不是<code>addEventListener</code>和<code>dispatchEvent</code>的別名。</p>
<p>父組件可以直接監聽在子層裡<code>template</code>裡的事件</p>
<p class="tip">無法使用<code>$on</code>直接監聽子層觸發的事件。必須直接在<code>template</code>使用<code>v-on</code></p>
<b>HTML</b>
<pre><code class="html">< div id="counter-event-example">
< p>{ { total } }< /p>
< button-counter v-on:increment="incrementTotal">< /button-counter> < -- 3. 子層的自訂義increment事件,觸發父層的incrementTotal
< button-counter v-on:increment="incrementTotal">< /button-counter>
< /div></code></pre>
<b>Javascript</b>
<pre><code class="javascript">Vue.component('button-counter', {
template: '< button v-on:click="incrementCounter" >{ { counter } }< /button >', //1. 子組件用v-on執行incrementCounter
data: function () {
return {
counter: 0
}
},
methods: {
incrementCounter: function () {
this.counter += 1
this.$emit('increment') //2. 自訂事件觸發$emit給父層的Method
}
},
})
new Vue({
el: '#counter-event-example',
data: {
total: 0
},
methods: {
incrementTotal: function () {
this.total += 1 //4. 執行父層函數,更新total
}
}
})</code></pre>
<b>數值傳遞圖</b>
<img src="https://i.imgur.com/7WeRxSL.jpg" alt="" class="note-graph">
<b>Result</b>
<div id="counter-event-example">
<p>{{ total }}</p>
<button-counter v-on:increment="incrementTotal"></button-counter>
<button-counter v-on:increment="incrementTotal"></button-counter>
</div>
<h3>Binding Native Events to Components</h3>
<p>如果你不要自訂,要用原生的,在<code>template</code>的<code>v-on</code>加上<code>.native</code>的修飾字</p>
<pre><code class="html">< my-component v-on:click.native="doTheThing">< /my-component></code></pre>
<h3><code>.sync</code>修飾符</h3>
<p class="question">不同於v1.x版的雙向綁定的用途,在v2.x版<code>.sync</code>當作一個自動附加父組件<code>v-on</code>偵聽器的屬性。目的在於<b>讓子組件改變父組件狀態的代碼更容易被區分。</b>,也就只是作為一個編譯時的語法糖存在。</p>
<pre><code class="html">< comp :foo.sync="bar">< /comp></code></pre>
<p class="question">會幫你加上</p>
<pre><code class="html">< comp :foo="bar" @update:foo="val => bar = val">< /comp></code></pre>
<p class="question">組件需要更新<code>foo</code>時,可以這樣寫</p>
<pre><code class="javascript">this .$emit( 'update:foo' , newValue)</code></pre>
<h3>Form Input Components using Custom Events</h3>
<p>一般而言,我們用雙向綁定vue實例與HTML,在HTML加上<code>v-mode</code></p>
<pre><code class="html">< input v-model="something"></code></pre>
<p>Vue會幫你改成這樣</p>
<pre><code class="html">< input
v-bind:value="something"
v-on:input="something = $event.target.value"></code></pre>
<p>在<code>components</code>使用時,需要這樣寫</p>
<pre><code class="html">< custom-input
v-bind:value="something"
v-on:input="value => { something = value }">
< /custom-input></code></pre>
<b>練習</b>
<div id="vmode">
<!-- <input
v-bind:value="something"
v-on:input="something = $event.target.value"> -->
<!-- <span>{{something}}</span> -->
<custom-input
:value="something"
@input="value => { something = value }">
</custom-input>
</div>
<h2>暫時先看到這</h2>
<p>接下來,做<code>vue-cli</code>的練習</p>
<!-- <div>
<b>HTML</b>
<pre></pre>
<b>Javascript</b>
<pre></pre>
<b>Result</b>
</div>-->
<script src="https://unpkg.com/vue"></script>
<script type="text/javascript">
// register
Vue.component('my-component', {
template: '<div>A custom component!</div>'
})
// create a root instance
new Vue({
el: '#example'
})
new Vue({
el: '#local',
components: {
// <local-component> will only be available in parent's template
'local-component': {
template: '<div>A custom component!</div>'
}
}
})
Vue.component('table-cell', {
template: '<tr><td>有渲染,無is會搬出table</td></tr>'
})
Vue.component('ul-cell', {
template: '<li>有渲染</li>'
})
Vue.component('ol-cell', {
template: '<li>有渲染</li>'
})
Vue.component('section-cell', {
template: '<h6>有渲染</h6>'
})
new Vue({
el: '#dom-templae'
})
var data = { counter: 0 }
Vue.component('simple-counter', {
template: '<button v-on:click="counter += 1">{{ counter }}</button>',
// data is technically a function, so Vue won't
// complain, but we return the same object
// reference for each component instance
data: function () {
return data
}
})
new Vue({
el: '#example-2'
})
Vue.component('simple-counter-right', {
template: '<button v-on:click="counter += 1">{{ counter }}</button>',
// data is technically a function, so Vue won't
// complain, but we return the same object
// reference for each component instance
data: function () {
return {
counter: 0
}
}
})
new Vue({
el: '#example-2right'
})
// Vue.component('child', {
// // declare the props
// props: ['message'],
// // just like data, the prop can be used inside templates
// // and is also made available in the vm as this.message
// template: '<span>{{ message }}</span>'
// })
var props = new Vue({
el: '#props',
components: {
'child': {
props: ['message'],
template: '<span v-on:click="showit">{{ message }}</span>',
methods: {
showit: function () {
setTimeout(() => console.log(this.message), 0);
}
}
}
}
})
Vue.component('child', {
props: ['myMessage'],
template: '<span>{{ myMessage }}</span>'
});
new Vue({
el: '#my-message'
})
var dynamic = new Vue({
el: '#dynamic_prop',
data: {
parentMsg: 'aaaaaa'
}
})
new Vue({
el: '#validation',
data: {
inputA: 0,
inputB: 0,
inputC: 'chris',
inputD: 10,
inputE: { message: 0},
inputF: 11
},
components: {
'vali': {
props : {
propA: Number , // 基本資料型別檢查(`null` 意思是任何類型都可以)
propB: [ String , Number ], // 多種類型
propC: { // 必填字串
type : String ,
required : true
},
propD: { // 數字,設定預設值
type : Number ,
default : 100
},
propE: { // 陣列/物件 預設值,要由一個「工廠函數」回傳
type : Object ,
default : function () {
return { message : 'hello' }
}
},
propF: { // 自定邏輯函數 驗證
validator : function ( value ) {
return value > 10
}
}
},
template: `<ol>
<li>propA: {{propA}}</li>
<li>propB: {{propB}}</li>
<li>propC: {{propC}}</li>
<li>propD: {{propD}}</li>
<li>propE: {{propE}}</li>
<li>propF: {{propF}}</li>
</ol>`
}
}
})
new Vue ({
el: '#non-prop',
components: {
'bs-date-input': {
template: `<div>component Rendered</div>`
}
}
})
new Vue ({
el: '#merging-attri',
components: {
'bs-date-input': {
template: `<input type="date" class="form-control">`
}
}
})
Vue.component('button-counter', {
template: '<button v-on:click="incrementCounter">{{ counter }}</button>',
data: function () {
return {
counter: 0
}
},
methods: {
incrementCounter: function () {
this.counter += 1
this.$emit('increment')
}
},
})
new Vue({
el: '#counter-event-example',
data: {
total: 0
},
methods: {
incrementTotal: function () {
this.total += 1
}
}
})
new Vue({
el: '#vmode',
data: {
something: 'XXXXXXXXX'
},
components : {
'custom-input': {
props: ['value'],
template: `<input :value="value">`
}
}
})
</script>
</body>
</html>