* W( {) A" w2 \<div id="app">" y: {* r( P* p$ @% v" i1 S
<todo></todo>+ g; s+ c0 ~& `/ M& T$ m! h; r) N
</div>. }# l/ S* j$ v8 c
<!--1.导入Vue.js-->: T) ?1 D3 i' x! m1 q
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>" v' X" o5 V, y2 w/ U
<script type="text/javascript"> 1 l7 K: ^+ \. z% \ Vue.component('todo',{ - Y( F% v; _/ ]+ Q+ g template:'<div>\ N9 j% C/ C7 F' r1 O9 D <div>代办事项</div>\ 7 v/ D# m0 X$ I <ul>\ " j }" Z6 a% n$ Y0 ]5 v1 f <li>学习狂神说Java</li>\% J2 I0 r$ @6 t9 ^
</ul>\6 g' [7 V, G) N* i4 y
</div>' 2 M$ l w w \ })3 M6 ?0 [+ S; v
</script> ; I* Q3 `* `3 l( ?, W1/ m6 k. ?& _( g3 e8 O: u2 ?
2 ( E# n8 c- l8 w7 @9 A5 ^3 / b: }% X# K" v- _& X" P+ ]2 `4 i1 k2 ]' n! [6 [- F/ R
5 . r, S9 e* h6 B3 E6 4 o) d- h! |0 e/ v* k7/ X2 r/ Z' V$ h" [# Z
8$ @/ ^ E5 K6 n1 ~9 e5 e
9 ) q1 F8 m+ ?1 f) U" g A) F9 w10 ( m6 N, U S7 n/ r3 C) G11 # N3 p5 g: w" d/ m; U ]! ~12 8 ^% o/ Y/ p6 Z9 c) |3 m Z* o13, I' N7 t0 |" S
14 5 a- z* G, [, S- `! ^5 G. y- o4 Q# f15 ' n; |" U/ U/ |" l. O( q5 M6 p第二步 我们需要让,代办事项的标题和值实现动态绑定,怎么做呢?我们可以留一个插槽! 8 B6 C9 Z# h, b& n/ m0 U; m 1-将上面的代码留出一个插槽,即slot$ L7 @6 `$ ?% J+ p
% v$ H( E: g- t% P) ]/ I. ~# W3 O& M: H! Y" O; Y5 \2 [
Vue.component('todo',{ 6 H# C) W, G, y template:'<div>\ ; a' {9 R& Y, Y1 ?; { a: e <slot name="todo-title"></slot>\& |2 Y: I$ I9 J9 H) C! {
<ul>\ 0 ^. N+ m7 t3 d9 _( B <slot name="todo-items"></slot>\, |. n0 i! f- X# Y0 x- P
</ul>\ 5 }& _% `( ^* A( T4 Y" | o e </div>' q9 v/ M& E" m* ^7 r$ e6 l' { });4 B) N! z8 J; k/ c* _% x P, s
1 3 I: A5 P" i. v. ?; v5 C2 , \5 }( A4 c& w. t" g" c+ b3( {' r% F7 s; e) L/ d- O
46 C0 I! x; {" _& K! @3 M
5 E* G+ D" D3 {8 b9 |1 n6 5 p9 B' q. x) ~) g9 A: s$ r, D7 0 g$ C" b8 N: b6 M H% p8- c, L7 d+ [7 }/ W- H: B& h& |
2-定义一个名为todo-title的待办标题组件 和 todo-items的待办内容组件% \' N! \& m! X) n0 O4 U! [
& Z `# r' P7 m. b, |# N2 N) p4 W$ C5 m6 V$ i& U0 T# |: p
Vue.component('todo-title',{% F/ \0 z& Q; m F' P
props:['title'], $ |" d) \3 G3 l7 f template:'<div>{{title}}</div>' ) N/ g& ~+ a- y }); $ J U2 T& c/ s2 }, O ! V- Z$ O! _) T5 S12345 0 l. J- p; _- V) t1 K' q8 D% p//这里的index,就是数组的下标,使用for循环遍历的时候,可以循环出来! : m6 L9 K b, K. h h S Vue.component("todo-items",{ 5 _$ H; P3 ]4 a props:["item","index"],* H5 ?. J- ^' P% t. i$ ?# ^
template:"<li>{{index+1}},{{item}}</li>" # ~. b0 L0 x; l2 h' r$ a5 T+ h9 F2 d+ \ }); + b" ~; B. @+ f2 R) u) W1 % r' `# ?5 n& C* |, c5 h3 y2: W+ J# M' f. a; A6 g0 ?% S
3 # @& L) v, }! D/ e, J4! h4 p6 p, y1 b5 y2 M8 k, _# ]
5 " k3 u; ^7 n" J! r6& W' v/ W, h# X2 v& x
7. f' M5 N( p7 T! g3 l, |, C3 m# v# N
8" y* r% @, a4 Q; m+ ]8 \% i
9# N% L; G. i0 j& Z& s! P
10: ]# U1 U0 T* U R7 B
11 , x9 p4 n6 {7 C0 i1 l3-实例化Vue并初始化数据 ( M1 o+ M( Q4 l/ }0 y, r A! t( O4 F' t! d: M3 {* p, P7 p
+ X+ ]4 {3 F& _0 d var vm = new Vue({% _ O+ c. @% `) L0 e- f4 x s0 x o
el:"#vue", % H! `# \7 U8 J6 i9 x data:{ / u* P% o' C( k, m todoItems:['test1','test2','test3'] 1 i: E/ d1 q2 Q } " U. L, V" W- g! o! N" \7 ^1 } });7 p3 v3 k; G4 `2 N
1: v5 {( J' H/ E3 o8 s. D6 C( J& C
20 ]0 H7 G2 F/ n3 k0 d1 A: t. ~
3 5 [2 ~+ G! K- [* c$ s48 n" X" N4 w: H% t/ t( P
50 U3 F( k0 }+ H9 v& x5 D( g( z- @
6: I: ?! W( J" i' V+ P# Q* e
4-将这些值,通过插槽插入 # a& e2 N3 l5 n5 ?; R7 ^" k7 d) ^1 j! X& j/ w# A' g) Y
+ V( t+ J* o$ e/ e$ o' L<div id="vue">3 z9 n' j3 R- h# D, y
<todo>9 k- w- Z- M9 M% p) ~
<todo-title slot="todo-title" title="秦老师系列课程"></todo-title> - S8 {" H7 `. ^: J1 T$ e <!--<todo-items slot="todo-items" v-for="{item,index} in todoItems" v-bind:item="item"></todo-items>-->+ R; t& y* D0 a+ d
<!--如下为简写--> 1 m4 H; _" J- _' V <todo-items slot="todo-items" v-for="item in todoItems" :item="item"></todo-items 4 y; ?$ U7 i8 M' f0 \' u& o </todo> $ {. a2 v! }& W- z1 H2 g% A' v8 I</div>9 {1 K4 q. I& r) j6 ]! L
1( N+ M) ~4 u4 ^ H
2 $ C8 W Y$ t, y7 t6 a3 7 w7 A& ~' i! e; h" ^! ~4/ i) e# y; m( ^" }9 G
5 ' K6 R ?. I6 Q- \, Q- C6 Z3 P/ A+ s% T e& b2 ^$ o7 , q+ ~& L, J. C" r/ z8 e% n8! U/ @: N* z9 i
说明:我们的todo-title和todo-items组件分别被分发到了todo组件的todo-title和todo-items插槽中/ r6 ?) J2 c. E* `0 g. e. n
完整代码如下:' _) \' [' p! P$ P
; `0 `' G" T6 T8 R7 O
9 r/ a; \ v* ?$ Q<!DOCTYPE html>) L) Y3 W% \ ~- c4 {5 N
<html lang="en"> ) s! W1 y2 H8 H+ L w. {7 Z+ U7 ]<head> ' |. G' R) i3 u9 K! c* {# a <meta charset="UTF-8">5 H% R# m1 }% r# U5 k
<title>Title</title> 4 p6 \# ]# L1 S: a</head>: K/ e: {3 J; T5 M6 N8 d: U
<body>' t$ A7 E _; H* n+ M
<!--view层,模板--> - T- F3 A4 h: b4 h5 r0 a9 O5 a<div id="vue"> ) q" n" U4 J' I* d' | <todo>2 [/ m- ~3 B4 }/ e
<todo-title slot="todo-title" title="title"></todo-title>$ f1 `% D: w. I2 r1 M% k
<!--<todo-items slot="todo-items" v-for="{item,index} in todoItems" v-bind:item="item"></todo-items>--> 3 p9 H3 ~9 \0 e" d5 l <!--如下为简写-->' q/ |& {( L" E! ^9 \8 Q7 x+ e Y1 R
<todo-items slot="todo-items" v-for="item in todoItems" :item="item"></todo-items 8 o5 h9 I! G, Z; ^! h </todo>" Z6 {- X' C5 \* w( q
</div> $ X5 q C% E7 s. j, \<!--1.导入Vue.js-->" p- E- d2 i' y+ I" R
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>, c2 F: |" T1 P) S
<script type="text/javascript">2 a; H& P+ W* R9 B
Vue.component('todo',{ 0 J7 y) ^6 H# x _) |7 s0 |) ]3 [ template:'<div>\ 1 b3 A+ M6 I% S) Y9 M <slot name="todo-title"></slot>\ + q! Y$ ^0 k3 E <ul>\ 4 X9 ?$ z& c: M2 M$ R$ C1 _ <slot name="todo-items"></slot>\ 1 G4 E# I; ~) O' g# F </ul>\# _, v5 [6 o5 y/ Z; S
</div>'" X7 E' d4 R5 Z
});: X2 H+ S5 d! d3 ]2 T+ w3 w. N
Vue.component('todo-title',{ 0 t( k# b0 [& f* x: V+ |5 N3 }7 C props:['title'], : F" l, G8 ~8 l X6 } template:'<div>{{title}}</div>'3 q; r5 O% h4 g
}); 2 x( X- Y$ x5 _! u //这里的index,就是数组的下标,使用for循环遍历的时候,可以循环出来!1 \$ Y6 ~) \) `5 M- D8 ]
Vue.component("todo-items",{. u0 u) h1 g6 i2 s( s' h0 }3 P; n
props:["item","index"],& A7 K* f+ _; ?4 m' `: t2 r3 n2 h
template:"<li>{{index+1}},{{item}}</li>" & S0 Q/ y$ ?8 @( q6 F }); 9 u; L. }* O- v* J 9 t% y q6 M: C! W7 D" n0 S' T! t+ e a! }: G5 {
var vm = new Vue({ 0 X7 Z! U$ c$ N6 ^- T* { el:"#vue", 6 H* E; ]- q" N7 a( p data:{ : ^9 O, l) _ p, G9 z title:"秦老师系列课程", 0 y2 j3 `/ n8 n1 P. [ todoItems:['test1','test2','test3']6 s- o i0 E1 c! Z3 J g
} / v1 P3 c& p0 `7 X2 } });! `: U5 R2 j9 V, I, E$ F) z
</script>4 m8 c0 ^. Q7 W1 h/ X( Y0 u
</body> ' t, u& F' j; o' p% X0 d2 W" m! g</html>5 Z9 G1 c5 U) c
1 ; o5 n* X- m. X8 y% b2 , X& b6 Q# r: f/ ^! H3( ]% t9 ~& [6 s& B/ _4 ~ ]4 `
4 0 Q# A: J: C/ }/ Y5 0 S) \8 }3 c! E5 ^6 2 e- P* z8 Z* w0 a7/ J# |' T" t8 b. |9 W! f* z
8 . k' ]* ~. u' q# D93 K( d+ @3 u+ X- _* V! [" w/ b
10 8 m" T$ T" @% j+ N6 E11 9 I+ Z8 ?/ z% D# h12 ' h5 w" E8 h/ x* t4 c13 ! }0 \( q) ^0 C" R14 8 o4 u' T2 k5 g9 B15/ j4 g4 m6 L# j- g" S- Q U: h- j
16% V/ p/ B6 P$ ?8 Z6 |9 C; v9 y. L
17' A2 A8 a* @: O. |0 s
18 9 T# k y( b( h0 W19 6 G: W( X. A/ E1 i4 F2 L20 ' k4 @! G6 U' a' B4 I21. {" ]. i, T: `& O& g1 I
221 Y, F' L# D$ @- F6 A z
23 ) _7 r, D5 q0 q0 e# x244 { _9 g( Q0 e0 m' O3 [0 a) t0 X
252 c* u' a1 J' h S) p/ ]
26" H, {, n& d! R8 U: n/ h) e
27; y$ {& G' w5 A! T. k
28 1 t- ^1 k( L' p/ n S8 R: O; M29 . W3 y( r, m! z, Q308 Z- I: I# M4 ^$ L/ A6 N4 J& K
31" h: e3 I. c8 _0 V m
32( o* B3 q# F, X8 I6 D5 e. O) a
33+ y* \ g! ~! q' J- k, a
345 [8 e/ o( ^" p( f$ `
355 s9 x. D% N d
36 2 q# f# H# u- l& T" G. Y/ W' \37 9 D3 ?( }7 e9 g+ ^+ R38 6 ~; ]$ J3 k4 x: @# o39 6 t8 A! Y9 v. |. _40 2 D t" }' }6 o* X/ T4 S2 k. B41 9 r! W, u" a8 w% `3 l+ n42 _* }! A! i* i$ d6 i4 D, O; D
43 6 A; U; I2 l4 I3 G. V" D3 }44 - c! `3 R: p( e. o. T6 I! x45 , F; V: |& _% F/ P1 G1 F1 j46 8 k5 I- O. g, F' ]7 B47 / w, F' X# ~: M8.3、自定义事件 . d, c% }( i A, e9 C" g2 V通以上代码不难发现,数据项在Vue的实例中, 但删除操作要在组件中完成, 那么组件如何才能删除Vue实例中的数据呢?此时就涉及到参数传递与事件分发了, Vue为我们提供了自定义事件的功能很好的帮助我们解决了这个问题; 使用this.$emit(‘自定义事件名’, 参数) , 操作过程如下:) x6 Y9 j' I3 U# M) U
1-在vue的实例中增加了methods对象并定义了一个名为removeTodoltems的方法- y1 G: ]! j2 z- B$ R
9 m& J* Q @! W/ `$ p5 K$ l8 _; @, C. I& {9 _7 P: S
var vm = new Vue({ - R8 s) |+ Z! o" S! `# T el:"#vue",2 K0 P0 O, w V% ]( e, p4 x
data:{ $ `4 u5 {$ [) P% Q1 _/ J/ `; ^ title_text:"秦老师系列课程", ( i. `( @: s8 u* k7 @. m todoItems:['test1','test2','test3'] / ~% }/ X7 L4 p! J/ b4 e. k, z! B7 U },: I+ c E! q+ G* a. w B
methods:{ " C2 O6 K' f' @3 C5 j removeItems:function(index){5 H9 U M" f9 T: P
console.log("删除了"+this.todoItems[index]+"OK");0 [ M+ ?: n& \) `' `2 Y6 ?, {
//splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目,其中index4 J% `; r7 `, a. c) r4 z: Y7 g
this.todoItems.splice(index,1);% u2 _8 S0 S. B: }$ r) l
}) a2 x0 C- l/ M* C. V
} / D$ o3 G; Z- Z2 `7 Y }); 4 k: ^% ^" `/ C( K9 R' [1- b9 M3 K6 G: l- w. t
2 , v: a P' z* V( h3 ! C. e8 K, @5 h1 U4 w, S4: v9 b$ k8 v% B2 t
5; `* J* `: U$ i' E/ P/ [
6 # w, ]% I. m6 j6 Y5 c8 a8 s7 ( c8 ~/ ?, R2 `0 ]" a7 _80 T" d5 z! _7 H
9 2 L. j7 r* ~; e10 t- Z' s' Z# y% R! d7 q5 L* q" p" w11 1 u1 v1 L1 z% Q7 @* @( l7 B12 _, O# r: H# x6 s3 p
131 z. K8 ?7 x0 \5 D
140 ]) b0 T$ j# D/ ]4 \' j$ G
2-修改todo-items待办内容组件的代码,增加一个删除按钮,并且绑定事件! - A8 _8 c: }/ J% C: E9 ]+ X ( C) S; l( {- ] 8 u9 Z5 T, V+ V, c Vue.component("todo-items",{ 4 }5 }9 b% q# o) _& i W props:["item_p","index_p"],' D% i+ n4 }3 O* k& H A
template:"<li>{{index_p+1}},{{item_p}} <button @click='remove'>删除</button></li>", - B1 b- Y* `& A5 L% p% B$ e methods:{1 o4 `& Z0 y3 X- L* z( _
remove:function (index) { ; L8 k% M% e% ~2 P* U3 P //这里的remove是自定义事件名称,需要在HTML中使用v-on:remove的方式 ' o6 x: d( p. ]: y+ T& V0 M* K //this.$emit 自定义事件分发 o2 T, i0 ?3 X/ G9 x
this.$emit('remove',index); 7 C! A; L1 J" d7 s+ x7 b- R) Z5 A3 [ }: N" @7 T; Z! a V( F; f/ b2 \
}+ N! M4 W1 t9 v8 _# h% @
}); ( J. f9 }# M, W, N8 `1 + S6 b5 j& ?4 O2 v6 Z0 Q; M+ V B- z2 $ `" d# y/ H1 E& U4 s+ g' E3+ w$ m! w. @6 d5 A0 v! r2 {
4 8 _* S a- f% C" Y9 l* o55 w2 N/ l4 ^! N# A: G5 T
6 ( l: T! A) u( Q) J6 \( j7; M; O6 r7 M# q8 w# i
8 : c8 Y3 p) J" a. y: o+ Z9 . S8 l& d2 k9 A! }: T3 D) T109 q4 j7 H) H d/ z3 E; V( |8 o7 C
11 % s6 `' Y; ^; f, D2 e$ U3-修改todo-items待办内容组件的HTML代码,增加一个自定义事件,比如叫remove,可以和组件的方法绑定,然后绑定到vue的方法!3 I0 ?) _9 m$ q& h6 b+ }7 a
) ~/ | S! P9 M+ j: A @; t 9 X7 H& O" P* v+ Z<!--增加了v-on:remove="removeTodoItems(index)"自定义事件,该组件会调用Vue实例中定义的--> 3 q4 }- Q% F( M* w1 L! }6 E<todo-items slot="todo-items" v-for="(item,index) in todoItems" 0 L' i% T! g- S2 o' A :item_p="item" :index_p="index" v-on:remove="removeItems(index)" :key="index"></todo-items>% H" r& ~* |" c0 ?' u; p9 r
1 % Y& i/ o! ^+ d- \; J, r! i2 # b( O( G. V6 ]( G1 J3 A8 d0 d( k3- x, n7 e, N0 j' h
对上一个代码进行修改,实现删除功能0 F C- J+ _9 D) G1 l; ^# h( I
" q7 G) h( U0 x0 r0 {0 v - I( t3 z) I+ x( r9 |) Y<!DOCTYPE html>4 M, Z0 s$ `6 M/ f2 W% G" ]
<html lang="en"> * D$ L8 D+ K5 x# ]& i) e9 C<head>+ g4 z2 G9 L0 j5 N8 [! l: J
<meta charset="UTF-8"> " T# e O) f" V, C N <title>Title</title> , _$ M: R5 |# _</head> ! ^- I, `6 C# L<body>! `8 x. f: d4 ^0 d* F/ H
<!--view层,模板--> 8 T f l5 c3 ~4 G7 k<div id="vue">3 K( Z' B2 R$ Y+ s" V
<todo> 8 j* b- j2 j1 {9 N' E <todo-title slot="todo-title" :title="title_text"></todo-title>1 x% T/ E/ T0 ?. S
<!--<todo-items slot="todo-items" v-for="(item,index) in todoItems" v-bind:item="item"></todo-items>--> * L$ s) a& ^3 \7 w <!--如下为简写-->) [; {2 [/ ]2 ~% [
<todo-items slot="todo-items" v-for="(item,index) in todoItems" 8 O: u4 k; J5 e- U :item_p="item" :index_p="index" v-on:remove="removeItems(index)" :key="index"></todo-items> ) j& Z( n x. S' z7 w </todo> # p% J2 ~; B; j! e# _$ z7 _$ Y! O% k( W</div> ' Q* [! P6 G, S: N, G" F<!--1.导入Vue.js--> z$ `1 X2 i q. w, I3 o
<script src="../js/vue.js"></script>2 t. l5 l8 k# F, `
<script type="text/javascript"> ; Q3 K7 D5 S7 b; U l Vue.component('todo',{5 D, U6 x& \- ]) e" E
template:'<div>\ 6 N, _0 A+ z& p0 O <slot name="todo-title"></slot>\ " Z6 m% k; v- f0 Y <ul>\6 R; r! b6 o( n
<slot name="todo-items"></slot>\ ) @, c% y% J) `6 Q3 \% R$ j# g2 T </ul>\. p( W$ E8 I! M' K; D: b. n
</div>'( \4 L1 x% U. v: `( U$ [$ p
});/ n( s4 o+ U3 @# N% d
Vue.component('todo-title',{ 9 [( r8 J: [8 R; `1 p props:['title'], 1 z1 U7 L$ b/ t- y! n4 H template:'<div>{{title}}</div>' 2 U! V7 |- D- A9 ~7 O; ? }); & |+ H. f* [5 e //这里的index,就是数组的下标,使用for循环遍历的时候,可以循环出来! 1 F+ Q; t: f+ M: @ Vue.component("todo-items",{ Y7 M5 q7 v& O- R# w+ F/ B props:["item_p","index_p"],6 A# V* P' T# W, A4 G& B
template:"<li>{{index_p+1}},{{item_p}} <button @click='remove_methods'>删除</button></li>",# p( B0 M7 Y4 T5 X# y- o
methods:{ 7 P( w7 M( n/ B remove_methods:function (index) { . V& j7 N( N) W; D, m5 O3 k //this.$emit 自定义事件分发6 l* _5 r, E& y* ?" F, C+ _2 b: S. i
this.$emit('remove',index);6 h7 @+ h0 \! h8 ~* k* c
}, z' z" ~6 ^8 C$ T m& h) }0 P% }, F3 k
} ' r: B0 _. F/ A });& U5 P" y, U; E, j6 n9 @, g2 r1 l+ k5 m& Y6 t
, E k% M# n; z, n: @: z
& q/ V/ {/ L9 K0 |: w
var vm = new Vue({ " v, q F$ F) H. M& \ el:"#vue",: a4 s' x a, H V8 k
data:{6 j/ g/ w- i' M1 e
title_text:"秦老师系列课程",8 ~) D* k* \" o1 D
todoItems:['test1','test2','test3'] $ J; p3 `/ ~1 A! F$ o- f }, * ?4 F2 C2 j. V5 O) ?7 Z methods:{6 u) m- B: t2 D# N3 _% P
removeItems:function(index){ . V( q0 v- X( i6 R3 J console.log("删除了"+this.todoItems[index]+"OK"); * p* D5 X. j" Y7 m' Y this.todoItems.splice(index,1); y% T1 {2 Y# M% M+ F% a& x }4 t; s x x; N8 a" z
}2 x& y6 e! \. u7 S; N; `
}); 2 \' Y- ?( _) L</script> * P, |8 R% W& {8 {</body># K4 D1 q( F) M' k
</html># j$ j. x" h8 U
11 s) k- A7 }/ g8 [; d- W2 r
2. {! U3 Z# d& b8 u9 ]$ J
3 ! f' S9 {3 N! ]( ^% E% I* |3 w4 ' M3 |- d1 y( _# O) v) z5 . a( h6 Q; ^3 E. ` } M7 ?9 d6 5 M9 b: a: w7 ^: _7 ' t! N% B0 T7 l3 C4 n8 C5 \9 `7 R, S# c& G. {; s" o
9 6 x V9 Y: g) O: L9 P# }102 k" ^' g) R6 I
110 \' Z( Y* n* q/ g
12% s; n1 a) L1 y. d
13 8 Z; l/ \. o w14/ l) t3 j% L# r, l# y$ k
15$ [6 {. _2 W. J+ C% o% c+ g. O' r
16; p6 w- I n6 E9 G7 p
17 ) o2 t B' [% P! a9 S/ I( o18; [8 z0 g$ T* C) d5 N0 O* a
19 4 V+ F) G8 T1 y( F$ I+ Z. y3 N3 n20. t. K' A) S; l- m$ m$ a; ^. a8 s
21$ [* c) g. G0 y9 v0 T, c& \4 T" |7 _
221 ]$ Z0 Q8 R: m% e7 S
233 V8 y. X M# \
24! q0 p) l$ z3 ^
25: n# T e* M" }$ g2 d0 c
26 4 [4 }; W. j8 \( [9 K) g272 V% d& C, ^1 a: U, V! N9 w1 k% {
28 ' N2 ]& j; ~+ t2 I9 i% k0 m29# q. w2 Q1 S1 l* ?+ S% s+ N% E
30 5 p9 O. R( b2 V, s6 {+ {/ o' x31) n) m3 c8 N @8 t' {* Y5 |
32 , f9 N& s1 h& g$ r' d* D" ~33 3 h0 n+ p6 O2 I+ e0 l34' a3 y! S) N+ t3 ]
35 / C B! R" ~& ^- h36 , m/ u6 h1 e# |371 r) @1 s: f. W- S/ I" ~ W; h' q
38/ F/ n# l2 [" f6 F/ N
394 \: q2 H4 V- P' {1 ^$ }6 |5 p) f1 a
40 7 H6 @; j' b) _) R4 t' p41. n0 I2 z' N! @4 ~- z, L8 Q( w
42 2 { V9 x. M1 ^' ^43 # u5 g/ x0 Z* K6 P% I- r/ Q44 ( h( r" d" w. R6 U9 F* \6 ^. }45 * ]% [; W0 ^* a% \& b# A' r46' |( h& C# J! X$ } W
47 8 F: g7 Z+ |' v) |8 I( e488 m! j0 n5 W4 D7 X
49 . f- t+ m6 K- k g0 s503 A: _7 J- \3 B, c
511 s7 r! v6 d' q. K0 v5 H5 }! z
52 n& t* D6 m: |1 f( }2 d* |0 d! l53 2 J }0 n8 s% Y3 ?: Z( H0 }54/ |/ U2 c, K5 N; V: d4 S: h
55 5 f; c3 r# c a* H! x: N56 : S: }5 ^7 p5 o% u6 _5 z H2 h& M- u, T57* ]0 W& u J! V9 W- x- G
58( R% Z% L' e, T# }7 T
59; [6 P3 r: @" X
60 + k+ R0 l% t4 e- a7 c9 Y1 x逻辑理解7 E5 y5 ?; `. L' D) w
# ?. n8 D$ E1 I9 d( t$ d h, F3 y
( y$ H/ X8 r) M
; x5 E: E3 A; y: I( i- l
' a# x4 l, R9 H. }; _' t
8.4、Vue入门小结9 |6 C, t8 |9 [1 z
核心:数据驱动,组件化 9 r' T5 i$ a! k/ b) ?6 H3 B" M2 S3 g6 y. X, T" D: q" B, {
4 d0 J4 g z/ X9 h' K优点:借鉴了AngularJS的模块化开发和React的虚拟Dom,虚拟Dom就是把Demo操作放到内存中执行;# v Z/ Q- P1 |& b1 Z p; E' F# Q) i
1 C% B$ O; o' H$ y3 | * ?: v/ `1 r& N( w) R常用的属性:2 F4 A; I6 s% [% Q( u I; S7 m: k
+ D' m3 d3 r# i3 Q8 F
9 ?+ [) i3 s3 k1 o; G/ [
v-if $ [5 w' z% P! a. z8 ?v-else-if " _- r4 Z, ?! Lv-else 2 D& r, x2 M; j. m! }& av-for' G# K! s Q4 m5 H! ?
v-on绑定事件,简写@5 Z0 D/ W6 m+ }, L
v-model数据双向绑定 ! L' _( z- Q: E+ iv-bind给组件绑定参数,简写:6 a5 [& Q5 b# ]* E
组件化:6 n$ f2 P7 p( I2 ~7 w
! g. |8 A: M! \4 H0 N C' P! X0 k5 ^! w, k, U
组合组件slot插槽) z/ X+ y. D1 m5 ^) e/ p# R
组件内部绑定事件需要使用到this.$emit("事件名",参数); * v! a* \3 e4 X计算属性的特色,缓存计算数据 5 r& T2 m, J4 c遵循SoC关注度分离原则,Vue是纯粹的视图框架,并不包含,比如Ajax之类的通信功能,为了解决通信问题,我们需要使用Axios框架做异步通信; 8 r1 n& ~$ y; T 4 }3 e, U/ o+ Z* I2 q1 L; v( j0 K7 U- V
说明 2 j5 y, @3 K6 [0 U7 ~* pVue的开发都是要基于NodeJS,实际开发采用Vue-cli脚手架开发,vue-router路由,vuex做状态管理;Vue UI,界面我们一般使用ElementUI(饿了么出品),或者ICE(阿里巴巴出品)来快速搭建前端项目~~ Q# K! _/ j* I' l4 \2 U9 g/ _7 Z) q
8 I# R2 Y6 E, n, ~官网: * M: \( M# A+ k: k) e" r* L R% q4 l2 j; F( Z# T ; c8 W9 F" p6 |1 E6 Dhttps://element.eleme.cn/#/zh-CN 3 G+ R. ?1 y% b2 |https://ice.work/ [5 I ~% C/ O; V7 R4 d九、第一个vue-cli项目8 V! u6 r, U3 z# Z# {" H8 v
9.1、什么是vue-cli" y; v. `4 Q; Y3 @2 q
vue-cli官方提供的一个脚手架,用于快速生成一个vue的项目模板; * \8 T" ], k5 S& `: i 预先定义好的目录结构及基础代码,就好比咱们在创建Maven项目时可以选择创建一个骨架项目,这个估计项目就是脚手架,我们的开发更加的快速; ; a) M3 _5 I8 z. o" c 项目的功能 1 {/ U3 _+ Q# P; c% U: i" P) ` - X' X8 t/ x; f3 s6 V2 @# i1 F " Z1 f) E0 `$ K: `0 R# d统一的目录结构. I$ ]5 R5 i/ L2 X3 ^" s( b: l k
本地调试* R$ ~6 c. m7 y5 Y$ ?8 G
热部署; E/ v- _) v) d6 [2 Q
单元测试4 T' S0 m( K9 u3 D1 o
集成打包上线 / Y, V- S) u0 k. L" ?9.2、需要的环境" k- w" u" x4 }( ?) T& ~
Node.js:http://nodejs.cn/download/" e6 k6 C' t# d" d& w
安装就是无脑的下一步就好,安装在自己的环境目录下 $ A5 \2 B1 C; J/ MGit:https://git-scm.com/doenloads& k3 z/ K1 B2 Z4 l4 [: M/ O A
镜像:https://npm.taobao.org/mirrors/git-for-windows/ 4 r1 b# [6 m7 @ Z! t3 P7 q4 G确认nodejs安装成功:; c* g! i1 E0 g G- ?. ~
. a) }0 _& j$ m' D- U% c " M7 g1 C: C% E. Q/ B7 s: W hcmd下输入node -v,查看是否能够正确打印出版本号即可! 6 R% }. N7 L ?cmd下输入npm -v,查看是否能够正确打印出版本号即可! $ N- E6 B4 J7 M! M这个npm,就是一个软件包管理工具,就和linux下的apt软件安装差不多! ( R8 Z- }4 Y* f1 L1 S0 j 安装Node.js淘宝镜像加速器(cnpm) : I) g( \3 R1 p 这样的话,下载会快很多~ 5 ]" e4 U( E& F( N/ V8 \& F" |# -g 就是全局安装 }: M' ] V3 U! k! ?# ~npm install cnpm -g : q$ a& h( p7 S) E / {0 y, r7 V+ ]% h# S! P: P4 H$ V
# 或使用如下语句解决npm速度慢的问题) V7 W+ M4 k& T: ?! v
npm install --registry=https://registry.npm.taobao.org' t" f$ ^% a8 j$ k0 d1 q7 P$ m
1 ! b6 Q1 S! M. P7 ]- G' a2 # @. c4 e" R2 w( B3 % P: N v/ n7 |4 m8 m# q- D44 {+ y6 Z# f* S+ P3 A- \
5" H3 B9 W. b. G0 G. K' L) g
安装的过程可能有点慢~,耐心等待!虽然安装了cnpm,但是尽量少用! 9 }& T( |: v* N* X: `. t 安装的位置:C:\Users\administrator\AppData\Roaming\npm" P! e/ D+ a9 i% C
T) M+ |+ ]" d( [# q+ E* }. } * b$ _; Q/ ]. V% K* f $ ~+ I% [' ~, o- t- A. t+ b% f * V5 \ J3 I x7 k7 o+ f+ L! m2 W" G+ _, ] 安装vue-cli1 ~* s6 W0 _' g' P3 o k
; {, y* @& P3 @$ A% p: A ~& r1 @5 P( K' n t, M# x
cnpm instal1 vue-cli-g : G4 }- X+ n h2 Z$ X0 i1 a#测试是否安装成功#查看可以基于哪些模板创建vue应用程序,通常我们选择webpack * u4 x* o( W2 O u/ c5 F% p3 hvue list0 `# j" k1 k+ }5 h
1! {( a+ k/ b! w3 H* _
2 ! P9 F# j* v) G) j* _3$ K( C/ w# x5 k9 i. N1 @
) _5 J2 j% C) J ! T+ m" Z- h3 ?5 ]0 |* f/ q* s 9 Y' y0 Q% e7 P& i! h, w# o% b' S, C3 k0 g2 _
9.3、第一个vue-cli应用程序! O0 Z* l, o. E9 ], y- K7 u1 A! A$ u
1.创建一个Vue项目,我们随便建立一个空的文件夹在电脑上,我这里在D盘下新建一个目录' V3 j( u# e1 B U& P' M% y8 ]$ M& s/ R
3 Q8 {/ b+ ?8 [9 {6 ~7 } 9 Y/ J: a3 ]' a3 p( J7 |- wD:\Project\vue-study;* g; |$ j8 d( `0 K6 s" B m9 d
1! c) v( h# s: [4 c) i% m& S5 f5 b
2.创建一个基于webpack模板的vue应用程序- { g/ T1 o0 @0 C9 C0 U
2 ^ {. _- W+ O7 M, ?
' G# b4 h4 @/ P* R0 r#1、首先需要进入到对应的目录 cd D:\Project\vue-study 8 t+ U' N' v/ P+ e% y6 P#2、这里的myvue是顶日名称,可以根据自己的需求起名 ; c8 d! f0 o. P* \vue init webpack myvue& N" n- u; L: _5 F2 v2 S9 D& t: M
11 v4 o, R9 G/ c. w6 o3 x
2( E7 ^) l2 p6 w, f9 s& x
3 p/ I* x' y9 \一路都选择no即可; ' t+ W) W' c7 |; m" p$ G! a+ U$ a- R 说明: ; L9 y1 j# M9 ` / m$ C% p- c, @5 Y+ b8 D% X3 K* e( G9 R2 R) _
Project name:项目名称,默认回车即可7 Y& v& L3 u8 ^9 x, ^0 P
Project description:项目描述,默认回车即可 6 ^8 v5 U- K) B' o- E2 i$ ^Author:项目作者,默认回车即可 * j, C2 O# y& y6 R, IInstall vue-router:是否安装vue-router,选择n不安装(后期需要再手动添加)9 c( D# \, G7 T, O5 N. G
Use ESLint to lint your code:是否使用ESLint做代码检查,选择n不安装(后期需要再手动添加)4 j2 d. O! J4 d; ~% M N" s7 G
Set up unit tests:单元测试相关,选择n不安装(后期需要再手动添加) ; y# b% r1 M2 T$ i+ D) hSetupe2etests with Nightwatch:单元测试相关,选择n不安装(后期需要再手动添加) + o! `, R+ e" u( JShould we run npm install for you after the,project has been created:创建完成后直接初始化,选择n,我们手动执行;运行结果! 8 ~) d, l' u5 Q: I0 i9 F(1)初始化并运行 , i( B3 J# L& H. ~' x$ f& i5 A % @ m% v- x8 Q$ M$ f5 z X/ {7 S7 O o1 I, D8 p O
cd myvue& A& S" h. S3 w9 H1 J5 c6 G+ r |
npm install 7 i; S0 ^9 e5 A2 _6 e5 u) Inpm run dev4 ^" o/ T' A! n
1 , C1 K# E; ]1 I4 S3 N3 v. _2 9 U) y) T) u& M2 [7 q3 - J2 V3 O' D' c$ m& I执行完成后,目录多了很多依赖& R' g0 H! X+ D. W
7 r- y0 P5 t5 C A( o: J# \( R
" [- Y! R7 F5 k# |5 F7 f
当出现问题时,可以查看提示进行处理如下 ' v5 a6 s( x1 E' x( O* h% N6 _ ?' \6 d& g5 L
4 Y( F. }4 S1 p) E8 }: z
! J) F' R# [3 J# W' T
4 E) Y- [- w0 @# A. P; g十、webpack使用: `. ?& d5 f, j4 S
10.1、什么是Webpack5 z+ p. D( c3 t3 d# z! ] ~
本质上, webpack是一个现代JavaScript应用程序的静态模块打包器(module bundler) 。当webpack处理应用程序时, 它会递归地构建一个依赖关系图(dependency graph) , 其中包含应用程序需要的每个模块, 然后将所有这些模块打包成一个或多个bundle.4 m# p3 c) @) T; G o
Webpack是当下最热门的前端资源模块化管理和打包工具, 它可以将许多松散耦合的模块按照依赖和规则打包成符合生产环境部署的前端资源。还可以将按需加载的模块进行代码分离,等到实际需要时再异步加载。通过loader转换, 任何形式的资源都可以当做模块, 比如Commons JS、AMD、ES 6、CSS、JSON、Coffee Script、LESS等; , ~% E7 X6 M3 d: ]+ ^" ^1 [ 伴随着移动互联网的大潮, 当今越来越多的网站已经从网页模式进化到了WebApp模式。它们运行在现代浏览器里, 使用HTML 5、CSS 3、ES 6等新的技术来开发丰富的功能, 网页已经不仅仅是完成浏览器的基本需求; WebApp通常是一个SPA(单页面应用) , 每一个视图通过异步的方式加载,这导致页面初始化和使用过程中会加载越来越多的JS代码,这给前端的开发流程和资源组织带来了巨大挑战。 8 W' d' h. c7 @( \3 j" }/ @6 h 前端开发和其他开发工作的主要区别,首先是前端基于多语言、多层次的编码和组织工作,其次前端产品的交付是基于浏览器的,这些资源是通过增量加载的方式运行到浏览器端,如何在开发环境组织好这些碎片化的代码和资源,并且保证他们在浏览器端快速、优雅的加载和更新,就需要一个模块化系统,这个理想中的模块化系统是前端工程师多年来一直探索的难题。8 p6 l! b: g9 U* ?
3 v+ s+ U! m1 B0 C5 z: k, {& R" ^% a
10.2、模块化的演进 & F8 a! Y* [/ E! J5 M5 e/ GScript标签 + K# G. Q. ^& } J. ]5 F1 F7 f7 h <script src = "module1.js"></script> + V1 t- K b+ ?( `1 _8 ~! E8 { <script src = "module2.js"></script> O' x0 [5 W& C/ J
<script src = "module3.js"></script> & ?% s$ e3 t6 _1+ w6 |2 L. r: M& k4 S' u F7 q
2 5 _) B7 [. O o* ?( ~4 u; e3 9 e2 H4 J; \; }7 Q这是最原始的JavaScript文件加载方式,如果把每一个文件看做是一个模块,那么他们的接口通常是暴露在全局作用域下,也就是定义在window对象中,不同模块的调用都是一个作用域。) `2 r8 |" n/ C" ^" o! Z0 w; W& |
这种原始的加载方式暴露了一些显而易见的弊端:7 d! I& g T: }) V; o" P
/ @% h$ z/ R: D/ Q6 ]
( W- y' J" Z6 T: R
全局作用域下容易造成变量冲突 0 }8 P0 P( L5 D- L文件只能按照<script>的书写顺序进行加载 3 h: p0 J9 E1 d开发人员必须主观解决模块和代码库的依赖关系2 f0 ?+ g3 Q1 P" m) N
在大型项目中各种资源难以管理,长期积累的问题导致代码库混乱不堪 ! l# ?7 Z1 i6 B# B0 y kCommonsJS 5 z' I( N" w5 E1 ]8 a% e1 V B6 h服务器端的NodeJS遵循CommonsJS规范,该规范核心思想是允许模块通过require方法来同步加载所需依赖的其它模块,然后通过exports或module.exports来导出需要暴露的接口。 . L; S, Y% `" A9 b, n( [9 [$ I, P# G6 R" n7 a
3 O; ^: Q# w% W3 W2 Trequire("module"); . U1 N- x8 _* m3 Wrequire("../module.js"); * m3 z9 b _! W( k% o G* Mexport.doStuff = function(){};/ V+ F" t5 o3 f) ]: m. B5 b4 w0 T
module.exports = someValue; & P+ o1 V# {) W12340 H& f- q2 Q# R. V! V$ R
1 3 e+ B6 L$ ^# C& P2 X) A, K21 \0 }4 ~% u/ F4 \9 y7 w! a
3 / p3 E! V2 e# X5 U& @44 j- z! N9 ~& U% p7 v7 e! I
54 a: v8 r8 X1 K7 ^+ m
优点: # K7 V _7 X5 I$ v, A; V 3 s& R5 x- g$ Q: s6 s9 A ; z2 m' ?( T5 u8 p. h( V服务器端模块便于重用! x' I- h% f$ @. z4 S
NPM中已经有超过45万个可以使用的模块包! \. ~; K1 S' Q/ G4 d! L, e$ d1 ]
简单易用 ; U* _; s0 e! Y6 H$ x' q; F缺点: / t4 t' b% {/ l: c2 }, @* v! B' [, g/ M; {2 r: \! T
& o* C U" O% L' B
同步的模块加载方式不适合在浏览器环境中,同步意味着阻塞加载,浏览器资源是异步加载的 0 r. A$ }. y ?' [% K5 L4 G不能非阻塞的并行加载多个模块9 C1 p! }- ^ V. x
实现:0 X+ R; S+ e* `) g; v) ?
; A/ O( ~" q- N0 V 6 r6 X- @1 b* A服务端的NodeJS 1 w& k0 E. h$ H x0 v# |6 R" ?3 F•Browserify,浏览器端的CommonsJS实现,可以使用NPM的模块,但是编译打包后的文件体积较大 ! ^! \& K" G+ r0 s! L) h3 [modules-webmake,类似Browserify,但不如Browserify灵活% H) k; H5 Z: z4 p
wreq,Browserify的前身8 `& c. Z" Y+ ? p
AMD ; Z! @# _# \4 x* [2 CAsynchronous Module Definition规范其实主要一个主要接口define(id?,dependencies?,factory);它要在声明模块的时候指定所有的依赖dependencies,并且还要当做形参传到factory中,对于依赖的模块提前执行。7 O! q& S9 t& A- ?. Z* L
' x: Q; j2 E' T8 C; R9 O2 e 5 m) A( J1 ?5 g- w m8 _define("module",["dep1","dep2"],functian(d1,d2){ ]5 u: P0 e8 p return someExportedValue; 1 Z6 F" K. m7 F6 F% y});. X0 \: S( T% E7 W. {
require(["module","../file.js"],function(module,file){});* J% \! U/ [+ m$ m
12340 o7 S" ~' U* R
14 B$ r3 n; T1 P" U
2 9 X. F6 b t) O% \; X6 T3! r5 ~( P+ d* Q# n2 g
4) W4 u% L5 t* i: d! E/ m: z9 `
5 4 t, h; w3 `% e& Y3 h! `" B优点, M; U8 E2 d/ c9 i2 @! Z
, E. ~3 B! U- T9 t & y O Y3 F0 b, |7 E% d+ l- T0 i5 j适合在浏览器环境中异步加载模块+ N7 k6 C1 `1 z A3 T; a
可以并行加载多个模块; \1 g5 e7 A9 ?( f0 s. t5 O: t3 e
缺点/ t) h) a e1 v, L" n, E
! a Y9 a6 O5 T! m/ |
; v7 n( W( X# o% @! V提高了开发成本,代码的阅读和书写比较困难,模块定义方式的语义不畅8 f# ^& u3 k6 X2 u7 K
不符合通用的模块化思维方式,是一种妥协的实现- Z7 r& ], @' S$ l
实现2 q+ o" I( X. ]* _8 P# g+ I
- t5 |1 `3 ^( P/ x
% N9 n, M' C- ~- ` k% Q
RequireJS - C- p- h% Q% O- l* jcurl& O L- C* s1 {8 R: J6 m- w9 \$ n
CMD7 L* S8 V4 V$ i7 O7 _7 ]
Commons Module Definition规范和AMD很相似,尽保持简单,并与CommonsJS和NodeJS的Modules规范保持了很大的兼容性。 6 L6 K; ]# s- O* |" I# A0 g% |- ^8 D) e( m, P. X1 p# Z
9 y L6 F( u+ _" ^define(function(require,exports,module){' z/ p1 R ]: t' \" F3 N
var $=require("jquery");9 c6 ]) L( G0 [( u+ V% }1 }
var Spinning = require("./spinning"); " c- C! F. B' ]# |" J/ z exports.doSomething = ...;$ J6 k" x0 J$ I; ]/ b) V2 S
module.exports=...;, b+ m* l( x# t' ?/ G: D
});# J7 j8 P- g0 I- x
11 f! O- m% L. j; a
2 # K- s1 o' n+ d5 P) I( }0 T3% d f" D% _) p# I/ K
4 3 O% u! i! _! s" E5. Y# c) ?! t5 R# e( _* T. e
6 ) Z; o% M; D% u. n! d* v优点:0 `& S0 ~+ I; `# q7 r
- x+ d1 ^ a, Z ( ]! [) ~1 U' w依赖就近,延迟执行& X+ o* }; V, o, Z' r5 P; N
可以很容易在NodeJS中运行缺点 " R; b% F# I$ x7 H, K+ s' _: }依赖SPM打包,模块的加载逻辑偏重 % I# R8 K2 x% r7 a( L+ ?5 }实现3 \$ j3 J0 i2 C6 F8 C( u3 y
& p& i0 ]5 ~- R. M( `! Q<style> % e Q( k0 \) X/ e0 L#app { ) V4 |, c$ V+ [3 L1 n2 P font-family: 'Avenir', Helvetica, Arial, sans-serif; + V: @9 i4 \/ ~# I# A4 i2 r( y+ P -webkit-font-smoothing: antialiased; 7 R1 n' c; T" ?5 x( h# K, b3 Z7 w -moz-osx-font-smoothing: grayscale;& ]% x+ |# u, j! v
text-align: center; 8 n3 @/ C2 h, [0 b) [+ ^ color: #2c3e50;# S8 \7 R8 C$ }+ Q. P
margin-top: 60px;" T+ o* M& k! Z2 f. g+ u
} . ?" R9 M/ V* `</style> ; B- E! [ v- l7 D* J# L1- p1 O- P1 w3 c ]
2% T4 A+ l1 ~+ g$ n. Z, R
3" a: j) H1 T1 x7 F, }3 _
4 ^4 {; m$ a) `5 F. `
5 - m+ e4 h/ I3 M/ X6' {6 G. ?( l s f
7 b$ g3 ~* z: _- Y- L) W
8 ! r, p3 R, Q# v! L2 c, i9. Q- a0 X2 V7 _' J
10 ! Z0 H; ~! a) ?) g+ A( e11" l2 ^5 V/ {$ ~! s
12) _% p% u; b" u, p+ P
138 G1 x# k( {$ S! _( o: Y; P
14* B" b# H2 J$ z0 b7 E9 S" B
15 3 w/ j) c0 S! R16 # Z. W+ s& z* X5 @9 U& [- c$ B17 # |$ [- S$ H3 R6 }- E9 [18 ! |0 @$ F8 F* M5 Y: V& }" [$ X19 1 t# b, x6 O, N! u' a208 _2 S6 K H& R3 _9 ]( v
21 % s+ q1 B( x- d2 s- [' Y% a22 }6 J1 r( q' `' P) t3 }% |- |) ?. T234 O% P% r* w& M& U0 o
249 I O' N, y7 X! k
25 4 @) e8 S# L7 s* tmain.js 5 [" o/ {' M! _2 E( U7 g! l$ \ e6 M
7 ] Z9 W8 \3 |% T// The Vue build version to load with the `import` command& Y( a7 n2 B+ ~6 G4 Z6 N. J! H( y
// (runtime-only or standalone) has been set in webpack.base.conf with an alias. 4 S1 j& m* \- `9 G0 Dimport Vue from 'vue'1 X9 A; d6 l* F+ M5 j; q. F3 t0 W
import App from './App' 7 @4 B4 q$ r/ X* D$ I+ Dimport router from "./router"; b: I. N3 i6 {% O3 O
+ o+ |. I1 G7 N" @
* s7 o- W& \0 v. {import ElementUI from 'element-ui' 7 r- f2 f; b% }( d) l1 qimport 'element-ui/lib/theme-chalk/index.css' / r6 t9 ]5 ]) `4 R+ y1 D: Y; h4 E4 y* \
- c) \) n0 ?/ ^ @" \* G
Vue.use(router) [9 @# [% I* I2 yVue.use(ElementUI) 1 H2 D* j. y) r. I: U7 n5 j! u 6 s8 d% h' a3 Q( b2 S3 u% z3 X# c * x' v5 X; }& \/* eslint-disable no-new */2 g' C7 N W4 G$ K' o$ v. j; f
new Vue({ / @1 r K7 Y$ B+ c- x" H, F' W el: '#app', + @' K& w% m- R. w router, 2 y. C* v0 P1 b render:h=>h(App)+ S& K! Y1 B. K" |% P- Q$ f
})5 I( O3 `. g4 B, |$ a7 T. f
1/ P+ q0 _- a) e" c) ]) G. s
2 * I5 p9 {; {3 E. A3& T8 j/ H q, C! p( k Q, f
4 $ L6 D" T1 {% a. O4 a+ z5 , S; ?: {+ F" o3 W6 * H% r% e( j( [* Q" m8 Q. f7# F" f2 R* K, [) X5 u7 D! ]4 @
8/ G; w+ d7 ^: l. F% ?. s+ j, u
9 9 Q' K/ o$ A. E7 S10 1 i* F( S, F) F11* y3 n( k6 U/ W: g0 O: @" J
12/ b+ @) Z2 h, Z$ Y6 p& f$ M
13 l1 s( q& {( F E14 1 `) {$ C3 Z# b1 i152 L, ^9 ?5 u$ O9 U8 {
16 7 ]3 c! H% A B. M: g17 - h, J* Q3 V% W1 |6 R182 \, n/ v3 D2 g9 {
测试:在浏览器打开 http://localhost:8080/#/login/ \' h$ o: T: v, M1 }0 x
如果出现错误: 可能是因为sass-loader的版本过高导致的编译错误,当前最高版本是8.0.2,需要退回到7.3.1 ;3 W( E% }1 T2 G, t
去package.json文件里面的 "sass-loader"的版本更换成7.3.1,然后重新cnpm install就可以了; - v8 V0 q1 I) N6 K+ _4 x. c; s) O9 } ' B* \/ l' o$ a % X Z/ S8 F! I* H12.3、路由嵌套/ |4 l/ f- x+ e }" E' x
嵌套路由又称子路由,在实际应用中,通常由多层嵌套的组件组合而成。7 b' D! E4 S8 O/ o7 t
demo 9 H" [0 J$ `0 W: {5 W1、 创建用户信息组件,在 views/user 目录下创建一个名为 Profile.vue 的视图组件; 5 ^; v) I' I) Q8 n" }/ CProfile.vue ' m+ _1 V9 F+ W _/ n1 r' ~; `0 `! v& _% m
# l- k3 L" Y, z7 \<template>. i8 s0 c+ d% M7 ? U3 |! q
<h1>个人信息</h1> 8 A5 G( a# w( y+ B1 M* J</template>9 v' y9 H, ?6 A6 \, M, Q5 G3 E) Y
<script># Z' |+ [! s* _% G
export default { - D1 F/ s+ s! J, y5 q name: "UserProfile"% p _. W* R" O" x3 S4 q5 i
} & G: w+ r* x( f# r* \</script># x! f% q% d( y
<style scoped>$ s1 s: L6 m8 F$ l3 ^( V, y* T
</style>/ o- u4 R+ p9 P3 n
1 . F R0 m7 ?1 e$ c- p- K2 8 @9 N% l; U/ }/ H- F; q' J# R3 ( Y2 Y. s$ d; r* @* H$ C! w4( n& W8 k( v/ K
5, R3 c( @& [! B$ h
6 ( c- C. i4 G, L7 X2 K. e' H; w# O7 & J9 g9 N2 `) K' M; L. S8$ s( s" x. D5 q ?( W+ {+ N9 R+ N- u
9 % Y; @" P; Z3 G3 ]7 }/ u100 h8 m( y! y, d& O m1 \
2、在用户列表组件在 views/user 目录下创建一个名为 List.vue 的视图组件; 8 f7 Z% [' k: _$ Z* XList.vue - l- a: u) l$ y5 B& j $ Z# A$ d# q* c; |4 f3 F6 ^ - B1 a: J$ S# O0 F# @ a& u<template>* ^# o2 V0 K1 l% B( U# M( B# `, m
<h1>用户列表</h1>5 ^+ i' u0 \; E! |
</template> / W! D1 |( f8 W# c5 A) n<script> 2 m! G W4 D, P; B% F export default {0 ?5 M6 G1 F9 z
name: "UserList" 2 R8 V7 Z% B E2 H, W }; s% U ?! m( s- z* l; L
</script>; E+ ?$ A7 M2 R9 y
<style scoped> - ~1 O- f3 P+ ~$ v" M</style> # [! g N5 V* ]3 C5 ]( z1 M$ X& M1 + d0 W4 z: G' V" y9 W2/ c* ^( H* e' c- b
34 _6 D1 R- [0 r3 d4 H3 u$ r
4 % K2 X+ y, ?0 D1 e8 Y6 P. y5 ; s8 T7 M2 q6 h* s; _6: F8 s1 p( N( i( B7 E# t
7 8 T! x$ p* D( d, `$ p. Q8# F, F) c% F0 ~/ i0 Q: }" @
9; L2 P( q6 ~ _) u8 K
10/ T% t7 x. c8 t( E6 R$ A( c* T
3、 修改首页视图,我们修改 Main.vue 视图组件,此处使用了 ElementUI 布局容器组件,代码如下:. s7 f2 u9 I% @7 \8 d+ f2 ~ d6 a6 `
Main.vue ' _! i. ]" P# C8 o `3 a 4 l, M5 h8 W9 j; q- [* ?, E% @# c5 @. E
<template>* \, }4 }% F G( \
<div>" m8 G3 @2 C( U* }9 w7 }
<el-container>& B& P- Q; r% N1 R: W0 s* z5 i
<el-aside width="200px">' P, H# w1 P2 ~ N; v3 U# L O1 V
<el-menu :default-openeds="['1']">5 h" X& \$ M7 r9 R
<el-submenu index="1"> 6 N9 u4 I& v+ \4 |" ]. _ <template slot="title"><i class="el-icon-caret-right"></i>用户管理</template> ) e6 r' L# Z& Z# T <el-menu-item-group>- F1 g# H- g' N+ f( t& W) e7 q3 s
<el-menu-item index="1-1"> ! G9 a8 e/ W) |) v9 G* y) T7 l <!--插入的地方-->: L& \9 ^5 i( @8 R
<router-link to="/user/profile">个人信息</router-link>) A3 v l% U3 ?: V* \" W
</el-menu-item>6 e- v0 W2 r* l1 g
<el-menu-item index="1-2"> ( Z& l2 k2 v8 m! i) A: R; ?5 h <!--插入的地方--> 4 R2 S; S3 v+ y/ k' E <router-link to="/user/list">用户列表</router-link>7 q& l4 y; D$ T( m9 H$ w& E
</el-menu-item> 5 o& Q! |% m& ?4 T- } </el-menu-item-group> " @) a! L& n( n5 x </el-submenu>3 r( P9 A- r: d4 n9 R0 `0 K3 h
<el-submenu index="2"> # X# g. E- y/ D' @8 [* {1 {/ l <template slot="title"><i class="el-icon-caret-right"></i>内容管理</template> * z |) [4 ~8 s1 ? <el-menu-item-group>) J# J/ k' A8 }; ]
<el-menu-item index="2-1">分类管理</el-menu-item>5 ]! I3 z% w V
<el-menu-item index="2-2">内容列表</el-menu-item>4 [* Q. z# ~0 o
</el-menu-item-group>+ \) j; [1 {: n
</el-submenu> * s9 o* l9 C- f+ Q/ q9 D3 q </el-menu> j6 M9 g4 d: e </el-aside> 0 y5 G2 A9 \ j 0 }0 h0 @( t; W T* `: t4 D1 K; u1 R) I% L <el-container>( O. H( b3 [/ D
<el-header style="text-align: right; font-size: 12px"> # A0 |- x& ? l6 D1 ^ <el-dropdown># ^8 }; M" j; \( y, ]1 J
<i class="el-icon-setting" style="margin-right: 15px"></i>" k8 n3 P F9 v; j( b l, y0 [2 c
<el-dropdown-menu slot="dropdown">+ z1 L' ~4 A( @# m1 G- f* D
<el-dropdown-item>个人信息</el-dropdown-item>" h s: S8 W+ t& ]0 g0 B8 K
<el-dropdown-item>退出登录</el-dropdown-item>3 [3 f# ~7 ~0 m) S
</el-dropdown-menu> . V; O( Z7 A- z o. K </el-dropdown>- n* h) x9 `$ l0 f& D1 K* w6 {
</el-header>8 H& I; }" {' f
<el-main> N, }/ i) m9 ` <!--在这里展示视图-->7 I3 R. @6 \, k% t) z
<router-view /> 1 D N$ n' V6 I1 [ y' K7 p# }' I# ?5 c2 g </el-main>+ d0 Z, L, }: [5 o! o$ _, @" ~1 X
</el-container>' z$ w. S+ z& _5 t- y- I
</el-container> * u q: N/ S1 N+ W/ ~4 N" ] </div> 1 g9 \$ @5 i& W# [" ^</template>4 m: {$ ?0 ?3 i9 r- k1 E- Z
<script> 8 u$ f* T9 b. x- d0 y4 o9 D6 J export default { # g/ O' t: I. } name: "Main"" E/ _4 B+ h3 J
} - ~( @ }7 N5 d* i( U/ s</script> 1 I; E# a9 v9 m<style scoped lang="scss"> 1 x9 {/ ]. B! W: b% f4 [3 ` .el-header {$ L1 c" [( e0 }& ^
background-color: #B3C0D1;. |4 m6 q# G0 J) t+ a
color: #333;3 a6 A) d( i3 @4 P5 T# n
line-height: 60px;$ ~( V7 C' x% p7 s
} * B z' }0 K; O! u7 f .el-aside {9 ?* j6 E" R+ r6 H( c
color: #333;$ s+ H( o8 }0 P# r
}0 z+ _, t/ N2 {/ a9 @9 k3 V
</style> + `! Q }4 q; O. Q& w17 l( X- M; f0 A. B) f$ j* j
2. Q8 X2 t8 D' ~) j1 D3 n
3' d9 i5 @ K! K8 K
4/ D& B$ u S# D7 K ]
5 ( v/ n/ Q- O3 ]$ `+ I6 ! x8 M; c, E2 t) g4 q0 M0 U1 q7 ; d: E- V0 K# z! ~6 e [ K8 % w& N, N F |$ D6 |8 X2 O9 ( C) Q: C, N p103 ?5 N; Q4 }& U
11! S! W2 T% X w4 W
12, s0 f/ e2 Q. D" S$ U
13 P; A9 S5 G+ \6 N, q; c' e
14 3 f/ N; S; C8 y8 {. j. k7 h154 t; O! P- d6 N$ l. {# b8 u
16 ( e0 A2 U5 s( u17 1 n7 o6 H0 U6 E' ^+ `18+ x$ z3 ~" M+ C4 F; L# c* a$ q
19 9 r. ~7 {1 _, q: {- ^" k20 2 I# I0 T- |1 R# E! Y( @21 ) k9 F8 ~( a4 ?: |22 , q. `- [- `, ~* L- u/ Z3 h2 L0 ~) V232 q+ j5 w! C' m% i- w1 P' ?
24. j+ o! w) I4 b0 J9 Q) I
253 c9 y' d8 @( ~! w
26 ' H+ s" a- V- {1 b% Z27) |& Z' a% b) D' W: |
28 ; N a1 K! Z8 ~ z4 N1 X8 v) H0 Q29! v7 v) w; w# h; r& Z! o2 o6 |
301 W3 B8 k- I" S4 X @* }4 r
318 L6 r) Q: c7 N) W2 D' B1 z$ e/ {
32* z* r$ T1 |2 U5 J1 l
33 L6 K5 F( z1 A/ R34! `; O0 z. z9 G$ N8 ?8 j
35 1 [4 S% P) s: u36 + X$ A9 A: d6 p7 M' q0 [ r3 P. k, y37 1 Z! S5 I% o8 m! z38 d( t% [# \5 g3 m0 w391 \- T x6 Q2 {- v
40 2 k: `2 B6 ?, y41 % V& ^! ]+ v5 i# J; B- ^, H422 W# F, K2 I# D# j& ^
43* ]+ Q7 |8 ^) v% p x
44 - I7 ~. h" f: g, X45" G+ g; W$ C v3 U% ^! q
46 0 S8 Q# A5 M+ B( S S479 G0 B: C2 O3 ?6 @; F
48 $ c5 b/ {/ ]$ W49 . V8 s3 b: N) B% H5 [% l- t+ }, C# v. _501 d$ s8 c: I, r+ X0 R* ]) y
51 8 i9 R6 w: m* }& Y4 \: k' e52 0 f5 O( J1 U n$ |; t. y7 n, F0 M535 \5 S$ x! Z) q3 M6 C/ [
54 . n2 Y O9 t* Z5 j2 ^, }' b" Y55 " [5 Q" t D1 |9 U5 [56 + k1 A: Y' Q7 i* b57 : }6 ^0 o; ]- Z. o7 x2 j0 ^58 $ B1 F! }, D. m6 ~$ @8 H) ~# ~' [59 " A& ], R% U; t1 d0 X! @) d60' Q4 E! D3 [. o. t" M- Q8 A
61 % ?* m5 m8 x6 b: ?4、 配置嵌套路由修改 router 目录下的 index.js 路由配置文件,使用children放入main中写入子模块,代码如下 ) j& V; V: P, sindex.js- T2 U3 Q3 z" \& Z
" w! K' V4 Y" G* K3 w ) C1 Z s3 J4 z0 A//导入vue7 S- h/ {: J, Q6 y! l" d
import Vue from 'vue'; + v: Z4 C N" I2 f& U6 k: h# Ximport VueRouter from 'vue-router'; 1 i ~' E1 W7 Y, c2 N' u//导入组件 # Q: z: t/ M% U7 ^! I* Aimport Main from "../views/Main"; . s; M6 |. c+ K" e) Nimport Login from "../views/Login";! r, p6 M$ M$ C6 U4 ?
//导入子模块 # ~; `2 p9 k. J# C+ A& G9 g) ~import UserList from "../views/user/List"; ; ?2 t! c: P& ~ r% X3 M+ j. \" ^3 Gimport UserProfile from "../views/user/Profile";2 c/ ?# x+ B3 j" C
: p6 \( @% P# {; i) g+ |1 \$ T$ L' W& f) Q" s' _" b
//使用+ C: \1 L/ \$ o+ E% @' J0 k' T, P- e
Vue.use(VueRouter); 0 o- f' c5 k% A0 X, {- o//导出0 ?7 _, ]" S; Y: g4 A8 y
export default new VueRouter({2 }; k# X- p5 O0 x6 o
routes: [1 m8 y& r- f/ y- X
{% r$ m/ f' D! A, P0 U5 y3 M
//登录页 ! p5 l, X/ }# I8 R) t) K! G path: '/main',( i1 A, a6 j& d: P6 V5 Q
component: Main, * t" e* w0 f7 n9 r6 j+ H' N9 x // 写入子模块 - d4 M7 L0 d; b9 D- U" u children: [ ! o+ v3 h5 x% ^4 H& d {& V$ a7 n; x# m+ @8 m: h, j
path: '/user/profile',/ _% o2 b( V" T8 ]' u/ S! J9 Y7 s
component: UserProfile, / l; Z! ~2 {7 m8 | }, { ( d B9 y7 B. Z( B/ l- ] path: '/user/list', : i9 o* c) k( N' q component: UserList, 2 d& D @9 ~" K& G' D' X }, 0 s0 g8 |% H6 @4 r& J; A ] & K' Y6 x3 _5 ? },5 R* \# L8 [9 l4 Y
//首页2 e* @7 s$ }' v6 y m
{- v" A) @3 ]- N
path: '/login',! g9 Q4 ^1 @ k. N4 _4 ?% Z, o# z
component: Login % e/ N" {7 x+ j% L$ { 3 _! V7 i3 x: |/ i" J# h. L2 C0 D2 q% i% h8 `' Q
},$ j) a9 ?+ h1 `& X/ O3 ~" R! Z
]9 B& ?; }2 p' Z7 j' t9 q% w; w
})+ i3 `- g% j, s+ @
1 . a+ ~6 ?/ h6 _4 v# }+ d2 " h8 c1 @ E! t& B' S$ z. t- v37 p) b$ A: ]& I. p
4 6 Y, F5 W- y: |( k5/ v$ \) @4 ~, y5 C. J
64 W8 \( K& z) d) P6 D( A
7 # j2 k4 \ t( W) G84 L+ u9 O9 ]9 u0 O# \" g
9 0 M) W* u; U3 B( s% ~105 O! c+ x# f7 @" I* z
118 G$ ~. \% {* Q b( Y; _0 `5 _
12' f+ B8 c' N& p% G# V! n0 }
13% t! _" \3 J9 u# z; F
14 & W5 [9 ]+ l; g) P8 X" k" p+ t& _15+ g2 O) E. s9 b
16 - @9 j9 A5 g) |7 |9 x17; m6 f" k) K* Y5 s* @- A0 c
18 + ]/ X5 Z# O8 D/ S19* B* H3 F# ?; N& v
20+ D% d1 u# V0 Y1 J: ~: T- ?
21& e- V) o8 u1 V9 y- f/ z
22. Q, o+ o8 H2 r7 o' G
238 H0 j. _+ J/ a- Z: R; L
24 4 K, x$ p/ Y/ ]4 K1 y7 n. E25. m- Q& {, S l+ O t
26+ P+ |( y, V+ C
27 3 u+ T+ S6 @* y I288 x2 ]/ J7 S9 @" ^/ @7 F6 e9 ^6 l
29! T) |+ c V4 h' P, M' u8 j
306 s5 s* G5 m T- ?
31 4 }* |9 a. c. Q7 H2 r2 L! k32 * n( ]3 r! `: D7 G; r4 o9 V33 . Z6 F; q/ k5 v7 Y346 ]" y0 m6 g y
35( I# ?' @0 e- B, W; |. E
36 8 h5 N1 x+ ?+ d* K" d) G, p' ]( [. ?37 & X% e! E& D9 y/ T; x/ \. `: ~38 9 _+ @4 w( N- n' j3 @) p5、 路由嵌套实战效果图8 ^4 U! I$ E& ~! L3 q7 }* T4 A- s
1 j3 E, }: E6 a. J" h' `
5 F6 G; c, f! A. S2 [* _
9 j7 B& N+ E5 K/ C0 e9 ]5 P* f: [ + b G5 G( v d# z图 路由嵌套效果图 ( N h$ J6 j: f; E 4 h% p$ L# I, N. P0 u ( o( d# E6 \* i( T+ x12.4、参数传递+ v# j- A4 X, d& X3 D9 ~- u' o
这里演示如果请求带有参数该怎么传递9 {% Q5 c f w" Y
demo 4 d, V7 V5 {$ H) o 用的还是上述例子的代码 修改一些代码 这里不放重复的代码了+ g4 a, F9 t! i) `* n) ~( |
第一种取值方式4 L# A, S" p: W% J( {
1、 修改路由配置, 主要是router下的index.js中的 path 属性中增加了 :id 这样的占位符 ( f) } Z" \5 {3 y# D; M3 l, H' N, v. ^" w
, m! i5 u1 u- F* u{ 5 w7 s( p, t+ m path: '/user/profile/:id', . Y- \7 n5 N# I( w/ X5 S' @
name:'UserProfile', " A0 I8 | q( C+ B
component: UserProfile 1 |8 Z, C+ v8 C, A$ x} 0 Y0 [9 _$ X& ]4 K1 x' Y6 G1 F5 k" K& I
2/ G+ u* f- L! y( l) g. i
39 k* G+ t$ A+ R8 U6 U" j
4 & [& K# @3 f' B5 ~7 B& B5 % I- y& ?* T: [ C y: ~* U2、传递参数% Q: y" Q; {3 T8 s* D% n o
此时我们在Main.vue中的route-link位置处 to 改为了 :to,是为了将这一属性当成对象使用,注意 router-link 中的 name 属性名称 一定要和 路由中的 name 属性名称 匹配,因为这样 Vue 才能找到对应的路由路径; 6 o e+ t0 j' l" L ' t, S# G. \9 Y$ C 8 W$ u& [$ b, e5 z% h& K) m<!--name是组件的名字 params是传的参数 如果要传参数的话就需要用v:bind:来绑定--> 9 u" s6 i' F$ d/ r<router-link :to="{name:'UserProfile',params:{id:1}}">个人信息</router-link> : a+ P2 @9 M! H" A1 * w* p4 e7 V! G ]7 n2# Y$ l' z# O/ O# Y8 O% j: W
3、在要展示的组件Profile.vue中接收参数 使用 {{$route.params.id}}来接收 5 ~" Z* f" v* N- H7 TProfile.vue 部分代码 3 Q; T0 l% T, t3 t! z6 I: t6 _* v5 d" B, ~9 }8 g; A
7 j1 ?& {4 i, u8 C3 U: j( |) Z! K<template> # [0 p, O0 M7 v <!-- 所有的元素必须在根节点下--> 2 K% ^1 D% e5 `! Y <div># Q2 t; C3 y: G9 G1 D9 |
<h1>个人信息</h1>, u8 H6 G( }4 |! X
{{$route.params.id}} . m% U8 |: v, {% X |% v' j </div> + J1 H! m8 x/ ^</template>& C) ^& I5 `) R, D( P1 w: D( i9 X
19 n( z: L. Z4 n. [1 P
20 t& C6 q4 m( ?* ]
3 ! `/ u% j% l/ M4 i6 V4 T2 S' t47 t- R0 n3 O c \4 P1 [: V$ o, q, j
5 - {& o; }( i6 ^/ d# f6 / K4 |* _: g$ N/ B7 5 F+ J L9 t1 Z# `第二种取值方式 使用props 减少耦合 * V$ _' Q* Y3 A1、修改路由配置 , 主要在router下的index.js中的路由属性中增加了 props: true 属性1 U ^& `- P9 W4 I1 x" @
! s! U1 e) ], U2 \0 Y8 h4 K