系统学习前端Vue框架,笔记记录于B站的why老师,具体视频链接 ,在此感谢老师的悉心授课。github笔记地址
初始化Vue 初识Vue 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 <script src="../js/vue.js" ></script> <div id ="hi" > Hello {{name}}</div > <div class ="movie" > <ul > <li v-for ="item in movies" > {{item}} </li > </ul > </div > <script > const hi = new Vue ({ el : "#hi" , data : { name : 'Vue.js' } }) let movie = new Vue ({ el : '.movie' , data : { movies : ["星际穿越" , '大话西游' , '海贼王之黄金城' , '复仇者联盟' ] } }) </script >
简易计数器 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 <body > <div id ="count" > <h2 > {{counter}}</h2 > <button v-on:click ="add" > +</button > <button v-on:click ="sub" > -</button > </div > <ol > <li > 原因是你的body中的div中没有设置id,vue没有绑定</li > <li > 解决:body中加 div id="app" </li > <li > 双向绑定:view,model,ViewModel</li > </ol > </body > <script > const obj = { counter : 0 } let count = new Vue ({ el : "#count" , data : obj, methods : { add : function ( ) { this .counter ++; }, sub : function ( ){ this .counter --; } } }) </script >
Vue中的MVVM MVVM简介   MVVM 是Model-View-ViewModel 的缩写,它是一种基于前端开发的架构模式,其核心是提供对View 和 ViewModel 的双向数据绑定,这使得ViewModel 的状态改变可以自动传递给 View,即所谓的数据双向绑定。   Vue.js 是一个提供了 MVVM 风格的双向数据绑定的 Javascript 库,专注于View 层。它的核心是 MVVM 中的 VM,也就是 ViewModel。 ViewModel负责连接 View 和 Model,保证视图和数据的一致性,这种轻量级的架构让前端开发更加高效、便捷。
MVVM模型
MVVM拆开来即为Model-View-ViewModel,有View,ViewModel,Model三部分组成。
View层:是视图、模版,负责将数据模型转化为UI展现出来。
Model层:是模型、数据,可以在Model层中定义数据修改和操作的业务逻辑。
ViewModel层:View层和Model层并没有直接联系,而是通过ViewModel层进行交互。ViewModel层通过双向数据绑定将View层和Model层连接了起来,使得View层和Model层的同步工作完全是自动的。
Vue.js中mvvm的体现   Vue.js的实现方式,对数据(Model)进行劫持,当数据变动时,数据会出发劫持时绑定的方法,对视图进行更新。
实例分析如下:
Vue.js关于双向数据绑定的一些实现细节
  vue是采用Object.defineProperty的getter和setter,并结合观察者模式来实现数据绑定的。当把一个普通的javascript对象传给Vue实例来作为它的data选项时,Vue将遍历它的属性,用Object.defineProperty将它们转为getter/setter。用户看不到getter/setter,但是在内部它们让Vue追踪依赖。在属性被访问和修改时通知变化。
