-
渐进式框架 哪里用到嵌入到哪里
-
Core + Vue-router + Vuex
Vue特点和功能
-
解耦视图和数据
-
可复用的组件
-
前端路由技术
-
状态管理
-
虚拟DOM
基础前提
-
HTML CSS JavaScript
安装
-
CDN引入
开发版
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
生产版
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
-
下载和引入
-
NPM安装 推荐()
webpack和CLI
案例
-
new Vue()对象
-
挂载对象el
-
数据data
-
v-for遍历列表
-
<li v-for="(item,index) in moveies">{{item}}</li>
-
点击事件
-
v-on:click 语法糖 简写 @click
-
函数定义
-
methods:{
add:function(){
},
sub:function(){
}
} -
调用
-
<button v-on:click="add">+</button>
-
<button @click="sub">-</button>
-
调用变量
-
this.counter
MVVM
-
View-------ViewModel------Model
-
视图层-----视图模型层-----数据层
创建Vue实例传入的options
-
el string | HTMLElement 实例DOM
-
data Object | Function (组件必须是函数) 数据对象
-
methods ([key:string] Function) 方法
生命周期(钩子函数)
new Vue() 对象内部的一系列操作
-
beforeCreate:function(){}
-
created:function(){}
-
mounted:function(){}
基本语法
插值操作
-
Mustache语法 {{}}
-
v-once指令 只显示第一次的状态 取消响应式
-
<h2 v-once>{{messages}}</h2>
<!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><div id="app"> <h2>{{messages}}</h2> <h2 v-once>{{messages}}</h2> </div> <script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ messages:"你好" }, }) </script>
</body>
</html>
-
v-html 解析html数据
-
<h2 v-html="url"></h2>
<div id="app"> <h2>{{messages}}</h2> <h2 v-html="url"></h2> </div><script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ messages:"你好", url:'<a href="http://wwww.baidu.com">百度一下</a>' }, }) </script></pre>
-
v-text 不推荐使用
-
<h2 v-text="messages"></h2>
<div id="app"> <h2>{{messages}},sasfa</h2> <!-- 你好,sasfa--> <h2 v-text="messages"></h2> <!-- 你好 --> <!-- 覆盖 --> <h2 v-text="messages">,sasfa</h2> <!-- ,sasfa --> </div><script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ messages:"你好", }, }) </script></pre>
-
v-pre的使用 原封不动
-
<h2 v-pre>{{messages}}</h2>
<div id="app"> <h2>{{messages}}</h2> <h2 v-pre>{{messages}}</h2> <!-- 原封显示 --> <!-- {{messages}} --> </div><script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ messages:"你好", }, }) </script></pre>
-
v-cloak指令 vue解析完成会删除该属性
<!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> <style> [v-cloak]{ display: none; } </style> </head> <body><div id="app" v-cloak> <h2>{{messages}}</h2> </div> <script src="../js/vue.js"></script> <script> setTimeout(function(){ const app = new Vue({ el:"#app", data:{ messages:"你好", }, }) },1000); </script>
</body>
</html>
-
v-bind操作 动态写属性 缩写: 语法糖
<div id="app"> <h2>{{messages}}</h2> <!-- <img src="https://img13.360buyimg.com/n1/jfs/t1/82232/33/6593/192712/5d4b9de7Ee0fcb246/f5af33071e9815ee.jpg" alt=""> --> <!-- <img src="{{imgUrl}}" alt=""> 错误写法--> <!-- <img src="imgUrl" alt=""> 错误写法--> <!-- <img v-bind:src="{{imgUrl}}" alt=""> 错误写法--><img v-bind:src="imgUrl" alt=""> <a :href="linkURL">百度一下</a> </div> <script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ messages:"你好", imgUrl:"https://img13.360buyimg.com/n1/jfs/t1/82232/33/6593/192712/5d4b9de7Ee0fcb246/f5af33071e9815ee.jpg", linkURL:"https://www.baidu.com", }, }) </script></pre>
-
v-bind 绑定class属性 对象语法
<!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> <style> .active{ color: red; } </style> </head> <body><div id="app"> <h2 :class="active">{{messages}}</h2> <!-- 使用场景 --> <!-- <h2 v-bind:class="{key1:value1,key2:value2}">{{messages}}</h2> --> <!-- <h2 v-bind:class="{类名1:boolean,类名2:boolean}">{{messages}}</h2> --> <h2 v-bind:class="{active:isActive,line:isLine}">{{messages}}</h2> <button v-on:click="btnclick">按钮</button> <!-- 固定不变的直接写 --> <h2 class="title" v-bind:class="getclasses()">{{messages}}</h2> </div> <script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ messages:"你好", isActive:true, isLine:true, }, methods:{ btnclick:function(){ this.isActive=!this.isActive; }, getclasses:function(){ return {active:this.isActive,line:this.isLine}; } } }) </script>
</body>
</html>
-
v-bind 动态绑定class 数组语法
<!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> <style> .active{ color: red; } </style> </head> <body><div id="app"> <h2 class="title" :class="[active,line]">{{messages}}</h2> <h2 class="title" :class="getclasses()">{{messages}}</h2> </div> <script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ messages:"你好", active:"aaa", line:"bbb", }, methods:{ getclasses:function(){ return [this.active,this.line]; } } }) </script>
</body>
</html>
案例
-
v-for和v-bind的结合
<div id="app"> <ul> <li v-for="(item,index) in movies" :class="{active:currentIndex === index}" @click="btnclick(index)" >{{item}}</li> </ul> </div><script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ movies:['海王','海尔兄弟','火隐忍者','进击的巨人'], currentIndex:0, }, methods:{ btnclick(index){ this.currentIndex=index; } } }) </script></pre>
动态绑定style
对象写法
-
<h2 :style="{key(属性名): value(属性值)}">{{messages}}</h2>
-
<h2 :style="{fontSize:'50px'}">{{messages}}</h2>
-
h2 :style="{fontSize:finalSize}">{{messages}}</h2>
-
h2 :style="{fontSize:finalSize2 + px}">{{messages}}</h2>
-
注意不加单引号作为变量使用
<body><div id="app"> <!-- <h2 :style="{key(属性名): value(属性值)}">{{messages}}</h2> --> <!-- <h2 :style="{fontSize:'50px'}">{{messages}}</h2> --> <!-- <h2 :style="{fontSize:finalSize}">{{messages}}</h2> --> <h2 :style="{fontSize:finalSize2 + 'px',color:finalColor,backgroundColor:finalBgColor}">{{messages}}</h2> </div> <script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ messages:"你好", finalSize:'100px', finalSize2:100, finalColor:'#ddd', finalBgColor:'red', }, }) </script>
</body>
数组写法
-
<h2 :style="[baseStyle,baseStyle1]">{{messages}}</h2>
<div id="app"> <h2 :style="[baseStyle,baseStyle1]">{{messages}}</h2> </div><script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ messages:"你好", baseStyle:{backgroundColor:'red'}, baseStyle1:{fontSize:'100px'}, }, }) </script></pre>
计算属性
computed:{ fullName:function(){ return this.firstName + ' ' + this.lastName; } },<div id="app"> <h2>{{firstName + ' ' + lastName}}</h2> <h2>{{firstName}} {{lastName}}</h2> <h2>{{getFullName()}}</h2> <!-- 计算属性 --> <h2>{{fullName}}</h2> </div><script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ firstName:"nick", lastName:"mike" }, computed:{ fullName:function(){ return this.firstName + ' ' + this.lastName; } }, methods:{ getFullName(){ return this.firstName + ' ' + this.lastName; } } }) </script></pre>
复杂操作
<div id="app"> <h2>总价格:{{totalPrice}} </h2> </div><script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ messages:"你好", books:[ {id:110,name:'unix',price:119}, {id:111,name:'代码大全',price:105}, {id:112,name:'计算机',price:87}, {id:113,name:'操作系统',price:78} ], }, computed:{ totalPrice:function(){ let result = 0; for(let i =0;i < this.books.length;i++){ result += this.books[i].price; } return result; } }, }) </script></pre>
setter 和 getter 计算属性的本质
<div id="app"> <h2>{{fullName}}</h2> </div><script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ firstName:"nack", lastName:"maaty", }, computed:{ // fullName:{ // //一般set只读 // //所以不写 // // set:function(newVal){ // // }, // get:function(){ // return this.firstName + ' ' + this.lastName // } // } //简写 fullName:function(){ return this.firstName + ' ' + this.lastName } } }) </script></pre>
计算属性和methods的对比 计算属性的缓存
-
调用次数上
<div id="app"> <!-- 直接拼接 pass--> <!-- <h2>{{firstName}} {{lastName}}</h2> --><!--对比多次调用 --> <!-- methods实现 --> <h2>{{getFullName()}}</h2> <h2>{{getFullName()}}</h2> <h2>{{getFullName()}}</h2> <h2>{{getFullName()}}</h2> <!-- console.log("getFullName")打印4次 --> <!-- computed实现 --> <h2>{{fullName}}</h2> <h2>{{fullName}}</h2> <h2>{{fullName}}</h2> <h2>{{fullName}}</h2> <!-- console.log("fullName")打印1次 --> <!-- 缓存 --> <!-- 性能提高 --> </div> <script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ firstName:"nack", lastName:"maaty", }, methods:{ getFullName:function(){ console.log("getFullName") return this.firstName + ' ' + this.lastName; } }, computed:{ fullName:function(){ console.log("fullName") return this.firstName + ' ' + this.lastName; } }, }) </script></pre>
事件监听
-
v-on:click及@click
<div id="app"> <h2>{{counter}}</h2> <!-- <button v-on:click="counter++">+</button> <button v-on:click="counter--">-</button> --> <button @click="increment">+</button> <button @click="decrement">-</button> </div><script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ counter:0, }, methods:{ increment(){ this.counter++; }, decrement(){ this.counter--; } }, }) </script></pre>
-
v-on参数
-
有无括号的区别
-
默认形参
-
浏览器event对象获取
<div id="app"> <!-- 无参数写法 --> <button @click="btnClick1()">按钮1</button> <button @click="btnClick1">按钮1</button><!-- 有参数 --> <button @click="btnClick2(123)">按钮2</button> <!-- 有参无传入 默认undefined --> <button @click="btnClick2()">按钮2</button> <!-- 省略括号 默认为event对象 --> <button @click="btnClick2">按钮2</button> <!-- 函数需要event也需要abc --> <!-- 参数1abc为event,而参数二为undefined --> <button @click="btnClick3">按钮3</button> <!-- 这条报错 event被当作变量或方法 --> <button @click="btnClick3(123,event)">按钮3</button> <!-- 如何主动获取浏览器event --> <button @click="btnClick3(123,$event)">按钮3</button> </div> <script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ counter:0, }, methods:{ btnClick1(){ console.log("btnClick1"); }, btnClick2(abc){ console.log("btnClick2----",abc); }, btnClick3(abc,event){ console.log("btnClick3----",abc,event); } }, }) </script></pre>
-
v-on修饰符
-
.stop
-
.prevent
-
@keyup
-
.enter
-
.once
<div id="app"> <div @click="divClick"> <!-- .stop 阻止事件冒泡 调用event.stopPropagation()--> <button @click.stop="btnclick">按钮</button> </div><form action="baidu"> <!-- .prevent 阻止默认行为 调用event.preventDefault()--> <input type="submit" value="提交" @click.prevent="submitClick"> </form> <!-- 监听键盘事件keyup --> <input type="text" @keyup="keyup"/> <!-- 监听键盘enter事件 --> <input type="text" @keyup.enter="keyup"/> <!-- once修饰符 只能执行一次--> <button @click.once="btn2click">按钮2</button> </div> <script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ messages:"你好", }, methods:{ divClick(){ console.log("divClick"); }, btnclick(){ console.log("btnclick"); }, submitClick(){ console.log("submitClick"); }, keyup(){ console.log("keyup"); }, btn2click(){ console.log("btn2click"); }, } }) </script></pre>
条件判断
-
v-if,v-else-if,v-else
<div id="app"> <!-- 简单逻辑使用 --> <h2 v-if="isShow">{{messages}}</h2> <h2 v-else=> isShow为false </h2><!-- 不常用 一版用计算属性进行 --> <h2 v-if="score>=90">优秀</h2> <h2 v-else-if="score>=80">良好</h2> <h2 v-else-if="score>=60">及格</h2> <h2 v-else="score>=90">不及格</h2> </div> <script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ messages:"你好", isShow:true, score:99, }, }) </script></pre>
条件渲染案例
<div id="app"> <span v-if="isUser"> <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="isUser = !isUser">切换类型</button> </div><script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ isUser:true }, }) </script></pre>
-
案例问题
-
input的内容保留问题
-
原因: 生成虚拟DOM 与 真实DOM对比时 不一样的进行渲染 并不是重新生成新的input(复用之前的)
-
解决: key标识
<!-- input的内容保留问题 --> <!-- 原因: 生成虚拟DOM 与 真实DOM对比时 不一样的进行渲染 并不是重新生成新的input(复用之前的)--> <!-- 解决: key标识 --> <div id="app"> <span v-if="isUser"> <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="email"/> </span> <button @click="isUser = !isUser">切换类型</button> </div><script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ isUser:true }, }) </script></pre>
-
v-show
<div id="app"> <!-- 直接删除DOM --> <!-- 一般只切换几次的操作 --> <h2 v-if="isShow" id="aaa">{{messages}}</h2><!-- 只是给DOM增加了display样式 --> <!-- 切换频率高使用 --> <h2 v-show="isShow" id="bbb">{{messages}}</h2> </div> <script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ messages:"你好", isShow:true, }, }) </script></pre>
遍历循环
-
v-for
<div id="app"> <!-- 遍历数组 --> <ul> <li v-for="item in names">{{item}}</li> </ul><!-- 获取索引 --> <ul> <li v-for="(item,index) in names">{{index+1}}.{{item}}</li> </ul> <!-- 遍历对象 --> <!-- 只拿value --> <ul> <li v-for="item in info">{{item}}</li> </ul> <!-- 获取value和key --> <ul> <li v-for="(value,key) in info">{{value}}:{{key}}</li> </ul> <!-- 获取下标index --> <ul> <li v-for="(value,key,index) in info">{{value}}:{{key}}--{{index}}</li> </ul> </div> <script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ messages:"你好", names:['nick',"jack","mary"], info:{ name:"nick", age:18, height:1.88, } }, }) </script></pre>
-
遍历的时候加上一个key
为了更好的复用 -
v-for 使用key 不要使用index作为key
<div id="app"> <ul> <!-- 在某个位置插入元素 letters.splice(2,0,'F') --> <!-- 设计性能问题 这种是替换操作 该位置之后的都会替换 (进行重新编排位置) --> <!-- 引入key 解决性能问题 不要使用index作为key--> <li v-for="item in letters" :key="item">{{item}}</li> </ul> </div><script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ messages:"你好", letters:['A','B','C','D','E'], }, }) </script></pre>
数组中的响应式方法
-
响应式
-
push(),pop(),shift(),unshift(),splice(),sort(),reverse(),Vue.set();
-
-
非响应式
-
this.letters[0]="bbbb";
-
<div id="app"> <ul> <li v-for="item in letters">{{item}}</li> </ul><button @click="btnClick">按钮</button> </div> <script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ messages:"你好", letters:['A','C','B','D'], }, methods:{ btnClick(){ // 响应式 //1.push方法 添加最后 // this.letters.push("aaa"); //多个 // this.letters.push("aaa","bbb","ccc"); //2.pop() 删除最后 // this.letters.pop(); //3.shift() 删除最前 // this.letters.shift(); //4.unshift() 添加最前 // this.letters.unshift("aaa"); //多个 // this.letters.unshift("aaa","bbb","ccc"); //5.splice() 删除或插入或替换 // 删除 从第2个位置开始 删除1个 索引0开始 // this.letters.splice(2,1) //不传入 从第2个位置开始 删除后面所有 // this.letters.splice(2); //插入 从第2个位置开始插入 删除0个 插入aaa,bbb // this.letters.splice(2,0,"aaa","bbb"); //替换 从第2个位置开始 删除1个 替换为aaa,bbb // this.letters.splice(2,1,"aaa","bbbb"); //Vue内部的方式 Vue.set(this.letters,2,"bbbb"); //6.sort() 排序 正向 // this.letters.sort(); //7.reverse() 反转 // this.letters.reverse(); //非响应式 //1..通过索引值修改数组中的元素 非响应式 // this.letters[0]="bbbb"; } } }) </script></pre>
书籍购物车案例
table{ border: 1px solid #e9e9e9; border-collapse: collapse; border-spacing: 0; }th,td{
padding: 0px 16px;
border: 1px solid #e9e9e9;
text-align: left;
}th{
background-color: #f7f7f7;
color: #5c6b77;
font-weight: 600;
}<div id="app"> <div v-if="books.length"> <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"> <td>{{item.id}}</td> <td>{{item.name}}</td> <td>{{item.date}}</td> <!-- <td>¥{{item.price.toFixed(2)}}</td> --> <!-- <td>{{getFinalPrice(item.price)}}</td> --> <!-- 推荐方法 使用过滤器--> <td>{{item.price | showPrice}}</td> <td> <!-- 动态添加属性disabled --> <button @click="decrement(index)" v-bind:disabled="item.count <= 1">-</button> {{item.count}} <button @click="increment(index)">+</button> </td> <td> <button @click="removehandle(index)">移除</button> </td> </tr> </tbody> </table> <h2>总价格: {{totalPrice | showPrice}}</h2> </div> <h2 v-else>购物车为空</h2> </div> <script src="../js/vue.js"></script> <script src="./main.js"></script> const app = new Vue({ el:"#app", data:{ books:[ { id:1, name:"《算法导论》", date:"2006-9", price:85.00, count:1, }, { id:2, name:"《LUIX编程艺术》", date:"2006-2", price:59.00, count:1, }, { id:3, name:"《编程特玑》", date:"2006-9", price:85.00, count:1, }, { id:4, name:"《代码大全》", date:"200613", price:128.00, count:1, }, ] }, methods:{ getFinalPrice(price){ return '¥' + price.toFixed(2); }, decrement(index){ this.books[index].count--; }, increment(index){ this.books[index].count++; }, removehandle(index){ this.books.splice(index,1); } }, computed:{ totalPrice(){ let totalPrice = 0; // for( let i = 0; i < this.books.length; i++){ // totalPrice += this.books[i].price * this.books[i].count; // } // for(let i in this.books){ // totalPrice += this.books[i].price * this.books[i].count; // } for(let item of this.books){ totalPrice += item.price * item.count; } return totalPrice; //return this.books.reduce( //(preValue,book) => preValue + book.price * book.count,0); } }, filters:{ showPrice(price){ return '¥' + price.toFixed(2); } } })js高级函数
-
filter
-
map
-
reduce
<script> // filter/mpa/reduceconst nums = [10,20,111,222,44,40,50]; // filter的回调函数为boolean类型 满足加入新数组 let newNums = nums.filter(function(n){ return n<100 }) console.log(newNums) //map 返回结果 let new2Nums = newNums.map(function(n){ return n * 2; }) console.log(new2Nums) //reduce 对数组中所有内容进行汇总 preValue:上一次返回的值 n 表示遍历的当前值 let total = new2Nums.reduce(function(preValue,n){ return preValue + n; }); console.log(total); let totalAll = nums.filter(function(n){ return n < 100; }).map(function(n){ return n * 2; }).reduce(function(preValue,n){ return preValue + n; }) console.log(totalAll); let totalAll2 = nums.filter(n => n < 100).map(n=>n*2).reduce((preValue,n)=>preValue+n); console.log(totalAll2); </script></pre>
v-model
-
实现及原理
<!-- 双向绑定 --> <!-- 数据联动 --><div id="app"> <input type="text" v-model="messages"/> <h2>{{messages}}</h2> <!-- 原理 --> <input type="text" v-bind:value="messages" @input="messages = $event.target.value"/> <!-- 原理 --> <!-- input 的 value属性 和输入事件 v-on:input --> <!-- <input type="text" :value="messages" v-on:input="valueChange"> --> <!-- 实现方法 --> </div> <script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ messages:"你好", }, methods:{ valueChange(event){ this.messages=event.target.value } } }) </script></pre>
-
v-model与radio结合
<div id="app"> <!-- 与radio结合 --> <!-- 加上v-model 省略了name属性 依然互斥 --> <label for="male"> <input type="radio" id="male" value="男" v-model="sex"/>男 </label><label for="female"> <input type="radio" id="female" value="女" v-model="sex"/>女 </label> <h2>您选择的性别是: {{sex}}</h2> </div> <script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ messages:"你好", sex:'男', }, }) </script></pre>
-
v-model与checkbox结合
<div id="app"> <label for="agree"> <input type="checkbox" id="agree" v-model="isAgree"/>同意协议 </label> <h2>您选择的是: {{isAgree}}</h2> <button :disabled="!isAgree">下一步</button><!-- 多选 --> <input type="checkbox" value="篮球" v-model="hobbies"/>篮球 <input type="checkbox" value="足球" v-model="hobbies"/>足球 <input type="checkbox" value="乒乓球" v-model="hobbies"/>乒乓球 <input type="checkbox" value="羽毛球" v-model="hobbies"/>羽毛球 <h2>您的爱好是: {{hobbies}}</h2> </div> <script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ messages:"你好", isAgree:false, hobbies:[], }, }) </script></pre>
-
v-model与select结合
<div id="app"> <!-- 选择一个 --> <select name="abc" v-model="fruit"> <option value="苹果">苹果</option> <option value="香蕉">香蕉</option> <option value="榴莲">榴莲</option> <option value="葡萄">葡萄</option> </select> <h2>您选择的水果是: {{fruit}}</h2><!-- 选择多个 --> <select name="abc" v-model="fruits" multiple> <option value="苹果">苹果</option> <option value="香蕉">香蕉</option> <option value="榴莲">榴莲</option> <option value="葡萄">葡萄</option> </select> <h2>您选择的水果是: {{fruits}}</h2> </div> <script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ messages:"你好", fruit:'香蕉', fruits:[], }, }) </script>
</body>
值绑定
-
动态显示数据 也就是v-bind
<div id="app"><h2>您的爱好是: {{hobbies}}</h2>
<!-- 值绑定 就是不要写死 也就是 v-bind 下面语法糖:-->
<label v-for="item in originHobbies" :for="item">
<input type="checkbox" :value="item" :id="item" v-model="hobbies">{{item}}
</label>
</div><script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ messages:"你好", hobbies:[], originHobbies:["篮球","足球","乒乓球","羽毛球","台球","高尔夫球"], }, }) </script></pre>
v-model修饰符
-
lazy
-
number
-
trim
<div id="app"> <!-- 修饰符 --> <!-- 1.lazy --> <!-- 解决实时动态绑定 回车或失去焦点的时候的时候绑定 --> <input type="text" v-model.lazy="messages"> <h2>{{messages}}</h2><!-- 2.number --> <!-- v-model默认为string类型 --> <input type="number" v-model.number="age"> <h2>{{age}}-{{typeof age}}</h2> <!-- 3.trim 去首尾空格 控制台查看--> <input type="text" v-model.trim="name"> <h2>您输入的名字是: {{name}}</h2> </div> <script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ messages:"你好", age:"", name:"", }, }) </script></pre>
组件化
-
拆分零件思想
-
独立小组件
-
形成组件树
-
步骤
-
创建组件构造器 Vue.extend()
-
注册组件 Vue.component()
-
使用组件
-
<div id="app"> <!-- 3. 使用组件 --> <mycpn></mycpn> <mycpn></mycpn> <mycpn></mycpn> <mycpn></mycpn> </div><script src="../js/vue.js"></script> <script> //1.创建组件构造器对象 const cpnC = Vue.extend({ template: ` <div> <h2>我是标题</h2> <p>我是内容1111111</p> <p>我是内容2222222</p> </div> ` }); //2.注册组件 Vue.component('mycpn',cpnC); const app = new Vue({ el:"#app", data:{ messages:"你好", }, }) </script></pre>
全局组件和局部组件
components:{ cpn:cpnC, },
<div id="app"> <!-- <my-cpn></my-cpn> <my-cpn></my-cpn> <my-cpn></my-cpn> --> <cpn></cpn> <cpn></cpn> </div><script src="../js/vue.js"></script> <script> const cpnC = Vue.extend({ template: ` <div> <h2>我是标题</h2> <p>我是内容111111</p> </div> ` }); // 全局注册 // Vue.component('my-cpn',cpnC); const app = new Vue({ el:"#app", data:{ messages:"你好", }, // 局部注册 components:{ cpn:cpnC, }, }) </script></pre>
父组件和子组件
<div id="app"> <cpn2></cpn2><!-- 报错 cpn1未注册 单独使用 必须去注册--> <!-- <cpn1></cpn1> --> </div> <script src="../js/vue.js"></script> <script> // 子组件 const cpnC1 = Vue.extend({ template:` <div> <h2>我是标题1</h2> <p>我是内容1111111</p> </div> `, }); //父组件 const cpnC2 = Vue.extend({ template:` <div> <h2>我是标题2</h2> <p>我是内容2222222</p> <cpn1></cpn1> </div> `, // 方式二 components:{ cpn1:cpnC1, } }) const app = new Vue({//顶层根组件 el:"#app", data:{ messages:"你好", }, // 方式一 components:{ cpn2:cpnC2, } }) </script></pre>
注册组件的语法糖
-
省略Vue.extend
-
使用对象替换
<div id="app"> <cpn1></cpn1> <cpn2></cpn2> </div><script src="../js/vue.js"></script> <script>
// 全局组件的语法糖 内部做了Vue.extend
Vue.component('cpn1',{
template:<div> <h2>我是标题1</h2> <p>我是内容1111111</p> </div>
});const app = new Vue({ el:"#app", data:{ messages:"你好", }, // 局部组件语法糖 components:{ 'cpn2':{ template:` <div> <h2>我是标题2</h2> <p>我是内容2222222</p> </div> ` }, } }) </script></pre>
组件模板抽离
-
script写法 必须是 type="text/x-template"
-
template
-
通过id绑定
<div id="app"> <cpn1></cpn1> <cpn1></cpn1> <cpn1></cpn1> </div><!-- 抽离写模板 --> <!-- 写法一 script写法 必须是 type="text/x-template"--> <!-- <script type="text/x-template" id="cpn"> <div> <h2>我是标题1</h2> <p>我是内容1111111</p> </div> </script> --> <!-- 写法二 --> <template id="cpn"> <div> <h2>我是标题111</h2> <p>我是内容1111111</p> </div> </template> <script src="../js/vue.js"></script> <script>
// 全局组件的语法糖 内部做了Vue.extend
Vue.component('cpn1',{
template:'#cpn',
});const app = new Vue({ el:"#app", data:{ messages:"你好", }, }) </script></pre>
组件如何获取data
-
组件不能直接访问Vue的data的属性
-
所以需要一个
自己的data
属性 -
这个data必须是
函数类型
<div id="app"> <cpn1></cpn1> <cpn1></cpn1> <cpn1></cpn1> </div> <!-- 写法二 --> <template id="cpn"> <div> <h2>{{title}}</h2> <p>我是内容1111111</p> </div> </template><script src="../js/vue.js"></script> <script>
// 全局组件的语法糖 内部做了Vue.extend
Vue.component('cpn1',{
template:'#cpn',
data(){
return{
title:"data标题返回"
}
}
});const app = new Vue({ el:"#app", data:{ messages:"你好", }, }) </script></pre>
-
为什么是函数
<div id="app"> <!-- 每个组件实例都是独立的 因为data是函数 返回的是一个新对象--> <cpn></cpn> <cpn></cpn> <cpn></cpn> </div><template id="cpn"> <div> <h2>当前计数: {{counter}}</h2> <button @click="increment">+</button> <button @click="decrement">-</button> </div> </template> <script src="../js/vue.js"></script> <script> // 直接写成属性 组件的实例共享一个data // 写成函数 组件实例每次返回的是一个新对象
// 相当于 属性写法
const obj = {
name:'jack',
age:18,
}function data(){ return obj; }
// 相当于 函数写法
function data(){
return {
name:'jack',
age:18,
};
}Vue.component('cpn',{ template:'#cpn', data(){ return{ counter:0, } }, methods:{ increment(){ this.counter++; }, decrement(){ this.counter--; } } }) const app = new Vue({ el:"#app", data:{ messages:"你好", }, }) </script></pre>
父子组件通讯
-
props传递 及定义写法
<!-- 注意使用 v-bind --> <div id="app"> <cpn :cmovies="movies" :cmessages="messages"></cpn> <!-- :cmovies必须传值 --> <!-- <cpn></cpn> --> <cpn :cmovies="movies"></cpn> </div><template id="cpn"> <div> <ul> <li v-for="item in cmovies">{{item}}</li> </ul> <h2>{{cmessages}}</h2> </div> </template> <script src="../js/vue.js"></script> <script> // 父传子 const cpn = { template:'#cpn', // 写法一 数组写法 // props:['cmovies','cmessages'], //写法二 对象写法 可以加类型 // 类型String Array Number Object 自定义类型 props:{ // cmovies:Array, // cmessages:String, // 提供默认值 cmovies:{ type:Array, // 默认值是对象和数组是 必须是个函数 default(){ return [] }, // 必须传值:required required:true, }, cmessages:{ // 多种类型 type:[String,Number], // type:String, default:111 }, }, data(){ return {} } } const app = new Vue({ el:"#app", data:{ messages:"你好", movies:['海王','海贼王','海尔兄弟'] }, components:{ cpn, } }) // 自定义类型 function Person(firstname,lastname){ this.firstname = firstname; this.lastname = lastname; } Vue.component('blog-post',{ props:{ author:Person } }) </script></pre>
-
props中驼峰用法
-
使用
-
拼接
<!-- v-bind 不支持驼峰 --> <div id="app"> <!-- <cpn :cinfo="info"></cpn> --> <!-- 支持驼峰 --> <cpn :c-info="info" :child-my-message="message"></cpn> </div><template id="cpn"> <!-- 外层需包裹起来 --> <div> <h2>{{cInfo}}</h2> <h2>{{childMyMessage}}</h2> </div> </template> <script src="../js/vue.js"></script> <script> const cpn ={ template:'#cpn', props:{ cInfo:{ type:Object, default(){ return {} } }, childMyMessage:{ type:String, default:"", } } } const app = new Vue({ el:"#app", data:{ info:{ name:'jack', age:18, height:1.88, }, message:"你好!" }, components:{ cpn, } }) </script></pre>
-
子传父
-
通过this.$emit('itemclick',item);传递事件和参数
-
父组件接收事件进行处理
<div id="app"> <!-- 监听事件 省略括号默认传递item 而不是event 因为itemclick不是浏览器生成的--> <cpn @itemclick="cpnClick"></cpn> </div><template id="cpn"> <!-- 外层需包裹起来 --> <div> <button v-for="item in categories" @click="btnClick(item)" >{{item.name}}}</button> </div> </template> <script src="../js/vue.js"></script> <script> const cpn ={ template:'#cpn', data(){ return { categories:[ {id:"aaa",name:"热门推荐"}, {id:"bbb",name:"手机数码"}, {id:"ccc",name:"家用家电"}, {id:"ddd",name:"电脑办公"}, ] } }, methods:{ btnClick(item){ // 传递事件 给父组件 传递参数 this.$emit('itemclick',item); } } } const app = new Vue({ el:"#app", data:{ }, methods:{ // 处理事件 cpnClick(item){ console.log(item) } }, components:{ cpn, } }) </script></pre>
-
案例
<div id="app"> <cpn :number1="num1" :number2="num2" @num1change="num1change" @num2change="num2change" /> </div><template id="cpn"> <div> <h2>props: {{number1}}</h2> <h2>data: {{dnumber1}}</h2> <!-- <input type="text" v-model="dnumber1"/> --> <input type="text" :value="dnumber1" @input="num1Input"/> <h2>props: {{number2}}</h2> <h2>data: {{dnumber2}}</h2> <!-- <input type="text" v-model="dnumber2"/> --> <input type="text" :value="dnumber2" @input="num2Input"/> </div> </template> <script src="../js/vue.js"></script> <script> const cpn = { template:'#cpn', props:{ number1:Number, number2:Number, }, data(){ return { dnumber1:this.number1, dnumber2:this.number2, } }, methods:{ num1Input(event){ this.dnumber1 = event.target.value; this.$emit("num1change",this.dnumber1); this.dnumber2=this.dnumber1*100; this.$emit("num2change",this.dnumber2); }, num2Input(event){ this.dnumber2 = event.target.value; this.$emit("num2change",this.dnumber2) this.dnumber1=this.dnumber2 /100; this.$emit("num1change",this.dnumber1); } }, } const app = new Vue({ el:"#app", data:{ num1:1, num2:0, }, methods:{ num1change(value){ this.num1=parseFloat(value) }, num2change(value){ this.num2=parseFloat(value) }, }, components:{ cpn, } }) </script></pre>
-
使用 watch实现
<div id="app"> <cpn :number1="num1" :number2="num2" @num1change="num1change" @num2change="num2change" /> </div><template id="cpn"> <div> <h2>props: {{number1}}</h2> <h2>data: {{dnumber1}}</h2> <input type="text" v-model="dnumber1"/> <h2>props: {{number2}}</h2> <h2>data: {{dnumber2}}</h2> <input type="text" v-model="dnumber2"/> </div> </template> <script src="../js/vue.js"></script> <script> const cpn = { template:'#cpn', props:{ number1:Number, number2:Number, }, data(){ return { dnumber1:this.number1, dnumber2:this.number2, } }, watch:{ dnumber1(newValue){ this.dnumber2 = newValue * 100; this.$emit("num1change",newValue); }, dnumber2(newValue){ this.dnumber1 = newValue / 100; this.$emit("num2change",newValue); } }, } const app = new Vue({ el:"#app", data:{ num1:1, num2:0, }, methods:{ num1change(value){ this.num1=parseFloat(value) }, num2change(value){ this.num2=parseFloat(value) }, }, components:{ cpn, } }) </script></pre>
$children和$refs及$parent和$root
-
$children和$refs 推荐$refs
<div id="app"> <cpn ref="aaa"></cpn> <cpn></cpn> <cpn></cpn> <cpn></cpn> <button @click="btnclick">按钮</button> </div><template id="cpn"> <div>我是子组件</div> </template> <script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ messages:"你好", }, methods:{ btnclick(){ // 不推荐 // console.log(this.$children) // this.$children[0].showMessage(); // for(let c of this.$children){ // console.log(c.name); // c.showMessage(); // } // 必须在组件上加上ref="aaa" console.log(this.$refs.aaa.name); } }, components:{ cpn:{ template:"#cpn", data(){ return { name : "我是子组件的name" } }, methods:{ showMessage(){ console.log("showMessage"); } } } } }) </script></pre>
-
$parent 不建议使用 和 $root 基本不用
<div id="app"> <cpn></cpn> </div><template id="cpn"> <div> 我是cpn组件 <ccpn></ccpn> </div> </template> <template id="ccpn"> <div> <div>我是子组件</div> <button @click="btnclick">按钮</button> </div> </template> <script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ messages:"你好", }, components:{ cpn:{ template:"#cpn", data(){ return{ name:"我是cpn组件的name" } }, components:{ ccpn:{ template:"#ccpn", methods:{ btnclick(){ console.log(this.$parent); console.log(this.$parent.name); console.log(this.$root); console.log(this.$root.messages); } }, } } } } }) </script></pre>
插槽的使用 slot
-
根据需求添加
-
使组件具有扩展性
-
抽取共性保留不同做
<slot></slot>
-
插值 单个 多个 及 默认值
<div id="app"> <cpn> <!-- 插值 --> <button>按钮</button> </cpn> <cpn> <span>哈哈</span> </cpn> <cpn> <i>呵呵</i> </cpn> <cpn> <!-- 插入多个 --> <button>按钮</button> <span>哈哈</span> <i>呵呵</i> </cpn> <cpn></cpn> <cpn></cpn> <cpn></cpn> </div><template id="cpn"> <div> <h2>我是组件</h2> <p>我是组件哈哈哈</p> <!-- 插槽使用 --> <slot> <!-- 默认值 --> <button>按钮</button> </slot> </div> </template> <script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ messages:"你好", }, components:{ cpn:{ template:"#cpn", } } }) </script></pre>
具名插槽使用
-
<template v-slot:center></template>
-
v-slot: 缩写 #
-
<template #:center></template>
<div id="app"> <cpn> <!-- 根据名字插 无名字的都被视为是default--> <span>标题</span> <!--或者--> <template v-slot:default> <span>标题</span> </template> <template v-slot:center> <span>标题</span> </template> </cpn><cpn> <template v-slot:left> <button>返回</button> </template> </cpn> </div> <template id="cpn"> <div> <slot name="left"><span>左边</span></slot> <slot name="center"><span>中间</span></slot> <slot name="right"><span>右边</span></slot> <slot><span>无名</span></slot> <slot><span>无名</span></slot> </div> </template> <script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ messages:"你好", }, components:{ cpn:{ template:"#cpn", } } }) </script></pre>
作用域插槽
-
user属于父级的变量 访问不到
<span> <slot>{{ user.lastName }}</slot> </span>
-
使用插槽
<span> <slot v-bind:user="user"> {{ user.lastName }} </slot> </span>
编译作用域
<div id="app"> <!-- isShow拿的Vue的isShow 因为app属于Vue的模板 --> <cpn v-show="isShow"></cpn> </div><template id="cpn"> <div> <h2>我是子组件</h2> <p>我是内容:哈哈哈</p> <!-- 这里的isShow 属于cpn的isShow 因为这是cpn的模板 --> <button v-show="isShow">按钮</button> </div> </template> <script src="../js/vue.js"></script> <script> const app = new Vue({ el:"#app", data:{ messages:"你好", isShow:true, }, components:{ cpn:{ template:"#cpn", data(){ return{ isShow:false } } } } }) </script></pre>
模块化开发
-
为社么要模块化
-
代码量复杂
-
多人开发 分工合作
-
解决全局变量命名冲突
-
匿名闭包函数(可以解决)
-
但代码不能复用了
-
-
闭包+使用导出对象()可以解决
-
引用规范的模块化
-
CommonJS
-
AMD
-
CMD
-
ES6
-
-
-
-
-
CommonJs
-
导出
module.exports = { flag, sum, }
-
导入
let {flag,sum} = require("./aaa.js");
-
模块化的导入导出
-
ES6
-
export和import
export { flag, }import {flag} from './aaa.js';
export let name = 'jack';
import {name} from './aaa.js';
export function mul(){
}
import {mul} from './aaa.js';
export class Person{
}
import {Person} from './aaa.js';
//default 导出时 import时可以自定义名字
export defalut address;import addr from './aaa.js';
//全部导入
import * as aaa from './aaa.js';
aaa.flag
Webpack
-
是一个javascript应用的静态
模块打包
工具 -
底层支撑
-
转化AMD,CMD,CommonJS,ES6
-
和grunt/gulp的对比
-
grunth/gulp的核心时Task
-
无模块化概念
安装
-
依赖node环境 依赖各种包
-
npm工具(包管理工具)node package manager
-
-
安装Node.js
-
安装webpack3.6.0 vue cli2
npm install webpack@3.6.0 -g
npm install webpack webpack-cli -g --save-dev
-
--save-dev局部安装
-
dist打包文件夹
-
src开发文件夹
-
main.js
-
// 依赖位置 const {add,mul} = require('../js/mathUtil.js');
console.log(add(20,30));
console.log(mul(20,30)); -
mathUtil.js
-
function add(num1,num2){ return num1 + num2; }
function mul(num1,num2){
return num1 * num2;
}module.exports = {
add,
mul,
} -
打包
-
main.js入口
webpack .\src\main.js /dist/bundle.js
webpack .\src\main.js -o /dist/bundle.js --mode development
-
配置
-
npm init
-
配置文件 webpack.config.js
const path = require('path');module.exports = {
entry:'./src/main.js',
output:{
path:path.resolve(__dirname,'dist'),
filename:'bundle.js'
}
}
-
webpack运行
-
配置 package.json
{ "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" }
-
执行npm run build
-
本地webpack
-
npm install webpack --save-dev
-
生成 package.json
-
{ "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": "^4.42.1" } }
loader
-
main.js
-
// 依赖位置 const {add,mul} = require('../js/mathUtil.js');
console.log(add(20,30));
console.log(mul(20,30));
// 依赖位置
require("../css/normal.css"); -
安装
npm install --save-dev css-loader
-
配置 webpack.config.js
const path = require('path');module.exports = {
entry:'./src/main.js',
output:{
path:path.resolve(__dirname,'dist'),
filename:'bundle.js'
},
module:{
rules:[
{
test:/.css$/,
use : ['css-loader' ]
}
]
}
}
-
安装
npm install --save-dev style-loader
-
配置webpack.config.js
-
use : ['style-loader','css-loader' ] 从右向左加载
const path = require('path');module.exports = {
entry:'./src/main.js',
output:{
path:path.resolve(__dirname,'dist'),
filename:'bundle.js'
},
module:{
rules:[
{
test:/.css$/,
use : ['style-loader','css-loader' ]
}
]
}
}
less/scss/stylus文件处理 预处理
-
main.js
-
// 依赖位置 const {add,mul} = require('../js/mathUtil.js');
console.log(add(20,30));
console.log(mul(20,30));
// 依赖位置
require("../css/normal.css");// 依赖位置
require("../css/special.less");// 依赖位置
require("../css/one.scss");document.writeln('<h2>您好啊,哈哈哈</h2>');
document.writeln('<p>您好啊,我是内容p</p>'); -
安装
-
npm install --save-dev less-loader less
-
npm install sass-loader node-sass webpack --save-dev
-
配置 webpack.config.js
-
const path = require('path');
module.exports = {
entry:'./src/main.js',
output:{
path:path.resolve(__dirname,'dist'),
filename:'bundle.js'
},
module:{
rules:[
{
test:/.css$/,
use : ['style-loader','css-loader' ]
},
{
test: /.less$/,
use: [
{
loader: 'style-loader', // creates style nodes from JS strings
},
{
loader: 'css-loader', // translates CSS into CommonJS
},
{
loader: 'less-loader', // compiles Less to CSS
},
],
},
{
test: /.s[ac]ss$/i,
use: [
// Createsstyle
nodes from JS strings
'style-loader',
// Translates CSS into CommonJS
'css-loader',
// Compiles Sass to CSS
'sass-loader',
],
},
]
}
}图片引入
-
安装
-
npm install url-loader --save-dev
-
配置
-
{ test: /\.(png|jpg|gif|jpeg)$/i, use: [ { loader: 'url-loader', options: { limit: 8192, }, }, ], }
-
图片转为base64
-
加载图片小于limit: 8192,时
-
大于报错 需要file-loader模块
-
安装
-
npm install file-loader --save-dev
-
解决图片未显示
-
但已经打包在dist文件下生成新图片 32位hash值
-
路径不一致
-
配置 publicPath:'dist/',
-
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$/,
use : ['style-loader','css-loader' ]
},
{
test: /.less$/,
use: [
{
loader: 'style-loader', // creates style nodes from JS strings
},
{
loader: 'css-loader', // translates CSS into CommonJS
},
{
loader: 'less-loader', // compiles Less to CSS
},
],
},
{
test: /.s[ac]ss$/i,
use: [
// Createsstyle
nodes from JS strings
'style-loader',
// Translates CSS into CommonJS
'css-loader',
// Compiles Sass to CSS
'sass-loader',
],
},
{
test: /.(png|jpg|gif|jpeg)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 8192,
},
},
],
}
]
}
}
-
-
-
配置图片文件及文件名
-
img/name.hash:8.ext形式
-
8位hash ext后缀名变量
-
配置 webpack.config.js
-
name:'img/[name].[hash:8].[ext]'
-
const path = require('path');
module.exports = {
entry:'./src/main.js',
output:{
// 需要绝对路径
path:path.resolve(__dirname,'dist'),
filename:'bundle.js',
// url对应路径
publicPath:'dist/',
},
module:{
rules:[
{
test:/.css$/,
use : ['style-loader','css-loader' ]
},
{
test: /.less$/,
use: [
{
loader: 'style-loader', // creates style nodes from JS strings
},
{
loader: 'css-loader', // translates CSS into CommonJS
},
{
loader: 'less-loader', // compiles Less to CSS
},
],
},
{
test: /.s[ac]ss$/i,
use: [
// Createsstyle
nodes from JS strings
'style-loader',
// Translates CSS into CommonJS
'css-loader',
// Compiles Sass to CSS
'sass-loader',
],
},
{
test: /.(png|jpg|gif|jpeg)$/i,
use: [
{
loader: 'url-loader',
options: {
// 配置图片处理情况
limit: 8192,
name:'img/[name].[hash:8].[ext]',
},
},
],
}
]
}
}
ES6语法转ES5babel
-
安装
npm install -D babel-loader @babel/core @babel/preset-env
npm install --save-dev babel-loader @babel/core @babel/preset-es2015
npm install --save-dev babel-loader babel-core babel-preset-es2015
-
配置 webpack.config.js
-
{ test: /\.m?js$/, exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'] } } }
webpack配置Vue
-
安装依赖 不加dev dev:表示开发时依赖 不加表示运行时也需要使用该依赖
-
npm install vue --save
-
main.js
-
// 依赖位置 const {add,mul} = require('../js/mathUtil.js');
console.log(add(20,30));
console.log(mul(20,30));
// 依赖位置
require("../css/normal.css");// 依赖位置
require("../css/special.less");// 依赖位置
require("../css/one.scss");document.writeln('<h2>您好啊,哈哈哈</h2>');
document.writeln('<p>您好啊,我是内容p</p>');//使用Vue
import Vue from 'vue';
const app = new Vue({
el:'#app',
data:{
message:'你好啊',
},
}) -
index.html
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body>
<div id="app"> <h2>{{message}}</h2> </div> <script src="./dist/bundle.js"></script>
</body>
</html> -
打包
-
页面会报错
-
使用
-
runtime-only : 代码中 不可以有任何的template
-
runtime-compller: 代码中,可以有template,因为有compller可以用于编译template
-
-
配置 webpack.config.js
-
resolve:{ alias:{ // 指定匹配的文件 "vue$":'vue/dist/vue.esm.js' }, },
-
重新打包
template和el的关系
-
template会替换el的位置
-
即
-
template:` <div> <h2>{{message}}</h2> <button @click="btnclick">按钮/button> <h2>{{name}}</h2> </div> `,
-
替换
-
<div id="app"> </div>
案例
-
分离出App.vue
<template> <div> <h2 class="title">{{message}}</h2> <button @click="btnclick">按钮</button> <h2>{{name}}</h2> </div> </template><script>
export default {
name: "App",
data(){
return {
message:'你好啊',
name:'jack'
}
},
methods:{
btnClick(){} } }
</script>
<style scoped>
.title {
color: blue;
}
</style>
-
main.js
// 依赖位置 const {add,mul} = require('../js/mathUtil.js');console.log(add(20,30));
console.log(mul(20,30));
// 依赖位置
require("../css/normal.css");// 依赖位置
require("../css/special.less");// 依赖位置
require("../css/one.scss");document.writeln('<h2>您好啊,哈哈哈</h2>');
document.writeln('<p>您好啊,我是内容p</p>');//使用Vue
import Vue from 'vue';
// import App from './vue/app.js';
import App from "./vue/App.vue";const app = new Vue({
el:'#app',
template:'<App/>',
components:{
App,
}
})
-
运行报错
-
解决 配置对应的loader
-
npm install vue-loader vue-template-compiler --save-dev
-
配置 webpack.config.js
{ test:/\.vue$/, use:["vue-loader"] }
-
运行缺少文件
-
降级版本
-
"vue-loader": "^13.0.0",
-
npm install
-
运行
-
-
或者配置 webpack.config.js
-
plugins: [ // make sure to include the plugin for the magic new VueLoaderPlugin() ],
Plugin
-
添加版权
-
const webpack = require('webpack')
plugins:[ new webpack.BannerPlugin('最终版权归nick所有') ]
打包index.html到dist下
npm install html-webpack-plugin --save-dev
const HtmlWebpackPlugin = require('html-webpack-plugin')new HtmlWebpackPlugin()
-
添加app模板
-
修改src下对的index.html作为模板
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body>
<div id="app"> </div>
</body>
</html> -
修改配置
-
new HtmlWebpackPlugin({ template:'index.html' }),
-
解决路径问题
-
// publicPath:'dist/', 注释
js压缩(丑化)
npm install uglifyjs-webpack-plugin --save-dev npm install uglifyjs-webpack-plugin@1.1.1 --save-dev
-
配置
-
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin');
new UglifyjsWebpackPlugin()
-
webpack-dev-server搭建本地服务器
npm install --save-dev webpack-dev-server
-
内部使用express框架
-
生成不在本地文件里
-
只是给你测试用 放在内存(相当于缓存)
-
最后执行一次 npm run build
-
-
配置
-
devServer:{ contentBase:'./dist', //实时监听 inline:true, post:8089, }
-
运行
-
"dev": "webpack-dev-server --open"
-
npm run dev
配置分离
-
build/base.config.js
-
const path = require('path'); const VueLoaderPlugin = require('vue-loader/lib/plugin.js'); const webpack = require('webpack'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin'); module.exports = { entry:'./src/main.js', output:{ // 需要绝对路径 path:path.resolve(__dirname,'../dist'), filename:'bundle.js', // url对应路径 // publicPath:'dist/', }, plugins: [ // make sure to include the plugin for the magic new VueLoaderPlugin(), new webpack.BannerPlugin('最终版权归nick所有'), new HtmlWebpackPlugin({ template:'index.html' }), ], module:{ rules:[ { test:/\.css$/, use : ['style-loader','css-loader' ] }, { test: /\.less$/, use: [ { loader: 'style-loader', // creates style nodes from JS strings }, { loader: 'css-loader', // translates CSS into CommonJS }, { loader: 'less-loader', // compiles Less to CSS }, ], }, { test: /\.s[ac]ss$/i, use: [ // Creates `style` nodes from JS strings 'style-loader', // Translates CSS into CommonJS 'css-loader', // Compiles Sass to CSS 'sass-loader', ], }, { test: /\.(png|jpg|gif|jpeg)$/i, use: [ { loader: 'url-loader', options: { // 配置图片处理情况 limit: 8192, name:'img/[name].[hash:8].[ext]', }, }, ], }, { test: /\.m?js$/, exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'] } } }, { test: /\.vue$/, loader: 'vue-loader' } ] }, resolve:{ alias:{ // 指定匹配的文件 "vue$":'vue/dist/vue.esm.js' }, }, }
-
prod.config.js
-
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin'); const WebpackMerge = require("Webpack-merge"); const baseConfig = require("./base.config.js");
module.exports = WebpackMerge(baseConfig,{
plugins: [
new UglifyjsWebpackPlugin(),
],
}); -
dev.config.js
-
const WebpackMerge = require("Webpack-merge"); const baseConfig = require("./base.config.js");
module.exports = WebpackMerge(baseConfig,{
devServer:{
contentBase:'./dist',
inline:true,
port:8089,
},
}-
安装 合并插件
-
npm install webpack-merge --save-dev
-
-
配置
-
"build": "webpack --config ./build/prod.config.js --mode development", "dev": "webpack-dev-server --config ./build/dev.config.js --open"
脚手架
-
Vue CLI
-
解决繁琐的webpack
-
依赖node环境
-
使用webpack模板
安装
npm install -g @vue/clinpm install -g @vue/cli
-
拉取旧模板
-
npm install -g @vue/cli-init
-
创建项目
-
//2 vue init webpack my-project
//3
vue create my-project
-
project name
-
projecct description
-
author
-
//一般选择这项 Runtime + Compiler: recommended for most users
//后者小 效率高 推荐
> Runtime-only: about 6KB lighter min+gzip, but templates (or any Vue-specific HTML) are ONLY allowed in .vue files - render functions are required elsewhere -
vue-router
-
Use ESLint to lint your code?// ESLint js代码限制(规范)
-
//规范选择
Standard (https://github.com/standard/standard) //标准规范 选择
Airbnb (https://github.com/airbnb/javascript) //
none (configure it yourself) -
Set up unit tests (Y/n) 单元测试 一般不用
-
Setup e2e tests with Nightwatch? (Y/n) end to end (端到端测试) 依赖Nightwatch 结合selenlum 进行自动化测试 (自动测试操作) 一般给测试
-
? Should we run
npm install
for you after the project has been created? (recommended) (Use arrow keys)//管理项目使用什么 -
创建
node支撑环境
-
node提供一个服务器 是的js代码能在本地服务器上直接运行,而不用跑在浏览器上
-
node的V8引擎
-
chrome的V8引擎
-
使得js从原始的js-->字节码-->浏览器
-
变为 js --> 二进制码-->浏览器 效率更高
-
文件解析
-
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
re 即remove 清空原来的dist里的文件 在进行打包
-
相关配置文件夹
-
build
-
config
-
-
一些规范
-
.editorconfig
-
-
忽略js的限制
-
.eslintignore
-
-
css的转化0配置
-
.postcssrc.js
-
-
模板
-
index.html
-
关掉esLint
-
config/index.js
-
useEslint: false,
runtime+compiler和runtimeonly的区别
-
区别只在main.js
-
runtime+compiler App组件先注册
-
在使用App
-
步骤
-
template -> ast(抽象语法树) -> render -> virtual dom(虚拟DOM) -> 真实DOM(UI)
-
使用v1 代使用量多
-
// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' import App from './App'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
components: { App },
template: '<App/>'
})
-
runtimeonly 没有注册
-
使用render 使用箭头函数
-
参数h 是createElement
-
render: function(createElement){
return createElement('h2',{class:'box'},['hello world'])
}
生成
<div class="box">hello world</div>
替换
<div id="app"></div>
render: function(createElement){
return createElement('h2',{class:'box'},['hello world',createElement('button',['按钮']])
}
生成
<div class="box">
hello world
<button>按钮</button>
</div>
//可以传入组件
createElement(Cpn);
import Vue from 'vue'
import App from './App'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
render: h => h(App)
})
-
步骤 性能更高
-
render -> virtual dom(虚拟DOM) -> 真实DOM(UI)
-
使用v2 代码使用量少 少6kb就是这么来的
-
那么.vue的template是怎么处理的呢 怎么变为render函数
-
vue-loader用于加载.vue文件
-
vue-template-compler
用于解析.vue文件里的template-->render函数 开发时依赖 -
所以运行时不需要runtime+compiler 因为开发时已经解析过了
vue-cli 3 与 2版本的区别
-
3 是基于webpack 4 打造的, 2 是webpack3
-
3 的设计原则是
0 配置
移除的配置文件根目录下的, build和config等目录 -
3 提供vue ui命令 提供可视化配置, 更加人性化
-
移除 static文件夹 新增public文件夹,并且index.html移动到public中
vue create vuetestcli3
-
preset配置
-
default 默认
-
Manually 手动
-
-
空格选择取消
-
Babel Es6 -> Es5
-
TypeScript
-
Progressive Web App (PWA) Support 更新的App
-
Router
-
Vuex
-
CSS Pre-Processors
-
Linter /Formatter
-
Unit Testing
-
E2E Testing
-
-
配置文件存放
-
in dedicated 单独配置
-
in package.json
-
-
是否保存为自定义的模板
-