Observer相当于Model层观察vue实例中的data数据,当数据发生变化时,通知Watcher订阅者。
Compile指令解析器位于View层,初始化View的视图,将数据变化与更新函数绑定,传给Watcher订阅者。
Watcher是整个模型的核心,对应ViewModel层,连接Observer和Compile。所有的Watchers存于Dep订阅器中,Watcher将Observer监听到的数据变化对应相应的回调函数,处理数据,反馈给View层更新界面视图。
Dep消息订阅器,内部维护了一个数组,用来收集订阅者(watcher),数据变动触发notify函数,再调用订阅者的update方法。
基本模板语法 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 <!DOCTYPE html > <html lang ="zh-CN" > <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 > Document</title > <script src ="../js/vue.js" > </script > <style > [v-cloak] { display : none !important ; } </style > </head > <body > <div id ="app" > <h4 > Hello {{count}}</h4 > </div > <script > setTimeout (() => { let app = new Vue ({ el : '#app' , data : { count : 'v-cloak' }, methods : { }, beforeMount () { alert ("有趣" ); } }); }, 1000 ); </script > </body > </html >
动态绑定属性 class的绑定 传给 v-bind:class 一个对象,以动态地切换 class(语法糖:’:表示’)
根据isActive的true,false变化,动态绑定单个class
1 <div :class ="{ active: isActive==true }" > </div >
计算属性的方式绑定class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <div :class ="classObject" ></div> data : { isActive : true , error : null }, computed : { classObject : function ( ) { return { active : this .isActive && !this .error , 'text-danger' : this .error && this .error .type === 'fatal' } } }
数组的方式绑定class
1 2 3 4 5 6 7 <div v-bind :class ="[activeClass, errorClass]" ></div> data : { activeClass : 'active' , errorClass : 'text-danger' } 渲染为: <div class ="active text-danger" ></div>
三元表达式动态切换class(推荐)
1 <div :class ="[isActive ? activeClass : '', errorClass]" > </div >
style的绑定 v-bind:style 的对象语法十分直观——看着非常像 CSS,但其实是一个 JavaScript 对象。CSS 属性名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用单引号括起来) 来命名:
1 2 3 4 5 <div v-bind:style ="{ color: activeColor, fontSize: fontSize + 'px' }" > </div > data: { activeColor: 'red', fontSize: 30 }
直接绑定到一个样式对象通常更好,这会让模板更清晰:
1 2 3 4 5 6 7 <div :style ="styleObject" > </div > data: { styleObject: { color: 'red', fontSize: '13px' } }
v-bind:style 的数组语法可以将多个样式对象应用到同一个元素上:
1 <div v-bind:style ="[baseStyles, overridingStyles]" > </div >
计算属性 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 <body > <div id ="app" > <h3 > {{fullName}}</h3 > </div > <script > let app = new Vue ({ el : '#app' , data : { fisrtName : 'Lom' , lastName : 'Name' }, computed : { fullName : { set : function (newValue ) { console .log ("---------" , newValue); const value = newValue.split (' ' ); this .fisrtName = value[0 ]; this .lastName = value[1 ]; }, get : function ( ) { return this .fisrtName + ' ' + this .lastName ; } } } }); </script > </body >
计算属性和methods的对比 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 <body > <div id ="app" > <h3 > {{fisrtName}} {{lastName}}</h3 > <h3 > {{getFullName()}}</h3 > <h3 > {{fullName}}</h3 > </div > <script > const app = new Vue ({ el : '#app' , data : { fisrtName : 'Lom' , lastName : 'Name' }, methods : { getFullName : function ( ){ console .log ("fullName" ); return this .fisrtName + ' ' + this .lastName ; } }, computed : { fullName : { get : function ( ) { console .log ("fullName" ); return this .fisrtName + ' ' + this .lastName ; } } } }); </script > </body >
事件监听 v-on的基本使用 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 <body > <div id ="app" > <h3 > {{counter}}</h3 > <button @click ="increment" > +</button > <button v-on:click ="decrement()" > -</button > </div > <script > let app = new Vue ({ el : '#app' , data : { counter : 0 }, methods : { increment ( ){ this .counter ++ }, decrement ( ){ this .counter -- } } }); </script > </body >
v-on的参数问题 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 <body > <div id ="app" > <button @click ="btn0Click" > +</button > <button @click ="btn1Click()" > +</button > <button @click ="btn2Click(value)" > +</button > <button @click ="btn3Click(value, $event)" > +</button > </div > <script > let app = new Vue ({ el : '#app' , data : { value : 13 }, methods : { btn0Click ( ) { console .log ("btn1Click" ); }, btn1Click ( ) { console .log ("======" , event); }, btn2Click (value ) { console .log ("------" , value); }, btn3Click (value, event ) { console .log ("+++++" , value, event); } }, }); </script > </body >
v-on的修饰符 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 <body > <div id ="app" > <div @click ="divClick" > <button @click.stop ="btnClick" > 点击</button > </div > <form action ="" > <input type ="submit" value ="提交" @click.prevent ="submitClick" > </button > </form > <input @keyup ="keyup" > 松开</input > <br > <input @click.keyup ="keyup" > 鼠标点击松开</input > <br > <input @keyup.enter ="enter" > 回车</input > <br > <button @click.once ="once" > 只能点击一次</button > </div > <script > let app = new Vue ({ el : '#app' , data : { }, methods : { btnClick ( ){ console .log ("btnClick" ) }, divClick ( ){ console .log ("divClick" ) }, submitClick ( ){ console .log ("submitClick" ) }, keyup ( ){ console .log ("keyup" ) }, enter ( ){ console .log ("enter" ) }, once ( ){ console .log ("once" ) } } }); </script > </body >
条件判断 v-if的基本使用 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 <body > <div id ="app" > <h2 v-if ="isShow" > <div > abc</div > <div > abc</div > <div > abc</div > <div > abc</div > <div > abc</div > {{message}} </h2 > </div > <script > let app = new Vue ({ el : '#app' , data : { message : '哈哈' , isShow : true }, methods : { } }); </script > </body >
v-if和v-else的使用 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 <body > <div id ="app" > <h2 v-if ="isShow" > <div > abc</div > <div > abc</div > <div > abc</div > <div > abc</div > <div > abc</div > {{message}} </h2 > <h2 v-else > 当v-if为false的时候,我就开始显示了,我和v-if要紧连着使用</h2 > </div > <script > let app = new Vue ({ el : '#app' , data : { message : '哈哈' , isShow : true }, methods : { } }); </script > </body >
v-if和v-else-if和v-else的使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <body > <div id ="app" > <p v-if ="score >= 90" > 优秀</p > <p v-else-if ="score >= 80" > 良好</p > <p v-else-if ="score >= 60" > 及格</p > <p v-else > 不及格</p > </div > <script > let app = new Vue ({ el : '#app' , data : { score : 99 } }); </script > </body >
用户登录切换的案例 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 <body > <div id ="app" > <span v-if ="isShowUserName" > <label for ="userName" > 用户名</label > <input type ="text" id ="userName" placeholder ="请输入用户名" > </span > <span v-else > <label for ="email" > 用户邮箱</label > <input type ="text" id ="email" placeholder ="请输入用户邮箱" > </span > <button @click ="isShowUser" > 切换类型1</button > <button @click ="isShowUserName = !isShowUserName" > 切换类型2</button > </div > <script > let app = new Vue ({ el : '#app' , data : { isShowUserName : true }, methods : { isShowUser ( ) { this .isShowUserName = !this .isShowUserName } } }); </script > </body >
用户登录切换的案例(复用的小问题) 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 <body > <div id ="app" > <span v-if ="isShowUserName" > <label for ="userName" > 用户名</label > <input type ="text" id ="userName" placeholder ="请输入用户名" key ="userName" > </span > <span v-else > <label for ="email" > 用户邮箱</label > <input type ="text" id ="email" placeholder ="请输入用户邮箱" key ="userName" > </span > <button @click ="isShowUser" > 切换类型1</button > </div > <script > let app = new Vue ({ el : '#app' , data : { isShowUserName : true }, methods : { isShowUser ( ) { this .isShowUserName = !this .isShowUserName , document .getElementById ("userName" ).value = '' ; document .getElementById ("email" ).value = '' ; } } }); </script > </body >
v-show的使用 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 <body > <div id ="app" > <span v-if ="isShow" id ="isShow" > V-if</span > <span v-show ="isShow" id ="VShow" > V-show</span > </div > <script > const app = new Vue ({ el : '#app' , data : { isShow : true }, methods : { } }); </script > </body >
循环遍历 v-for遍历数组 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 <body > <div id ="app" > <ul > <li v-for ="item in movies" > {{item}}</li > </ul > <br > <ul > <li v-for ="(item, index) in movies" > {{index + 1}}.{{item}}</li > </ul > <br > <ul > <li v-for ="(item, index) in movies" @click ="showIndex(index)" > {{index + 1}}.{{item}}</li > </ul > </div > <script > const app = new Vue ({ el : '#app' , data : { movies : ['海王' , '大话西游' , '星际争霸' , '三傻大闹宝莱坞' ] }, methods : { showIndex (index ) { console .log ('第' + (index + 1 ) + '个值' ); } } }); </script > </body >
v-for遍历对象 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 <body > <div id ="app" > <ul > <li v-for ="item in obj" > {{item}}</li > </ul > <br > <ul > <li v-for ="(item, key) in obj" > {{item}}--{{key}}</li > </ul > <br > <ul > <li v-for ="(value, key, index) in obj" > {{value}}--{{key}}--{{index+1}}</li > </ul > <br > </div > <script > const app = new Vue ({ el : '#app' , data : { obj : { id : 12 , name : 'Luck' , height : 1.78 } }, methods : { } }); </script > </body >
v-for使用过程添加key 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 <body > <div id ="app" > <ul > <li v-for ="item in obj" :key ="item" > {{item}}</li > </ul > </div > <script > const app = new Vue ({ el : '#app' , data : { obj : ['A' , 'B' , 'C' , 'D' , 'E' ] }, methods : { } }); </script > </body >
哪些数组的方法是响应式的 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 <body > <div id ="app" > <ul > <li v-for ="item in obj" :key ="item" > {{item}}</li > </ul > <button @click ="btnClick" > 点击</button > </div > <script > let myDate = new Date (); const app = new Vue ({ el : '#app' , data : { obj : ['R' , 'C' , 'B' , 'D' , 'E' ], }, methods : { btnClick ( ) { Vue .set (this .obj , 2 , 'G' ) } } }); </script > </body >
对遍历出的列表,点击后对应的能变红 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 <body > <div id ="app" > <ul > <li v-for ="(item, index) in obj" :key ="item" :class ="{active: currentIndex === index}" @click ="changeColor(index)" > {{item}}</li > </ul > </div > <script > let myDate = new Date (); const app = new Vue ({ el : '#app' , data : { obj : ['R' , 'C' , 'B' , 'D' , 'E' ], currentIndex : 0 }, methods : { changeColor (index ) { this .currentIndex = index; } } }); </script > </body >
书籍购物车案例 此案例包含JavaScript的高阶函数用法 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 const nums = [10 , 20 , 30 , 40 , 50 ];let newNum1 = nums.filter (function (n ) { return n < 100 ; }) console .log ('newNum1==filter==' + newNum1);let newNum2 = newNum1.map (function (n ) { return n * 2 ; }) console .log ('newNum2==map==' + newNum2);let newNum21 = nums.map (function (n ) { if (n < 80 ) { return n * 2 ; } else { return ; } }) console .log ('newNum21==map==' + newNum21);let total = newNum2.reduce (function (preValue, value ) { return preValue + value; }, 0 ) console .log ('total===' + total);let sum = nums.filter (function (n ) { return n < 50 }).map (function (n ) { return n * 2 }).reduce (function (preValue, value ) { return preValue + value }, 0 ) console .log ('sum===' + sum);let sum1 = nums.filter (n => n < 50 ).map (n => n * 2 ).reduce ((pre, value ) => pre + value);console .log ('sum1===' + sum1);
index.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 <!DOCTYPE html > <html lang ="en" > <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 > Document</title > <link rel ="stylesheet" href ="style.css" > </head > <body > <div id ="app" > <div v-if ="isFull" > <table > <thead > <tr > <th > 编号</th > <th > 书名</th > <th > 出版日期</th > <th > 价格</th > <th > 数量</th > <th > 操作</th > </tr > </thead > <tbody > <tr v-for ="(item,index) in books" :class ="{changeColor: number == 1}" @mouseenter ="change(index)" @mouseleave ="remove(index)" > <td > {{item.id}}</td > <td > {{item.name}}</td > <td > {{item.date}}</td > <td > {{item.price | showPrice}}</td > <td > <button @click ="subBtn(index)" > -</button > {{item.count}} <button @click ="addBtn(index)" > +</button > </td > <td > <button v-if ="exchange" @click ="addItemBtn(index)" > 新增</button > <button v-else @click ="removeBtn(index)" > 移除</button > <button @click ="changeType()" > 切换类型</button > </td > </tr > </tbody > </table > <br > <span > 总价格:{{showTotalPrice | showPrice}}</span > </div > <h2 v-else > 购物车清空</h2 > </div > </body > <script src ="../js/vue.js" > </script > <script src ="main.js" > </script > </html >
main.js 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 const app = new Vue ({ el : '#app' , data : { books : [{ id : 1 , name : '算法导论' , date : '2019-2' , price : 87.21 , count : 1 , exchange : true }, { id : 2 , name : 'UNIX编程艺术' , date : '2019-4' , price : 97.21 , count : 2 , exchange : true }, { id : 3 , name : '编程珠玑' , date : '2012-2' , price : 77.21 , count : 1 , exchange : true }, { id : 4 , name : '大话西游' , date : '2019-7' , price : 100 , count : 1 , exchange : true } ], number : 2 , exchange : false , isFull : true }, computed : { showTotalPrice ( ) { let totalPrice = 0 ; return this .books .reduce (function (preValue, book ) { return preValue + book.price * book.count }, 0 ) return totalPrice } }, methods : { subBtn (index ) { if (this .books [index].count > 0 ) { this .books [index].count -- } }, addBtn (index ) { this .books [index].count ++ }, removeBtn (index ) { this .books .splice (index, 1 ) if (this .books .length <= 0 ) { this .isFull = !this .isFull } }, change (index ) { this .number = 1 ; this .active = ".changeColor{ background-color: #cae6e6}" }, remove (index ) { this .number = 2 }, changeType ( ) { this .exchange = !this .exchange }, addItemBtn ( ) { const obj = [5 , '数值分析' , '2018-8' , 96.10 , 2 ]; this .books .push (obj) }, getfinalPrice (price ) { return '¥' + price.toFixed (2 ); } }, filters : { showPrice (price ) { return '¥' + price.toFixed (2 ); } } })
style.css 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 table { border : 1px solid #cccccc ; border-collapse : collapse; border-spacing : 0 ; width : 700px ; } table thead { background-color : lightskyblue; } table tr th { border : 1px solid #cccccc ; } table tr td { border : 1px solid #cccccc ; text-align : center; padding : 20px ; } .changeColor { background-color : #cae6e6 }
v-model的使用 v-model双向绑定的基本原理 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 <body > <div id ="app" > <input type ="text" v-model ="message" > {{message}} <br > <input type ="text" v-on:input ="changeInput($event)" > <input type ="text" @input ="changeInput" > <br > <input type ="text" v-bind:value ="message" v-on:input ="message = $event.target.value" > <input type ="text" :value ="message" @input ="message = $event.target.value" > </div > <script > const app = new Vue ({ el : '#app' , data : { message : '你好呀' }, methods : { changeInput (event ) { this .message = event.target .value ; } } }); </script > </body >
v-model结合radio单选框使用 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 <body > <div id ="app" > <label for ="male" > <input type ="radio" name ="sex" value ="男" id ="male" v-model ="message" > 男 </label > <label for ="female" > <input type ="radio" name ="sex" value ="女" id ="female" v-model ="message" > 女 </label > <br > {{'你选中的值:' + message}} </div > <script > const app = new Vue ({ el : '#app' , data : { message : '' }, methods : { } }); </script > </body >
v-model结合checkbox多选框使用 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 <body > <div id ="app" > <label for ="agreeLisence" > <input type ="checkbox" v-model ="isAgree" > 统一协议 </label > <button :disabled ="!isAgree" > 下一步</button > <br > <input type ="checkbox" value ="唱" v-model ="hobbies" > 唱 <input type ="checkbox" value ="跳" v-model ="hobbies" > 跳 <input type ="checkbox" value ="rap" v-model ="hobbies" > rap <input type ="checkbox" value ="打篮球" v-model ="hobbies" > 打篮球 你选择的兴趣爱好是:{{hobbies}} </div > <script > const app = new Vue ({ el : '#app' , data : { isAgree : false , hobbies : [] }, methods : { } }); </script > </body >
v-model结合select下拉框使用 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 <body > <div id ="app" > <select name ="demo" v-model ="fruit" > <option value ="香蕉" > 香蕉</option > <option value ="苹果" > 苹果</option > <option value ="葡萄" > 葡萄</option > <option value ="梨子" > 梨子</option > </select > <h3 > 你选择的水果是:{{fruit}}</h3 > <br > <select name ="demo" v-model ="fruits" multiple > <option value ="香蕉" > 香蕉</option > <option value ="苹果" > 苹果</option > <option value ="葡萄" > 葡萄</option > <option value ="梨子" > 梨子</option > </select > <h3 > 你选择的水果是:{{fruits}}</h3 > </div > <script > const app = new Vue ({ el : '#app' , data : { fruit : '香蕉' , fruits : [] }, methods : { } }); </script > </body >
v-model结合v-for使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <body > <div id ="app" > <label v-for ="(item, index) in originalHobbies" > <input type ="checkbox" v-model ="hobbies" :id ="index+1" :value ="item" > {{item}} </label > 你选择的兴趣爱好是:{{hobbies}} </div > <script > const app = new Vue ({ el : '#app' , data : { isAgree : false , hobbies : [], originalHobbies : ['唱' , '跳' , 'rap' , '打篮球' ] }, methods : { } }); </script > </body >
v-model的修饰符使用 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 <body > <div id ="app" > <input type ="text" v-model.lazy ="message" > {{message}} <hr > <input type ="number" v-model ="age" > <h3 > {{age}}--{{typeof age}}</h3 > <input type ="number" v-model.number ="height" > <h3 > {{height}}--{{typeof height}}</h3 > <hr > <input type ="text" v-model.trim ="name" > <input type ="number" v-model.lazy.number ="height" > <h3 > {{name}}</h3 > </div > <script > const app = new Vue ({ el : '#app' , data : { message : '你好呀' , age : 0 , height : 1 , name : '' }, methods : { } }); </script > </body >
组件化开发 组件化的基本使用 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 <body > <div id ="app" > <my-cpn > </my-cpn > <my-cpn > </my-cpn > <my-cpn > </my-cpn > <my-cpn > </my-cpn > </div > <script > const cpnC = Vue .extend ({ template : ` <div> <h2>组件化</h2> <h3>我是,哈哈哈哈</h3> <h3>我是,呵呵呵呵</h3> </div> ` }) Vue .component ('my-cpn' , cpnC) const app = new Vue ({ el : '#app' , data : { }, methods : { } }); </script > </body >
全局组件和局部组件 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 <body > <div id ="app" > <cpn > </cpn > <cpn > </cpn > <cpn > </cpn > <cpn > </cpn > </div > <div id ="app2" > <cpn > </cpn > </div > <script > const cpnC = Vue .extend ({ template : ` <div> <h2>组件化</h2> <h3>我是,哈哈哈哈</h3> <h3>我是,呵呵呵呵</h3> </div> ` }) Vue .component ("cpn" , cpnC) const app = new Vue ({ el : '#app' , data : { }, components : { cpn : cpnC } }); const app2 = new Vue ({ el : '#app2' , }); </script > </body >
父组件和子组件 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 <body > <div id ="app" > <cpn2 > </cpn2 > </div > <script > const cpnC = Vue.extend({ template: ` <div > <h2 > 子组件</h2 > <h3 > 我是,哈哈哈哈</h3 > <h3 > 我是,呵呵呵呵</h3 > </div > ` }) // 父组件:root组件 const cpnC2 = Vue.extend({ template: ` <div > <h2 > 父组件</h2 > <h3 > 我是,哈哈哈哈</h3 > <h3 > 我是,呵呵呵呵</h3 > // 这个子组件需要先注册 <cpn1 > <cpn1 /> </div > `, components: { cpn1: cpnC } }) // 注册全局组件 Vue.component("cpn", cpnC) const app = new Vue({ el: '#app', data: { }, components: { // 注册局部组件,即只能在app里使用这个组件 cpn1: cpnC, cpn2: cpnC2 } }); </script > </body >
组件的语法糖注册方式 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 <body > <div id ="app" > <cpn1 > </cpn1 > <cpn2 > </cpn2 > </div > <script > // const cpnC = Vue.extend() // 语法糖注册全局组件 Vue.component("cpn1", { template: ` <div > <h2 > 我是cpn1</h2 > <h3 > 我是,哈哈哈哈</h3 > </div > ` }) const app = new Vue({ el: '#app', data: { }, components: { // 语法糖注册局部组件,即只能在app里使用这个组件 'cpn2': { template: ` <div > <h2 > 我是cpn2</h2 > <h3 > 我是,呵呵呵呵</h3 > </div > ` } } }); </script > </body >
组件模块的分离写法 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 <body > <div id ="app" > <cpn > </cpn > <cpn1 > </cpn1 > </div > <script type ="text/x-template" id ="cpn" > <div > <h2 > 我是cpn1</h2 > <h3 > 我是,哈哈哈哈</h3 > </div > </script > <template id ="cpn1" > <div > <h2 > 我是cpn1</h2 > <h3 > 我是,哈哈哈哈</h3 > </div > </template > <script > Vue .component ("cpn" , { template : '#cpn1' }) const app = new Vue ({ el : '#app' , data : { } }); </script > </body >
组件中的数据存放问题 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 <body > <div id ="app" > <cpn > </cpn > <cpn > </cpn > </div > <template id ="cpn1" > <div > <h2 > 我是cpn1</h2 > <h3 > 我是,哈哈哈哈</h3 > <h3 > {{title}}</h3 > </div > </template > <script > Vue .component ("cpn" , { template : '#cpn1' , data ( ) { return { title : '好好学习,天天向上' } } }) const app = new Vue ({ el : '#app' , data : { title : '好好学习,天天向上' } }); </script > </body >
组件中的data为什么必须是函数 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 <body > <div id ="app" > <cpn > </cpn > <cpn > </cpn > <hr > <cpn1 > </cpn1 > <cpn1 > </cpn1 > </div > <template id ="cpn1" > <div > <h3 > 当前计数:{{count}}</h3 > <button @click ="increment" > +</button > <button @click ="decrement" > -</button > </div > </template > <template id ="cpn2" > <div > <h3 > 当前计数:{{count}}</h3 > <button @click ="increment" > +</button > <button @click ="decrement" > -</button > </div > </template > <script > Vue .component ("cpn" , { template : '#cpn1' , data ( ) { return { count : 0 } }, methods : { increment ( ) { this .count ++ }, decrement ( ) { this .count -- } } }) const obj = { count : 0 }; Vue .component ("cpn1" , { template : '#cpn2' , data ( ) { return obj }, methods : { increment ( ) { this .count ++ }, decrement ( ) { this .count -- } } }) const app = new Vue ({ el : '#app' , }); </script > </body >
组件通信-父组件向子组件传递数据 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 <body > <div id ="app" > {{movies.toString()}} <hr > <cpn v-bind:vmoives ="movies" :vmessage ="message" > </cpn > <hr > <cpn vmoives ="movies" vmessage ="message" > </cpn > </div > <template id ="cpn" > <div > <h2 > {{vmessage}}</h2 > <ul v-for ="(item,index) in vmoives" > <li > {{index}}.{{item}}</li > </ul > </div > </template > <script > const cpn = { template : '#cpn' , props : ['vmoives' , 'vmessage' ], data ( ) { return {} }, methods : { } } const app = new Vue ({ el : '#app' , data : { movies : ['海王' , '海贼王' , '航空母舰' ], message : '真香' }, components : { cpn } }); </script > </body >
组件通信-props用法详解 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 <body > <div id ="app" > {{movies.toString()}} <hr > <cpn v-bind:propF ="movies" :propC ="message" > </cpn > <hr > </div > <template id ="cpn" > <div > <h2 > {{propC}}</h2 > <ul v-for ="(item,index) in propF" > <li > {{index}}.{{item}}</li > </ul > </div > </template > <script > const cpn = { template : '#cpn' , props : { propA : Number , propB : [String , Number ], propC : { type : String , required : true , default : '你好呀' }, propD : { type : Number , default : 100 }, propE : { type : Object , default : function ( ) { return { message : 'hello' } } }, propF : { type : Array , default ( ) { return ['大话西游' , '造梦西游' ] } }, propG : { validator : function (value ) { return ['success' , 'warning' , 'danger' ].indexOf (value) !== -1 } } }, data ( ) { return {} } } const app = new Vue ({ el : '#app' , data : { movies : ['海王' , '海贼王' , '航空母舰' ], message : '真香' }, components : { cpn } }); </script > </body >
组件通信-父传子(props不支持驼峰标识) 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 <body > <div id ="app" > <cpn v-bind:prop-f ="movies" v-bind:prop-g ="message" > </cpn > <hr > </div > <template id ="cpn" > <div > <h2 > {{propG}}</h2 > <ul v-for ="(item,index) in propF" > <li > {{index}}.{{item}}</li > </ul > </div > </template > <script > const cpn = { template : '#cpn' , props : { propE : { type : Object , default : function ( ) { return { message : 'hello' } } }, propF : { type : Array , default ( ) { return ['大话西游' , '造梦西游' ] } }, propG : { validator : function (value ) { console .log (['success' , 'warning' , 'danger' ].indexOf (value) !== -1 ); return ['success' , 'warning' , 'danger' ].indexOf (value) !== -1 } } }, data ( ) { return {} } } const app = new Vue ({ el : '#app' , data : { movies : ['海王' , '海贼王' , '航空母舰' ], message : 'succe' }, components : { cpn } }); </script > </body >
组件通信-父子组件通信的案例 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 <body > <div id ="app" > <cpn v-on:item-click ="cpnClick" > </cpn > <hr > <cpn @item-click ="cpnClick($event)" > </cpn > </div > <template id ="cpn" > <div > <button v-for ="(item,index) in categories" @click ="btnClick(item)" > {{item.name}}</button > </div > </template > <script > const cpn = { template : '#cpn' , data ( ) { return { categories : [ {id : 'a1' , name : '热门推荐' }, {id : 'a2' , name : '手机数码' }, {id : 'a3' , name : '家用家电' }, {id : 'a4' , name : '电脑办公' } ] } }, methods : { btnClick (item ) { this .$emit('item-click' , item) } } } const app = new Vue ({ el : '#app' , components : { cpn }, methods : { cpnClick (item ) { console .log ('cpnClick' , item); } }, }); </script > </body >
组件通信-数字游戏-1 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 <body > <div id ="app" > <cpn :number1 ="num1" :number2 ="num2" > </cpn > </div > <template id ="cpn" > <div > <h2 > 双向绑定的是num1:{{dnum1}}</h2 > <h2 > props:{{number1}}</h2 > <input type ="text" v-model ="dnum1" > <h2 > 双向绑定的是num2:{{dnum2}}</h2 > <h2 > props:{{number2}}</h2 > <input type ="text" v-model ="dnum2" > </div > </template > <script > const app = new Vue ({ el : '#app' , data : { num1 : 0 , num2 : 1 }, components : { cpn : { template : '#cpn' , props : { number1 : Number , number2 : Number }, data ( ) { return { dnum1 : this .number1 , dnum2 : this .number2 } } } }, methods : { } }); </script > </body >
组件通信-数字游戏-2 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 <body > <div id ="app" > <cpn :number1 ="num1" :number2 ="num2" @change1props ="change1props" @change2props ="change2props" > </cpn > </div > <template id ="cpn" > <div > <h2 > 双向绑定的是num1:{{dnum1}}</h2 > <h2 > props:{{number1}}</h2 > <input type ="text" :value ="dnum1" @input ="changeInputValue1" > <h2 > 双向绑定的是num2:{{dnum2}}</h2 > <h2 > props:{{number2}}</h2 > <input type ="text" :value ="dnum2" @input ="changeInputValue2" > </div > </template > <script > const app = new Vue ({ el : '#app' , data : { num1 : 0 , num2 : 1 }, components : { cpn : { template : '#cpn' , props : { number1 : Number , number2 : Number }, data ( ) { return { dnum1 : this .number1 , dnum2 : this .number2 } }, methods : { changeInputValue1 (event ) { this .dnum1 = event.target .value ; this .$emit('change1props' , this .dnum1 ) this .dnum2 = this .dnum1 / 2 this .$emit('change2props' , this .dnum2 ) }, changeInputValue2 ( ) { this .dnum2 = event.target .value ; this .$emit('change2props' , this .dnum2 ) this .dnum1 = this .dnum2 * 2 this .$emit('change1props' , this .dnum1 ) } }, } }, methods : { change1props (value ) { console .log ('dum1' + value); this .num1 = parseFloat (value); }, change2props (value ) { console .log ('dum2' + value); this .num2 = parseFloat (value); } } }); </script > </body >
组件通信-父访问子-children-refs 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 <body > <div id ="app" > <cpn > </cpn > <cpn > </cpn > <cpn ref ="refA" > </cpn > <button @click ="btnClick" > 按钮</button > </div > <template id ="cpn" > <div > 我是子组件 </div > </template > <script > const app = new Vue ({ el : '#app' , data : { message : 'Lemon' }, methods : { btnClick ( ) { for (let item of this .$children ) { console .log (item.name ); item.showMessage () } console .log ('refs' + this .$refs .refA .name ); } }, components : { cpn : { template : '#cpn' , data ( ) { return { name : 'Lemon' , id : 1 , height : 1.78 } }, methods : { showMessage ( ) { console .log (this .id ); } }, } } }); </script > </body >
组件通信-子访问父-parent-root 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 <body > <div id ="app" > <cpn > </cpn > <hr > <ccpn > </ccpn > </div > <template id ="cpn" > <div > 我是cpn子组件</div > </template > <template id ="ccpn" > <div > <h3 > 我是cpn的子组件</h3 > <button @click ="btnClick" > ccpn按钮</button > </div > </template > <script > const ccpn = Vue .component ('ccpn' , { template : '#ccpn' , methods : { btnClick ( ) { console .log ('ccpn=' , this .$root .message ) } } }) const app = new Vue ({ el : '#app' , data : { message : 'Lemon' }, methods : { }, components : { cpn : { template : '#cpn' , data ( ) { return { name : '我是cpn的name' } }, components : { ccpn } } } }); </script > </body >
组件化高级 slot-插槽的基本使用 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 <body > <div id ="app" > <cpn > 嘻嘻嘻</cpn > <cpn > <button > 按钮</button > </cpn > <cpn > 哈哈哈</cpn > <cpn > </cpn > </div > <template id ="cpn" > <div > <h3 > 组件化开发</h3 > <slot > <button > 按钮</button > </slot > </div > </template > <script > const app = new Vue ({ el : '#app' , data : { }, methods : { }, components : { cpn : { template : '#cpn' } } }); </script > </body >
slot-具名插槽的使用 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 <body > <div id ="app" > <cpn > 嘻嘻嘻</cpn > <cpn > <span slot ="right" > 哈哈哈</span > </cpn > </div > <template id ="cpn" > <div > <slot name ="left" > 左边</slot > <slot name ="center" > 中间</slot > <slot name ="right" > 右边</slot > <slot > 右边</slot > </div > </template > <script > const app = new Vue ({ el : '#app' , data : { }, methods : { }, components : { cpn : { template : '#cpn' } } }); </script > </body >
什么是编译的作用域 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 <body > <div id ="app" > <cpn v-show ="isShow" > </cpn > </div > <template id ="cpn" > <div > <h2 > 我是组件</h2 > <h3 v-show ="isShowCpn" > 我是哈哈哈</h3 > </div > </template > <script > const app = new Vue ({ el : '#app' , data : { isShow : true }, methods : { }, components : { cpn : { template : '#cpn' , data ( ) { return { isShow : false , isShowCpn : true } } } } }); </script > </body >
作用域插槽的准备 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 <body > <div id ="app" > <cpn > </cpn > <hr > <cpn > 哈哈哈哈· <template > <div slot-scope ="slot" > <span v-for ="(item,index) in slot.data" > - {{item}} {{item}} - </span > <hr > </div > </template > </cpn > <hr > <cpn > <template v-slot:todo ="slotProps" > <div > 加join():<span > - {{slotProps.data.join(' - ')}}</span > <br > <span > {{slotProps.data}}</span > </div > </template > </cpn > </div > <template id ="cpn" > <div > <slot :data ="pLanguages" name ="todo" > <ul > <li v-for ="(item,index) in pLanguages" > {{item}} </li > </ul > </slot > </div > </template > <script > const app = new Vue ({ el : '#app' , data : { }, methods : { }, components : { cpn : { template : '#cpn' , data ( ) { return { pLanguages : ['Java' , 'C' , 'C++' , 'Python' , 'C#' ] } } } } }); </script > </body >
前端模块化 ES模块化的实现 aaa.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var name = '小红' let age = 18 var flag = true function sum (num1, num2 ) { return num1 + num2 } if (flag) { console .log (sum (200 , 300 )); } export { flag, sum }
bbb.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var name = '小红' var flag = false
index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <!DOCTYPE html > <html lang ="en" > <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 > Document</title > </head > <body > <script src ="aaa.js" type ="module" > </script > <script src ="bbb.js" type ="module" > </script > <script src ="mmm.js" type ="module" > </script > </body > </html >
mmm.js
1 2 3 4 5 import {flag} from "./aaa.js" ;if (flag) { console .log ('小明是天才,哈哈哈哈' ); }
webpack使用 webpack的起步 info.js
1 2 3 export const name = 'why' export const age = 18 export const height = 1.78
main.js
1 2 3 4 5 6 7 8 9 10 11 12 const {add, mul} = require ('./mathUtils.js' )console .log (add (20 , 30 ));console .log (mul (25 , 30 ));import {name, age, height} from "./info" ;console .log (name);console .log (age);console .log (height);
mathUtils.js
1 2 3 4 5 6 7 8 9 10 11 12 function add (num1, num2 ) { return num1 + num2 } function mul (num1, num2 ) { return num1 * num2 } module .exports = { add, mul }
index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <!DOCTYPE html > <html lang ="en" > <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 > Document</title > </head > <body > <script src ="./dist/bundle.js" > </script > </body > </html >
webpack的配置 webpack.config.js
1 2 3 4 5 6 7 8 9 10 11 12 const path = require ('path' )module .exports = { entry : './src/main.js' , output : { path : path.resolve (__dirname, 'dist' ), filename : 'bundle.js' }, }
package.json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 { "name" : "meetwebpack" , "version" : "1.0.0" , "description" : "" , "main" : "webpack.config.js" , "scripts" : { "test" : "echo \"Error: no test specified\" && exit 1" , "build" : "webpack" } , "author" : "" , "license" : "ISC" , "devDependencies" : { "webpack" : "^3.6.0" } }
webpack配置loader和vue webpack.config.js
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 const path = require ('path' )module .exports = { entry : './src/main.js' , output : { path : path.resolve (__dirname, 'dist' ), filename : 'bundle.js' , publicPath : 'dist/' }, module : { rules : [{ test : /\.css$/i , use : ['style-loader' , 'css-loader' ], }, { test : /\.less$/ , use : [{ loader : "style-loader" }, { loader : "css-loader" }, { loader : "less-loader" }] }, { test : /\.(png|jpg|gif)$/ , use : [{ loader : 'url-loader' , options : { limit : 8192 , name : 'img/[name].[hash:8].[ext]' } }] }, { test : /\.js$/ , exclude : /(node_modules|bower_components)/ , use : { loader : 'babel-loader' , options : { presets : ['es2015' ] } } } ], }, }
html index.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 <!DOCTYPE html > <html lang ="en" > <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 > Document</title > </head > <body > <script src ="./dist/bundle.js" > </script > </body > </html >
js main.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 const {add, mul} = require ('./js/mathUtils.js' )console .log (add (20 , 30 ));console .log (mul (25 , 30 ));import {name, age, height} from "./js/info" ;console .log (name);console .log (age);console .log (height);require ('./css/normal.css' )require ('./css/special.less' )document .writeln ('<h2>你好呀,李银河</h2>' )
info.js
1 2 3 export const name = 'why' export const age = 18 export const height = 1.78
mathUtils.js
1 2 3 4 5 6 7 8 9 10 11 12 function add (num1, num2 ) { return num1 + num2 } function mul (num1, num2 ) { return num1 * num2 } module .exports = { add, mul }
css normal.css
1 2 3 4 body { background : url ("../img/timg1.jpg" ) }
special.less
1 2 3 4 5 6 7 @fontSize : 50px ;@fontColor : orange;body { font-size : @fontSize; color : @fontColor }
模块展示
vue-cli3使用 App.vue
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 <template > <div id ="app" > <img alt ="Vue logo" src ="./assets/logo.png" > <HelloWorld msg ="Welcome to Your Vue.js App" /> </div > </template > <script > import HelloWorld from './components/HelloWorld.vue' export default { name : 'app' , components : { HelloWorld } } </script > <style > #app { font-family : 'Avenir' , Helvetica, Arial, sans-serif; -webkit-font-smoothing : antialiased; -moz-osx-font-smoothing : grayscale; text-align : center; color : #2c3e50 ; margin-top : 60px ; } </style >
HelloWorld.vue
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 <template > <div class ="hello" > <h1 > {{ msg }}</h1 > </div > </template > <script > export default { name : 'HelloWorld' , props : { msg : String } } </script > <style scoped > h3 { margin : 40px 0 0 ; } ul { list-style-type : none; padding : 0 ; } li { display : inline-block; margin : 0 10px ; } a { color : #42b983 ; } </style >
main.js
1 2 3 4 5 6 7 8 9 10 11 12 import Vue from 'vue' import App from './App.vue' Vue .config .productionTip = false new Vue ({ render : h => h (App ), }).$mount('#app' )
vue-router前端路由 vue-tabbar vuex axios request.js
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 import axios from 'axios' export function request (config ) { const instance = axios.create ({ baseURL : 'http://123.207.32.32:8000' , timeout : 5000 }) instance.interceptors .response .use (res => { return res }, err => { console .log (err); }) return instance (config) }
main.js
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 import Vue from 'vue' import App from './App' import axios from 'axios' Vue .config .productionTip = false new Vue ({ el : '#app' , render : h => h (App ) }) import { request } from "./network/request" ; request ({ url : '/home/multidata' }).then (res => { console .log (res); }).catch (err => { console .log (err); })