Vue学习记录
本地引入vue.js文件
<script src="./vue.js" type="text/javascript"></script>
数据绑定的几种方式
Html:
数据绑定①
<div id="demo">{{msg}}</div> |
数据绑定②
<div id="demo" v-html="msg"></div> |
数据绑定③
<div id="demo" v-text="msg"></div> |
js
var demo=new Vue({ el:'#demo', data:{ msg:'hello world!' }, methods:{ demoClick:function(){ alert('谢谢你的点击'); } } }) |
Vue事件绑定
html
<div id="demo" v-on:click="demoClick">{{msg}}</div> |
js
var demo=new Vue({ el:'#demo', data:{ msg:'hello world!' }, methods:{ demoClick:function(){ this.msg="hello~~"; } } }) |
属性绑定和双向数据绑定
属性绑定
<div id="root"> <div v-bind:title="title">hello world</div> </div> |
双向数据绑定(v-model只能用在表单元素中)
<div id="root"> <input type="text" v-model="content"/> <div>{{content}}</div> </div> |
js部分
<script> new Vue({ el:"#root", data:{ title:'this is the vue title', content:'文本框的内容' } }) </script> |
计算属性与侦听器
html
<div id="root"> 名:<input type="text" v-model="firstName"/> 姓:<input type="text" v-model="lastName"/> <div>{{firstName}}{{lastName}}</div> <div>{{fullName}}</div> <div>{{count}}</div> </div> |
js
new Vue({ el:'#root', data:{ firstName:'', lastName:'', count:0 }, computed:{ //计算属性 fullName:function(){ return this.firstName+this.lastName; } }, watch:{ //侦听 firstName:function(){ this.count++; }, lastName:function(){ this.count++; } } }); |
条件渲染
html
<div id="root"> <!-- 当点击按钮时候,v-if元素直接从dom树消失,v-show只是将style属性修改成display:none;再次点击按钮的时候,都可以重新恢复;<template> 元素当做包装元素,并在上面使用 v-if,最终的渲染结果不会包含它--> <div v-if="show">hello world</div> <div v-show="show">hello world</div> <template v-if="show"> hello world~ </template> <button v-on:click="handleClick">显示或者隐藏</button> </div> |
js
new Vue({ el:'#root', data:{ show:true, }, methods:{ handleClick:function(){ this.show=!this.show; } } }); |
列表渲染
html
<ul> <!--三种渲染方法--> <li v-for="item of list">{{item}}</li> <li v-for="item of list" :key="item">{{item}}</li> <li v-for="(item,index) of list" :key="index">{{item}}</li> </ul> |
js
new Vue({ el:'#root', data:{ list:[1,2,3] }, methods:{ handleClick:function(){ this.show=!this.show; } } }); |
v-cloak指令 解决刷新或者加载出现闪烁
<head> <meta name="viewport" content="width=device-width" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Vue</title> <style> [v-cloak]{ display: none; } </style> </head> <body> <div id="message"> <div v-cloak> {{msg}} </div> </div> </body> <script src="./js/vue.js" type="text/javascript" ></script> <script> var vue=new Vue({ el:"#message", data:{ msg:'这是一条新消息' } }); </script> |
v-text指令
<body> <div id="message"> <!-- v-text不存在闪烁问题 v-text会覆盖元素中原来的内容,而插值表达式只会替换自己的这个占位符,不会把整个元素内的内容清空 v-html类似v-text --> <div v-text="msg"> ++++++++++++++ </div> </div> </body> <script src="./js/vue.js" type="text/javascript" ></script> <script> var vue=new Vue({ el:"#message", data:{ msg:'这是一条新消息' } }); </script> |
v-bind指令 缩写:
<body> <div id="container"> <!--无效--> <button title="{{msg}}">按钮1</button> <!--有效--> <button v-bind:title="msg">按钮2</button> <!--有效--> <button :title="msg">按钮3</button> <!--有效--> <button :title="msg+'字符串'">按钮4</button> </div> </body> <script src="./js/vue.js" type="text/javascript" ></script> <script> var vue=new Vue({ el:"#container", data:{ msg:'按钮标题' } }); </script> |
v-on 缩写@
<div id="container"> <button v-on:click="alertFn">按钮</button> </div> </body> <script src="./js/vue.js" type="text/javascript" ></script> <script> var vue=new Vue({ el:"#container", data:{ msg:'按钮标题' }, methods:{ alertFn:function(){ alert('你点击了按钮'); } } }); </script> |
跑马灯制作
<div id="container"> <button @click="lang">浪起来</button> <button @click="stop">稳住</button> <div>{{msg}}</div> </div> </body> <script src="./js/vue.js" type="text/javascript" ></script> <script> var vue=new Vue({ el:"#container", data:{ msg:'猥琐发育,别浪~', intervalId:null }, methods:{ lang:function(){ /* var _this=this; setInterval(function(){ var msg=_this.msg; var str=msg.substring(0,1); //截取字符串 var otherStr=msg.substring(1); //剩余字符串 _this.msg=otherStr+str; },300);*/ //使用箭头函数 if(this.intervalId!=null) return; this.intervalId=setInterval(()=>{ var msg=this.msg; var str=msg.substring(0,1); //截取第一个字符串 var otherStr=msg.substring(1); //剩余字符串 this.msg=otherStr+str; },300); }, stop:function(){ clearInterval(this.intervalId); this.intervalId=null; } } }); </script> |
事件修饰符
<!--默认点击 冒泡--> <!-- <div @click="divClick" id="container"> <button @click="btnClick"> 按钮 </button> </div>--> <!--阻止事件冒泡stop--> <!-- <div @click="divClick" id="container"> <button @click.stop="btnClick"> 按钮 </button> </div>--> <!--阻止元素默认行为prevent 点击后a标签不跳转--> <!--<div id="container"> <a href="http://www.baidu.com" @click.prevent="linkClick">百度一下,你就知道</a> </div>--> <!--捕获事件capture 先触发div点击事件divClick--> <!--<div @click.capture="divClick" id="container"> <button @click="btnClick"> 按钮 </button> </div>--> <!--self 只有点击当前元素,才会触发事件--> <!--<div @click.self="divClick" id="container"> <button @click="btnClick"> 按钮 </button> </div>--> <!--使用once只触发一次事件--> <div id="container"> <a href="http://www.baidu.com" @click.prevent.once="linkClick">百度一下,你就知道</a> </div> </body> <script src="./js/vue.js" type="text/javascript" ></script> <script> var vue=new Vue({ el:"#container", data:{ }, methods:{ divClick:function(){ console.log('div点击事件'); }, btnClick:function(){ console.log('按钮点击事件'); }, linkClick:function(){ console.log('百度个毛线'); } } }); </script> |
简易计算器
<div id="container"> <input type="text" v-model="n1"/> <select v-model="opt"> <option>+</option> <option>-</option> <option>*</option> <option>/</option> </select> <input type="text" v-model="n2"/> <button @click="caculate">=</button> <span>{{result}}</span> </div> </body> <script src="./js/vue.js" type="text/javascript" ></script> <script> var vue=new Vue({ el:"#container", data:{ n1:0, opt:'+', n2:0, result:0 }, methods:{ caculate:function(){ switch (this.opt){ case '+': this.result=(parseFloat(this.n1)+parseFloat(this.n2)).toFixed(2); break; case '-': this.result=(parseFloat(this.n1)-parseFloat(this.n2)).toFixed(2); break; case '*': this.result=(parseFloat(this.n1)*parseFloat(this.n2)).toFixed(2); break; case '/': this.result=(parseFloat(this.n1)/parseFloat(this.n2)).toFixed(2); break; } } } }); </script> |
简易计算器2
<div id="container"> <input type="text" v-model="n1"/> <select v-model="opt"> <option>+</option> <option>-</option> <option>*</option> <option>/</option> </select> <input type="text" v-model="n2"/> <button @click="caculate">=</button> <span>{{result}}</span> </div> </body> <script src="./js/vue.js" type="text/javascript" ></script> <script> var vue=new Vue({ el:"#container", data:{ n1:0, opt:'+', n2:0, result:0 }, methods:{ caculate:function(){ var code=(parseFloat(this.n1)+this.opt+parseFloat(this.n2)); this.result=eval(code).toFixed(2); } } }); </script> |
Vue中属性绑定设置class类样式
<body> <div id="container"> <span :class="style1">数组形式</span> <!--渲染后 <span class="italic bold">数组形式</span> --> <span :class="['red','bold',flag?'active':'']">三元表达式</span> <!--渲染后 <span class="red bold active">三元表达式</span> --> <!--注意flag不用引号--> <span :class="flag?'active':''">三元表达式</span> <!--渲染后 <span class="active">三元表达式</span> --> <!--注意flag不用引号--> <span :class="['red','bold',{'active':flag}]">三元表达式</span> <!--渲染后 <span class="red bold active">三元表达式</span> --> <!--对象key可以加引号可以不加引号--> <span :class="{'red':true,bold:false,active:true}">对象</span> <!--渲染后 <span class="red active">对象</span> --> <span :class="classObj">对象</span> <!--效果同上--> </div> </body> <script src="./js/vue.js" type="text/javascript" ></script> <script> new Vue({ el:'#container', data:{ style1:['italic','bold'], style2:['red','bold'], flag:true, classObj:{red:true,bold:false,active:true} }, methods:{ } }) </script> |
Vue中属性绑定设置class类样式
<body> <div id="container"> <!--font-weight不加引号 报错 - invalid expression: Unexpected token - in {color:'red',font-weight:'bold'}--> <!--<span :style="{color:'red',font-weight:'bold'}">Vue通过属性为元素绑定style行内样式</span>--> <span :style="{color:'red','font-weight':'bold'}">Vue通过属性为元素绑定style行内样式</span> <!--渲染后 <span style="color: red; font-weight: bold;">Vue通过属性为元素绑定style行内样式</span> --> <span :style="styleObj1">Vue通过属性为元素绑定style行内样式</span> <!--渲染后 <span style="color: red; font-weight: bold;">Vue通过属性为元素绑定style行内样式</span> --> <span :style="[styleObj1,styleObj2]">Vue通过属性为元素绑定style行内样式</span> <!--渲染后 <span style="color: red; font-weight: bold; font-size: 16px;">Vue通过属性为元素绑定style行内样式</span> --> </div> </body> <script src="./js/vue.js" type="text/javascript" ></script> <script> new Vue({ el:'#container', data:{ styleObj1:{color:'red','font-weight':'bold'}, styleObj2:{'font-size':'16px','font-weight':'bold'} }, methods:{ } }) </script> |
v-for指令
<body> <div id="container"> <ul> <!--普通数组--> <li v-for="item in items">{{item}}</li> <!--渲染后 <li>小明</li><li>小红</li><li>小狗</li> --> <li v-for="(item,index) in items">{{item}}{{index}}</li> <!--渲染后 <li>小明0</li><li>小红1</li><li>小狗2</li> --> <!--对象数组--> <li v-for="(item,index) in students">编号:{{index+1}}姓名:{{item.name}}性别:{{item.gender}}</li> <!--渲染后 <li>编号:1姓名:小明性别:男</li><li>编号:2姓名:小红性别:男</li><li>编号:3姓名:小狗性别:公</li> --> <!--对象--> <li v-for="(item,key) in someOne">键:{{key}} 值:{{item}}</li> <!--渲染后 <li>键:name 值:小明</li> <li>键:gender 值:男</li> --> <!--对象--> <li v-for="(item,key,index) in someOne">索引:{{index}} 键:{{key}} 值:{{item}} </li> <!--渲染后 <li>索引:0 键:name 值:小明 </li> <li>索引:1 键:gender 值:男 </li> --> <!--对象--> <li v-for="item in someOne"> 值:{{item}}</li> <!--渲染后 <li>值:小明</li> <li>值:男</li> --> <!--数字--> <li v-for="count in 3"> 第{{count}}个</li> <!--渲染后 <li> 第1个</li> <li> 第2个</li> <li> 第3个</li> --> </ul> </div> </body> <script src="./js/vue.js" type="text/javascript" ></script> <script> new Vue({ el:'#container', data:{ items:['小明','小红','小狗'], students:[ {name:'小明',gender:'男'}, {name:'小红',gender:'男'}, {name:'小狗',gender:'公'} ], someOne:{ name:'小明', gender:'男' } }, methods:{ } }) </script> |
v-if和v-show指令
<body> <div id="ulContainer" @click="flagFn" style="height: 200px;border:1px solid black;"> <!-- 点击后渲染 <div id="ulContainer" style="height: 200px; border: 1px solid black;"><!––> <span style="display: none;">v-show显示</span></div> v-show是切换元素的display样式 v-if是重新删除或者创建元素 --> <span v-if="flag">v-if显示</span> <span v-show="flag">v-show显示</span> </div> </body> <script src="./js/vue.js" type="text/javascript" ></script> <script> new Vue({ el:'#ulContainer', data:{ flag:true }, methods:{ flagFn(){ this.flag=!this.flag; } } }); </script> |
效果同上
<div id="ulContainer" @click="flag=!flag" style="height: 200px;border:1px solid black;"> <!-- 点击后渲染 <div id="ulContainer" style="height: 200px; border: 1px solid black;"><!––> <span style="display: none;">v-show显示</span></div> v-show是切换元素的display样式 v-if是重新删除或者创建元素 --> <span v-if="flag">v-if显示</span> <span v-show="flag">v-show显示</span> </div> </body> <script src="./js/vue.js" type="text/javascript" ></script> <script> new Vue({ el:'#ulContainer', data:{ flag:true }, methods:{ } }); </script> |
品牌的添加和删除
<head> <title>品牌的添加,删除</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> </head> <body> <div id="ulContainer"> <div> <label>品牌id<input type="text" v-model="id"></label> <label>品牌名字<input type="text" v-model="name"></label> <button @click="addBrands">添加</button> </div> <table> <tr> <th>品牌ID</th> <th>品牌名字</th> </tr> <tr v-for="item in brands" :key="item.id"> <td v-text="item.id"></td> <td v-text="item.name"></td> <td><a href="" @click.prevent="del(item.id)">删除</a></td> </tr> </table> </div> </body> <script src="./js/vue.js" type="text/javascript"></script> <script> new Vue({ el: '#ulContainer', data: { id: '', name: '', keywords: '', brands: [ {id: 1, name: '宝马'}, {id: 2, name: '奔驰'} ] }, methods: { //添加品牌 addBrands(){ var brand = {id: this.id, name: this.name}; this.brands.push(brand); this.id = ''; this.name = ''; }, //删除品牌 del(id){ //删除方法一 //some()是对数组中每一项运行给定函数,如果该函数对任一项返回true,则返回true。 /* this.brands.some((item,i)=>{ if(item.id==id){ this.brands.splice(i,1); return true; } })*/ //删除方法二 var delIndex = this.brands.findIndex(item => { if(item.id == id) return true; }) ; this.brands.splice(delIndex, 1); } } }); </script> |
品牌的搜索功能
<head> <title>品牌的添加,删除和搜索</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> </head> <body> <div id="ulContainer"> <div> <label>品牌id<input type="text" v-model="id"></label> <label>品牌名字<input type="text" v-model="name"></label> <button @click="addBrands">添加</button> <label>搜索<input type="text" v-model="keywords"></label> </div> <table> <tr> <th>品牌ID</th> <th>品牌名字</th> </tr> <tr v-for="item in search()" :key="item.id"> <td v-text="item.id"></td> <td v-text="item.name"></td> <td><a href="" @click.prevent="del(item.id)">删除</a></td> </tr> </table> </div> </body> <script src="./js/vue.js" type="text/javascript"></script> <script> new Vue({ el: '#ulContainer', data: { id: '', name: '', keywords: '', brands: [ {id: 1, name: '宝马'}, {id: 2, name: '奔驰'} ] }, methods: { //添加品牌 addBrands(){ var brand = {id: this.id, name: this.name}; this.brands.push(brand); this.id = ''; this.name = ''; }, //删除品牌 del(id){ //删除方法一 //some()是对数组中每一项运行给定函数,如果该函数对任一项返回true,则返回true。 /* this.brands.some((item,i)=>{ if(item.id==id){ this.brands.splice(i,1); return true; } })*/ //删除方法二 var delIndex = this.brands.findIndex(item => { if(item.id == id) return true; }) ; this.brands.splice(delIndex, 1); }, //搜索过滤 search(){ /* 搜索方法一 var newBrands=[]; this.brands.forEach( item=>{ if(item.name.indexOf(this.keywords)!=-1){ newBrands.push(item); } }) return newBrands;*/ //搜索方法二 var newBrands = this.brands.filter(item => { if(item.name.includes(this.keywords)) { //es6方法 return true; } }) return newBrands; } } }); </script> |
vue全局过滤器
<body> <div id="ulContainer"> <div> {{msg|msgFormat1}} {{msg|msgFormat2('苦逼')}} <!--过滤器传参--> </div> </div> </body> <script src="./js/vue.js" type="text/javascript"></script> <script> //所谓全局过滤器,所有的vue示例都可以共享 /*Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化。过滤器可以用在两个地方:双花括号插值和 v-bind 表达式 (后者从 2.1.0+ 开始支持)。*/ Vue.filter('msgFormat1',function(msg){ return msg.replace(/操蛋/g,'小菜一碟'); }); Vue.filter('msgFormat2',function(msg,arg){ return msg.replace(/操蛋/g,arg); }); new Vue({ el: '#ulContainer', data: { msg:'一个phper来学Vue,是不是有点操蛋~~' }, methods: { } }); </script> |
Vue自定义私有过滤器
<body> <div id="ulContainer"> <div> {{msg|msgFormat1}} </div> </div> </body> <script src="./js/vue.js" type="text/javascript"></script> <script> /*Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化。过滤器可以用在两个地方:双花括号插值和 v-bind 表达式 (后者从 2.1.0+ 开始支持)。*/ Vue.filter('msgFormat1',function(msg){ return msg.replace(/操蛋/g,'小菜一碟'); //私有自定义过滤器优先级比全局过滤器的优先级比较高 }); new Vue({ el: '#ulContainer', data: { msg:'一个phper来学Vue,是不是有点操蛋~~' }, methods: { }, filters:{ msgFormat1:function(msg){ return msg.replace(/操蛋/g,'苦逼'); } } }); </script> |
Vue自定义按键修饰符
<body> <div id="ulContainer"> <div> <label>品牌id<input type="text" v-model="id"></label> <!--回车按enter键触发addBrands--> <!-- 全部的按键别名: .enter .tab .delete (捕获“删除”和“退格”键) .esc .space .up .down .left .right--> <!--<label>品牌名字<input type="text" v-model="name" @keyup.enter="addBrands"></label>--> <!-- 按键别名不太全 可以采用 键盘按钮KeyCodehttps://blog.csdn.net/tanga842428/article/details/77374713来控制按钮 <label>品牌名字<input type="text" v-model="name" @keyup.13="addBrands"></label> --> <!--自定义按键别名--> <label>品牌名字<input type="text" v-model="name" @keyup.f2="addBrands"></label> <button @click="addBrands">添加</button> </div> <table> <tr> <th>品牌ID</th> <th>品牌名字</th> </tr> <tr v-for="item in brands" :key="item.id"> <td v-text="item.id"></td> <td v-text="item.name"></td> </tr> </table> </div> </body> <script src="./js/vue.js" type="text/javascript"></script> <script> Vue.config.keyCodes.f2=113; new Vue({ el: '#ulContainer', data: { id: '', name: '', keywords: '', brands: [ {id: 1, name: '宝马'}, {id: 2, name: '奔驰'} ] }, methods: { //添加品牌 addBrands(){ var brand = {id: this.id, name: this.name}; this.brands.push(brand); this.id = ''; this.name = ''; } } }); </script> |
Vue自定义指令
<body> <div id="ulContainer"> <input type="text" v-focus/> </div> </body> <script src="./js/vue.js" type="text/javascript"></script> <script> //Vue.directive定义全局指令 v-focus //参数一代表指令的名称,参数二是一个对象,可以在特定阶段执行某些操作 Vue.directive('focus',{ bind:function(el){ //每当指令绑定到某个元素的时候,会立即执行bind函数,只执行一次 el为一个原生的js对象 el.focus(); //此时el还未插入dom元素中,所以调用dom操作无效 el.style.color='red'; //样式相关的可以直接在 }, inserted:function(el){ //被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。 el.focus(); }, updated:function(el){ //所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。 } }); new Vue({ el: '#ulContainer', data: { }, methods: { } }); </script> |
Vue自定义全局指令传递参数
<body> <div id="ulContainer"> <input type="text" v-color="'red'"/> </div> </body> <script src="./js/vue.js" type="text/javascript"></script> <script> Vue.directive('color',{ bind:function(el,binding){ console.log(JSON.stringify(binding)); //{"name":"color","rawName":"v-color","value":"red","expression":"'red'","modifiers":{},"def":{}} el.style.color=binding.value; }, inserted:function(el){ }, updated:function(el){ } }); new Vue({ el: '#ulContainer', data: { }, methods: { } }); </script> |
Vue自定义私有指令传递参数
<body> <div id="ulContainer"> <input type="text" v-color="'pink'"/> </div> </body> <script src="./js/vue.js" type="text/javascript"></script> <script> new Vue({ el: '#ulContainer', data: { }, methods: { }, directives:{ color:{ bind:function(el,binding){ el.style.color=binding.value; } } } }); </script> |
Vue-resource ajax请求
<body> <div id="ulContainer"> <button @click="getData">ajax获取数据</button> </div> </body> <script src="./js/vue.js" type="text/javascript"></script> <script src="./js/vue-resource.min.js" type="text/javascript"></script> <script> new Vue({ el: '#ulContainer', data: { }, methods: { getData:function(){ this.$http.get('http://ybtestshop.gouwanmei.wang/home/find/categoryList').then(response=>{ console.log(response); console.log(response.body); //服务器端的返回的json数据 }) } } }); </script> |
vue-resource参考地址:https://github.com/pagekit/vue-resource
使用过渡类名实现动画
<head> <title>使用过渡类名实现动画</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <style> .fade-enter-active,.fade-leave-active{ transition: all 3s ease; transform: translateX(150px); } .fade-enter,.fade-leave-to{ opacity:0; } </style> </head> <body> <div id="ulContainer"> <button @click="flag=!flag">按钮</button> <transition name="fade"> <div v-if="flag">过渡内容</div> </transition> </div> </body> <script src="./js/vue.js" type="text/javascript"></script> <script> new Vue({ el: '#ulContainer', data: { flag:true }, methods: { } }); </script> |
使用animate.css实现动画
<head> <title>使用animate.css实现动画</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <link href="./css/animate.css" type="text/css" rel="stylesheet"/> </head> <body> <div id="ulContainer"> <button @click="flag=!flag">按钮</button> <transition enter-active-class="animated bounceIn" leave-active-class="animated bounceOut" :duration="{enter:550,leave:900}" > <div v-if="flag">过渡内容</div> </transition> </div> </body> <script src="./js/vue.js" type="text/javascript"></script> <script> new Vue({ el: '#ulContainer', data: { flag:true }, methods: { } }); </script> |
使用钩子函数实现动画
<body> <div id="ulContainer"> <button @click="flag=!flag">快进车里来</button> <transition v-on:before-enter="beforeEnter" v-on:enter="enter" v-on:after-enter="afterEnter" > <div v-if="flag" style="background-color:pink;border-radius:50%;width:50px;height:50px;"></div> </transition> </div> </body> <script src="./js/vue.js" type="text/javascript"></script> <script> new Vue({ el: '#ulContainer', data: { flag:false }, methods: { beforeEnter(el){ el.style.transform="translate(0,0)"; }, enter(el,done){ el.offsetWidth; // el.style.transform="translate(300px,300px)"; el.style.transition="all 5s ease"; done(); //立刻消失需要用 done()是afterEnter的引用 }, afterEnter(el){ this.flag=false; } } }); </script> |
Vue全局自定义组件
<body> <div id="Container"> <!--组件如果使用驼峰注册,在引用组件时候必须用-分隔--> <custom-com></custom-com> </div> </body> <script src="./js/vue.js" type="text/javascript"></script> <script> /*创建组件方式① var com=Vue.extend({ template:'<div>有心者,才有所累;无心者,多无所谓</div>' }); Vue.component('customCom',com); */ /*创建组件方式① Vue.component('customCom',Vue.extend({ template:'<div>有心者,才有所累;无心者,多无所谓</div>' })); */ /*创建组件方式② Vue.component('customCom',{ template:'<div>有心者,才有所累;无心者,多无所谓</div>' });*/ //注意:组件的模板必须包含在一个根元素中 new Vue({ el: '#Container', data: { }, methods: { } }); </script> |
<body> <div id="Container"> <custom-com></custom-com> </div> <template id="temp"> <div>有心者,才有所累;无心者,多无所谓</div> </template> </body> <script src="./js/vue.js" type="text/javascript"></script> <script> //创建组件方式③ Vue.component('customCom',{ template:'#temp' }); new Vue({ el: '#Container', data: { }, methods: { } }); </script> |
Vue定义私有组件
<head> <title>定义私有组件</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> </head> <body> <div id="Container"> <custom-com></custom-com> </div> <div id="Container2"> <!--无法使用私有组件--> <custom-com></custom-com> </div> <template id="temp"><div>有心者,才有所累;无心者,多无所谓</div></template> </body> <script src="./js/vue.js" type="text/javascript"></script> <script> new Vue({ el: '#Container', data: { }, methods: { }, components:{ customCom: { template:'#temp' } } }); new Vue({ el: '#Container2', data: { }, methods: { } }); </script> |
Vue全局组件中data的使用
<body> <div id="Container"> <custom-com></custom-com> </div> <template id="temp"> <!--组件中的数据使用类似vue实例中的数据--> <div>有心者,才有所累;无心者,多无所谓{{attach}}</div> </template> </body> <script src="./js/vue.js" type="text/javascript"></script> <script> Vue.component('customCom',{ template:'#temp', data:function(){ //值为一个函数,返回一个对象 return { attach:'这是附加数据' } } }); new Vue({ el: '#Container', data: { }, methods: { } }); </script> |
登录注册组件的切换
<body> <div id="Container"> <a href="" @click.prevent="login">登录</a> <a href="" @click.prevent="register">注册</a> <login v-if="flag"></login> <register v-else></register> </div> <template id="login"> <div>这是登录页面</div> </template> <template id="register"> <div>这是注册页面</div> </template> </body> <script src="./js/vue.js" type="text/javascript"></script> <script> Vue.component('login',{ template:'#login' }); Vue.component('register',{ template:'#register' }); new Vue({ el: '#Container', data: { flag:true }, methods: { login(){ this.flag=true; },register(){ this.flag=false; } } }); </script> |
登录注册组件的切换
<body> <div id="Container"> <a href="" @click.prevent="login">登录</a> <a href="" @click.prevent="register">注册</a> <!--component是一个占位符 用来指定组件的名称--> <component :is="comName"></component> </div> <template id="login"> <div>这是登录页面</div> </template> <template id="register"> <div>这是注册页面</div> </template> </body> <script src="./js/vue.js" type="text/javascript"></script> <script> Vue.component('login',{ template:'#login' }); Vue.component('register',{ template:'#register' }); new Vue({ el: '#Container', data: { comName:'login' }, methods: { login(){ this.comName='login'; },register(){ this.comName='register'; } } }); </script> |
登录注册组件的动画切换
<head> <title>登录注册组件的动画切换</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <style> .v-enter,.v-leave-to{ opacity:0; transform:translateX(150px); } .v-enter-active,.v-leave-active{ transition:all 0.5s ease; } </style> </head> <body> <div id="Container"> <a href="" @click.prevent="login">登录</a> <a href="" @click.prevent="register">注册</a> <transition mode="out-in"> <!--component是一个占位符 用来指定组件的名称--> <component :is="comName"></component> </transition> </div> <template id="login"> <div>这是登录页面</div> </template> <template id="register"> <div>这是注册页面</div> </template> </body> <script src="./js/vue.js" type="text/javascript"></script> <script> Vue.component('login',{ template:'#login' }); Vue.component('register',{ template:'#register' }); new Vue({ el: '#Container', data: { comName:'login' }, methods: { login(){ this.comName='login'; },register(){ this.comName='register'; } } }); </script> |
父组件向子组件传值(踩坑,传值失败)
<body> <div id="Container"> <custom-com v-bind:parentData="parentMsg"></custom-com> </div> <template id="templ"> <div>这里是子组件的数据内容{{parentData}}</div> </template> </body> <script src="./js/vue.js" type="text/javascript"></script> <script> new Vue({ el: '#Container', data: { parentMsg:'这是父组件中的数据' }, methods: { }, components:{ customCom:{ template:'#templ', props:['parentData'] } } }); </script> <!-- 浏览器控制台提示 [Vue tip]: Prop "parentdata" is passed to component <Anonymous>, but the declared prop name is "parentData". Note that HTML attributes are case-insensitive and camelCased props need to use their kebab-case equivalents when using in-DOM templates. You should probably use "parent-data" instead of "parentData".--> |
解决方法
要么将v-bind:parentData中的parentData改为小写方式,props:[‘parentdata’],引用也采用小写方式。或者只改变props:[‘parentdata’]和引用为小写都可以。
父组件向子组件传值(正确方法)
<body> <div id="Container"> <custom-com v-bind:parentdata="parentMsg"></custom-com> </div> <template id="templ"> <div>这里是子组件的数据内容{{parentdata}}</div> </template> </body> <script src="./js/vue.js" type="text/javascript"></script> <script> new Vue({ el: '#Container', data: { parentMsg:'这是父组件中的数据' }, methods: { }, components:{ customCom:{ template:'#templ', props:['parentdata'] } } }); </script> |
子组件通过调用向父组件方法向父组件传值
<body> <div id="Container"> <!--向子组件传递父组件的方法 自定义一个事件属性,子组件通过$emit触发父组件的事件 此处不能带引号,带引号是引用eventFromParent执行的结果 不带引号,代表引用这个方法 --> <custom-com @parentevent="eventFromParent"></custom-com> </div> <template id="templ"> <!--子组件调用自己的方法--> <div @click="eventFromSon" style="width:250px;height:250px;">这里是子组件的数据内容</div> </template> </body> <script src="./js/vue.js" type="text/javascript"></script> <script> new Vue({ el: '#Container', data: { }, methods: { //这样父组件可以获取子组件的数据 eventFromParent:function(agr1,arg2){ console.log('父组件的事件'+agr1,arg2) } }, components:{ customCom:{ template:'#templ', props:['parentdata'], data:function(){ return { msg:'这是来自子组件的数据' } }, methods:{ eventFromSon:function(){ /*调用父组件的方法 子组件可以使用 $emit 触发父组件的自定义事件 * emit 发出; 发射 * */ console.log(this.$emit('parentevent',this.msg,'子参数2')) } } } } }); </script> |
评论案例(父组件和子组件通信演示)
<body> <div id="Container"> <custom-com @loadcontent="loadContent"></custom-com> <table> <thead> <tr> <th>评论人</th> <th>评论内容</th> </tr> </thead> <tbody> <tr v-for="item in comments" :key="item.id"> <td>{{item.name}}</td> <td>{{item.content}}</td> </tr> </tbody> </table> </div> <template id="templ"> <div> <label for='userName'>用户名</label> <input type="text" name="userName" id="userName" v-model="userName"/><br><br> <label for='comment'>评论内容</label> <textarea name="comment" id="comment" v-model="comment"></textarea> <br><br> <button @click="submitContent">提交评论</button> </div> </template> </body> <script src="./js/vue.js" type="text/javascript"></script> <script> new Vue({ el: '#Container', data: { comments:[ ] }, methods: { //这样父组件可以获取子组件的数据 loadContent:function(){ var commentStr=localStorage.getItem('comments'); this.comments=JSON.parse(commentStr).reverse(); //JSON.parse() 方法用于将一个 JSON 字符串转换为对象。 } }, created:function(){ this.loadContent(); }, components:{ customCom:{ template:'#templ', props:['parentdata'], data:function(){ return { userName:'', comment:'' } }, methods:{ submitContent:function(){ var comments=localStorage.getItem('comments'); //localStorage中存储的是字符串 comments=JSON.parse(comments||'[]'); comments.push({id:Date.now(),name:this.userName,content:this.comment}); comments=JSON.stringify(comments) localStorage.setItem('comments', comments); this.$emit('loadcontent') } } } } }); </script> |
使用ref获取dom元素和组件引用
<body> <div id="Container"> <button @click="getInfo">获取数据</button> <div ref="parentDom">父组件的dom数据</div> <!--引用父元素--> <custom-com id="sonCom" ref="sonCom"></custom-com> <!--引用组件--> </div> <template id="templ"> <div>子组件的数据</div> </template> </body> <script src="./js/vue.js" type="text/javascript"></script> <script> new Vue({ el: '#Container', data: { }, methods: { getInfo:function(){ console.log(this.$refs); console.log(this.$refs.parentDom.innerText); //调用父组件的dom元素 console.log(this.$refs.sonCom.sonData); //调用子组件的数据 this.$refs.sonCom.sonMethod(); //调用子组件的方法 } }, components:{ customCom:{ template:'#templ', data:function(){ return { sonData:'通过$refs调用了子组件的数据' } }, methods:{ sonMethod:function(){ console.log('通过$refs调用了子组件的方法') } } } } }); </script> |
Vue-router路由的基本使用
<body> <a href="#/login">登录</a> <a href="#/register">注册</a> <div id="Container"> <!--路由视图占位符--> <router-view></router-view> </div> </body> <script src="./js/vue.js" type="text/javascript"></script> <!--安装vue-router路由 引入后路径为,域名/36.html#/ --> <script src="./js/vue-router.js" type="text/javascript"></script> <script> //①定义 (路由) 组件 var login={ template:'<h3>登录界面</h3>' }; var register={ template:'<h3>注册界面</h3>' }; //②定义路由 每个路由应该映射一个组件。 其中"component" 可以是通过 Vue.extend() 创建的组件构造器,或者,只是一个组件配置对象。我们晚点再讨论嵌套路由。 const routes = [ { path: '/login', component: login }, { path: '/register', component: register } ]; //③创建 router 实例,然后传 `routes` 配置 const router=new VueRouter({routes: routes}); new Vue({ el: '#Container', data: { }, methods: { }, router:router //④通过 router 配置参数注入路由,从而让整个应用都有路由功能 }); </script> |
Vue-router router-link的基本使用
<head xmlns="http://www.w3.org/1999/html"> <title>Vue-router router-link的基本使用</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <style> /*设置当前router-link的样式*/ .router-link-active{ color:red; font-weight:bold; } </style> </head> <body> <div id="Container"> <!--router-link必须放在vue实例中 --> <router-link to="/login" tag="span">登录</router-link> <!--渲染为<span class="">登录</span>--> <router-link to="/register">注册</router-link> <!--渲染为<a href="#/register" class="">注册</a>--> <!--路由视图占位符--> <router-view></router-view> </div> </body> <script src="./js/vue.js" type="text/javascript"></script> <!--安装vue-router路由 引入后路径为,域名/36.html#/ --> <script src="./js/vue-router.js" type="text/javascript"></script> <script> //①定义 (路由) 组件 var login={ template:'<h3>登录界面</h3>' }; var register={ template:'<h3>注册界面</h3>' }; //②定义路由 每个路由应该映射一个组件。 其中"component" 可以是通过 Vue.extend() 创建的组件构造器,或者,只是一个组件配置对象。我们晚点再讨论嵌套路由。 const routes = [ { path: '/', redirect: '/login' }, //重定向,设置路由根路径展示默认页面 { path: '/login', component: login }, { path: '/register', component: register } ]; //③创建 router 实例,然后传 `routes` 配置 const router=new VueRouter({routes: routes}); new Vue({ el: '#Container', data: { }, methods: { }, router:router //④通过 router 配置参数注入路由,从而让整个应用都有路由功能 }); </script> |
Vue-router动画
<head xmlns="http://www.w3.org/1999/html"> <title>Vue-router动画</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <style> /*设置当前router-link的样式*/ .router-link-active{ color:red; font-weight:bold; } .v-enter,.v-leave-to{ opacity:0; transform:translateX(150px); } .v-enter-active,.v-leave-active{ transition:all 1s ease; } </style> </head> <body> <div id="Container"> <!--router-link必须放在vue实例中 --> <router-link to="/login" tag="span">登录</router-link> <!--渲染为<span class="">登录</span>--> <router-link to="/register">注册</router-link> <!--渲染为<a href="#/register" class="">注册</a>--> <transition mode="out-in"> <router-view></router-view> </transition> </div> </body> <script src="./js/vue.js" type="text/javascript"></script> <!--安装vue-router路由 引入后路径为,域名/36.html#/ --> <script src="./js/vue-router.js" type="text/javascript"></script> <script> //①定义 (路由) 组件 var login={ template:'<h3>登录界面</h3>' }; var register={ template:'<h3>注册界面</h3>' }; //②定义路由 每个路由应该映射一个组件。 其中"component" 可以是通过 Vue.extend() 创建的组件构造器,或者,只是一个组件配置对象。我们晚点再讨论嵌套路由。 const routes = [ { path: '/', redirect: '/login' }, //重定向,设置路由根路径展示默认页面 { path: '/login', component: login }, { path: '/register', component: register } ]; //③创建 router 实例,然后传 `routes` 配置 const router=new VueRouter({routes: routes}); new Vue({ el: '#Container', data: { }, methods: { }, router:router //④通过 router 配置参数注入路由,从而让整个应用都有路由功能 }); </script> |
使用$route.query获得路由中定义参数
<head xmlns="http://www.w3.org/1999/html"> <title>使用$route.query获得路由中定义参数</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <style> /*设置当前router-link的样式*/ .router-link-active{ color:red; font-weight:bold; } .v-enter,.v-leave-to{ opacity:0; transform:translateX(150px); } .v-enter-active,.v-leave-active{ transition:all 1s ease; } </style> </head> <body> <div id="Container"> <router-link to="/login?name=xiaoli&age=15" tag="span">登录</router-link> <router-link to="/register">注册</router-link> <transition mode="out-in"> <router-view></router-view> </transition> </div> </body> <script src="./js/vue.js" type="text/javascript"></script> <script src="./js/vue-router.js" type="text/javascript"></script> <script> var login={ template:'<h3>登录界面--{{$route.query.name}}--{{$route.query.age}}</h3>', created:function(){ console.log(this.$route); //获取路由信息,其中包括路由参数 } }; var register={ template:'<h3>注册界面</h3>' }; const routes = [ { path: '/', redirect: '/login' }, { path: '/login', component: login }, { path: '/register', component: register } ]; const router=new VueRouter({routes: routes}); new Vue({ el: '#Container', data: { }, methods: { }, router:router }); </script> |
使用$route.param获得路由中定义参数
<head xmlns="http://www.w3.org/1999/html"> <title>使用$route.param获得路由中定义参数</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <style> /*设置当前router-link的样式*/ .router-link-active{ color:red; font-weight:bold; } .v-enter,.v-leave-to{ opacity:0; transform:translateX(150px); } .v-enter-active,.v-leave-active{ transition:all 1s ease; } </style> </head> <body> <div id="Container"> <router-link to="/login/2" tag="span">登录</router-link> <router-link to="/register">注册</router-link> <transition mode="out-in"> <router-view></router-view> </transition> </div> </body> <script src="./js/vue.js" type="text/javascript"></script> <script src="./js/vue-router.js" type="text/javascript"></script> <script> /*通过$route.params获取参数*/ var login={ template:'<h3>登录界面--{{$route.params.id}}</h3>', created:function(){ console.log(this.$route); //获取路由信息,其中包括路由参数 } }; var register={ template:'<h3>注册界面</h3>' }; const routes = [ { path: '/', redirect: '/login' }, { path: '/login/:id', component: login }, { path: '/register', component: register } ]; const router=new VueRouter({routes: routes}); new Vue({ el: '#Container', data: { }, methods: { }, router:router }); </script> |
路由循环嵌套
<body> <div id="Container"> <!--父路由视图占位符--> <router-view></router-view> </div> <template id="account"> <div> 账户页面 <router-link to="/account/login">登录</router-link> <router-link to="/account/register">注册</router-link> <!--子路由视图占位符--> <router-view></router-view> </div> </template> </body> <script src="./js/vue.js" type="text/javascript"></script> <script src="./js/vue-router.js" type="text/javascript"></script> <script> const account={ template:'#account' }; const routes = [ { path: '/', redirect:'/account' }, { path: '/account', component:account, children:[{ //children子路由配置 注意路径不要带斜线 path: 'login', component:{ template:'<h3>登录组件页面</h3>' } }, { path: 'register', component:{ template:'<h3>注册组件页面</h3>' } } ] } ]; const router=new VueRouter({routes: routes}); new Vue({ el: '#Container', data: { }, methods: { }, router:router }); </script> |
使用命名视图实现经典布局
<head xmlns="http://www.w3.org/1999/html"> <title>使用命名视图实现经典布局</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <style> .container{ display:flex; height:300px; padding:0; } h3{ padding:0; margin:0; } .header{ background-color: tomato; } .left{ flex:2; background-color: pink; } .right{ flex:8; background-color: darkgreen; } </style> </head> <body> <div id="Container"> <div> <router-view></router-view> <div class="container"> <router-view name="left"></router-view> <router-view name="right"></router-view> </div> </div> </div> </body> <script src="./js/vue.js" type="text/javascript"></script> <script src="./js/vue-router.js" type="text/javascript"></script> <script> const header={ template:'<h3 class="header">头部组件</h3>' }; const leftBox={ template:'<h3 class="left">左侧组件</h3>' }; const rightBox={ template:'<h3 class="right">右侧组件</h3>' }; const routes = [ { path: '/', components:{ 'default':header, //默认组件 'left':leftBox, //自定义组件引用名字 'right':rightBox } } ]; const router=new VueRouter({routes: routes}); new Vue({ el: '#Container', data: { }, methods: { }, router:router }); </script> |
名称案例 watch
<body> <div id="Container"> <input type="text" v-model="firstName"/>+<input type="text" v-model="lastName"/>=<input type="text" v-model="fullName"/> </div> </body> <script src="./js/vue.js" type="text/javascript"></script> <script> new Vue({ el: '#Container', data: { firstName:'', lastName:'', fullName:'' }, methods: { change:function(){ this.fullName=this.firstName+'-'+this.lastName } }, watch:{ //监视data中的数据的变化 /** * @param newVal新值 * @param oldVal旧值 */ firstName:function(newVal,oldVal){ this.change(); }, lastName:function(){ this.change(); } } }); </script> |
watch监听路由的改变
<body> <div id="Container"> <!--父路由视图占位符--> <router-view></router-view> </div> <template id="account"> <div> 账户页面 <router-link to="/account/login">登录</router-link> <router-link to="/account/register">注册</router-link> <!--子路由视图占位符--> <router-view></router-view> </div> </template> </body> <script src="./js/vue.js" type="text/javascript"></script> <script src="./js/vue-router.js" type="text/javascript"></script> <script> const account={ template:'#account' }; const routes = [ { path: '/', redirect:'/account' }, { path: '/account', component:account, children:[{ //children子路由配置 注意路径不要带斜线 path: 'login', component:{ template:'<h3>登录组件页面</h3>' } }, { path: 'register', component:{ template:'<h3>注册组件页面</h3>' } } ] } ]; const router=new VueRouter({routes: routes}); new Vue({ el: '#Container', data: { }, methods: { }, router:router, watch:{ '$route.path':function(newVal,oldVal){ console.log(newVal); //当前路由 console.log(oldVal); //之前的路由 } } }); </script> |
名称案例 computed计算属性实现
<body> <div id="Container"> <input type="text" v-model="firstName"/>+<input type="text" v-model="lastName"/>=<input type="text" v-model="fullName"/> </div> </body> <script src="./js/vue.js" type="text/javascript"></script> <script> new Vue({ el: '#Container', data: { firstName:'', lastName:'' }, computed:{ fullName:function(){ //内部的任何数据变化,都会重新执行 return(返回)一个值 return this.firstName+'-'+this.lastName } } }); </script> |
nrm 是一个 npm 源管理器,允许你快速地在 npm 源间切换。
$ npm install -g nrm 安装nrm $ nrm ls // 查看所有的支持源(有*号的表示当前所使用的源,以下[name]表示源的名称) $ nrm use [name] // 将npm下载源切换成指定的源 $ nrm help // 查看nrm帮助 $ nrm home [name] // 跳转到指定源的官网 |
参考:
https://www.cnblogs.com/joyho/articles/4430148.html
>npm install webpack@3 -g //安装webpack
webpack安装报错
C:\Users\Dell>npm install webpack@3.6 -g npm ERR! code ETIMEDOUT npm ERR! errno ETIMEDOUT npm ERR! network request to https://registry.npmjs.org/webpack failed, reason: connect ETIMEDOUT 104.16.23.35:443 npm ERR! network This is a problem related to network connectivity. npm ERR! network In most cases you are behind a proxy or have bad network settings. npm ERR! network npm ERR! network If you are behind a proxy, please make sure that the npm ERR! network 'proxy' config is set properly. See: 'npm help config' npm ERR! A complete log of this run can be found in: npm ERR! C:\Users\Dell\AppData\Roaming\npm-cache\_logs\2019-01-07T10_32_36_731Z-debug.log |
解决方法,重新配置镜像源,可能宿舍网络太差:
npm config set registry https://registry.npm.taobao.org |
重新安装,OK!
npm init
npm init 用来初始化生成一个新的 package.json 文件。它会向用户提问一系列问题,如果你觉得不用修改默认配置,一路回车就可以了。
如果使用了 -f(代表force)、-y(代表yes),则跳过提问阶段,直接生成一个新的 package.json 文件。
执行npm init -y命令,生成一个package.json文件,内容如下:
{ "name": "webpackDemo", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" } |
执行 npm install jQuery -S 生成package-lock.json文件,内容如下:
{ "name": "webpackDemo", "version": "1.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { "jQuery": { "version": "1.7.4", "resolved": "http://registry.npm.taobao.org/jQuery/download/jQuery-1.7.4.tgz", "integrity": "sha1-8y3FyFpwRO6GS0RDue5F+UeLoTc=" } } } |
并且生成一个node_modules文件夹。
webpack案例代码演示路径
index.html文件
<head> <script src='./main.js' type="text/javascript"></script> </head> <body> <div id="demo">这是一个简单的webpack demo</div> </body> |
main.js
import $ from 'jquery'; $(function(){ alert($('#demo').text()); }); |
IE报错:SCRIPT1086: SCRIPT1086: Module import or export statement unexpected here,因为import是ES6的语法。
解决浏览器兼容es6方法
c:\webpackDemo>webpack ./codes/main.js ./dist/bundle.js Hash: c08e1e23e12b03592706 Version: webpack 3.6.0 Time: 364ms Asset Size Chunks Chunk Names bundle.js 275 kB 0 [emitted] [big] main [0] ./codes/main.js 73 bytes {0} [built] + 1 hidden module |
index.html脚本引用修改为
<script src='../dist/bundle.js' type="text/javascript"></script> |
引用OK!
webpack作用:
①webpack能处理js文件的依赖关系
②webpack能处理js文件的兼容问题,把不识别的高级语法,转为浏览器能识别的语法。
配置webpack.config.js
const path=require('path') //通过node的模块,向外暴露了一个配置对象 module.exports={ entry:path.join(__dirname,'./codes/main.js'), //入口文件,标识,要打包的文件 output:{ path:path.join(__dirname,'./dist'), //指定打包好的文件,输出到哪个目录中 filename:'bundle.js' //输出的文件的名称 } } |
执行命令webpack
c:\webpackDemo>webpack Hash: c08e1e23e12b03592706 Version: webpack 3.6.0 Time: 499ms Asset Size Chunks Chunk Names bundle.js 275 kB 0 [emitted] [big] main [0] ./codes/main.js 73 bytes {0} [built] + 1 hidden module |
webpack-dev-server(自动打包编译工具)
webpack-dev-server帮我们打包生成的js文件,并没有存放到实际的物理磁盘中,而是存放在内存中,所以项目中找不到js文件,可以通过根目录来进行访问。
npm常用安装执行命令都是什么意思?
npm install webpack-dev-server -D 安装webpack-dev-server:
npm install module_name -S 即 npm install module_name –save 写入dependencies
npm install module_name -D 即 npm install module_name –save-dev 写入devDependencies
npm install module_name -g 全局安装(命令行使用)
npm install module_name 本地安装(将安装包放在 ./node_modules 下)
devDependencies和dependencies区别
devDependencies(-D) 里面的插件只用于开发环境,不用于生产环境
dependencies(-S) 是需要发布到生产环境的
由于npm install webpack-dev-server -D是在本地安装的webpack-dev-server,所以无法把它当做脚本命令,在powershell终端中直接运行,只有安装到全局-g的工具,才能在终端正常指向。
为了保证webpack-dev-server正常执行,需要以下几个步骤:
①在package.json文件scripts属性中配置以下内容:
“dev”: “webpack-dev-server”
②npm install webpack@3.6.0 -D
③npm install webpack-cli@3.1.0 -D
④npm install webpack-dev-server@2.9.7 -D
注意在安装的过程中多次报如下错误:
c:\webpackDemo>npm run dev > webpackDemo@1.0.0 dev c:\webpackDemo > webpack-dev-server c:\webpackDemo\node_modules\ajv-keywords\keywords\instanceof.js:52 throw new Error('invalid "instanceof" keyword value ' + c); ^ Error: invalid "instanceof" keyword value Promise at getConstructor (c:\webpackDemo\node_modules\ajv-keywords\keywords\instanceof.js:52:11) at Ajv.compile (c:\webpackDemo\node_modules\ajv-keywords\keywords\instanceof.js:21:27) at Object.useCustomRule (c:\webpackDemo\node_modules\ajv\lib\compile\index.js:275:26) at Object.generate_custom [as code] (c:\webpackDemo\node_modules\ajv\lib\dotjs\custom.js:32:24) at Object.generate_validate [as validate] (c:\webpackDemo\node_modules\ajv\lib\dotjs\validate.js:347:35) at Object.generate_anyOf [as code] (c:\webpackDemo\node_modules\ajv\lib\dotjs\anyOf.js:34:27) at generate_validate (c:\webpackDemo\node_modules\ajv\lib\dotjs\validate.js:347:35) at localCompile (c:\webpackDemo\node_modules\ajv\lib\compile\index.js:87:22) at Ajv.compile (c:\webpackDemo\node_modules\ajv\lib\compile\index.js:56:13) at Ajv._compile (c:\webpackDemo\node_modules\ajv\lib\ajv.js:358:27) npm ERR! code ELIFECYCLE npm ERR! errno 1 npm ERR! webpackDemo@1.0.0 dev: `webpack-dev-server` npm ERR! Exit status 1 npm ERR! npm ERR! Failed at the webpackDemo@1.0.0 dev script. npm ERR! This is probably not a problem with npm. There is likely additional logging output above. npm ERR! A complete log of this run can be found in: npm ERR! C:\Users\Dell\AppData\Roaming\npm-cache\_logs\2019-01-07T14_16_40_174Z-debug.log |
于是调整webpack-dev-server版本达到了兼容。
{ "name": "webpackDemo", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "dev": "webpack-dev-server" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "jQuery": "^1.7.4", "jquery": "^3.3.1" }, "devDependencies": { "webpack": "^3.6.0", "webpack-cli": "^3.1.0", "webpack-dev-server": "^2.9.7" } } |
运行npm run dev
c:\webpackDemo>npm run dev > webpackDemo@1.0.0 dev c:\webpackDemo > webpack-dev-server Project is running at http://localhost:8080/ webpack output is served from / Hash: 63e354da243eb5b105e8 Version: webpack 3.6.0 Time: 568ms Asset Size Chunks Chunk Names bundle.js 597 kB 0 [emitted] [big] main [2] multi (webpack)-dev-server/client?http://localhost:8080 ./codes/main.js 40 bytes {0} [built] [3] (webpack)-dev-server/client?http://localhost:8080 7.95 kB {0} [built] [4] ./node_modules/url/url.js 23.3 kB {0} [built] [8] ./node_modules/querystring-es3/index.js 127 bytes {0} [built] [11] ./node_modules/strip-ansi/index.js 161 bytes {0} [built] [13] ./node_modules/loglevel/lib/loglevel.js 7.86 kB {0} [built] [14] (webpack)-dev-server/client/socket.js 1.05 kB {0} [built] [15] ./node_modules/sockjs-client/dist/sockjs.js 181 kB {0} [built] [16] (webpack)-dev-server/client/overlay.js 3.73 kB {0} [built] [17] ./node_modules/ansi-html/index.js 4.26 kB {0} [built] [18] ./node_modules/html-entities/index.js 231 bytes {0} [built] [21] (webpack)/hot nonrecursive ^\.\/log$ 170 bytes {0} [built] [23] (webpack)/hot/emitter.js 77 bytes {0} [built] [25] ./codes/main.js 73 bytes {0} [built] [26] ./node_modules/jquery/dist/jquery.js 272 kB {0} [built] + 12 hidden modules webpack: Compiled successfully. |
回车输入 http://localhost:8080/ 如下图:
由于webpack-dev-server编译的文件webpack output is served from /,而且存放在内存中,以便快速打包编译,所以index.html文件引入的时候,通过以下方式引入bundle.js:
<script src='/bundle.js' type="text/javascript"></script> |
webpack-dev-server常用指令
修改package.json文件将dev属性修改为:”dev”: “webpack-dev-server –open –port 2000 –contentBase src –hot”,然后重启npm run dev,就可以打包后,根据设置的服务器端口/默认打开目录热重载,直接打开浏览器.
另一种使用webpack-dev-server指令的方式
在webpack.config.js中配置webpack-dev-server
首先在package.json中scripts配置: “dev”: “webpack-dev-server”,然后再webpack.config.js中配置如下:
const path=require('path') const webpack=require('webpack') //通过node的模块,向外暴露了一个配置对象 module.exports={ entry:path.join(__dirname,'./src/main.js'), //入口文件,标识,要打包的文件 output:{ path:path.join(__dirname,'./dist'), //指定打包好的文件,输出到哪个目录中 filename:'bundle.js' //输出的文件的名称 }, devServer:{ open:true, port:3000, contentBase:'src', hot:true }, plugins:[ //配置插件的节点 new webpack.HotModuleReplacementPlugin() ] } |
html-webpack-plugin插件的使用
html-webpack-plugin 插件是用于编译 Webpack 项目中的 html 类型的文件,如果直接将 html 文件置于 ./src 目录中,用 Webpack 打包时是不会编译到生产环境中的。因为 Webpack 编译任何文件都需要基于配置文件先行配置的。
html-webpack-plugin安装:npm install html-webpack-plugin -D
const path=require('path') const webpack=require('webpack') //内存中生成html的插件 //只要是插件都一定要放到插件节点中去 const htmlWebpackPlugin=require('html-webpack-plugin') module.exports={ entry:path.join(__dirname,'./src/main.js'), //入口文件,标识,要打包的文件 output:{ path:path.join(__dirname,'./dist'), //指定打包好的文件,输出到哪个目录中 filename:'bundle.js' //输出的文件的名称 }, devServer:{ open:true, port:3000, contentBase:'src', hot:true }, plugins:[ //配置插件的节点 new webpack.HotModuleReplacementPlugin(), new htmlWebpackPlugin({ template:path.join(__dirname,'./src/index.html'), //指定模板页面,将来会根据指定的页面在内存中生成页面 filename:'index123.html' //指定生成的页面名称 }) ] } |
你就可以通过http://localhost:3000/index123.html访问/src/index.html模板文件
index.html文件代码:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <!-- <script src='/bundle.js' type='text/javascript'></script> --> </head> <body> <div id="demo">这是一个webpack的demo啊</div> </body> </html> |
index123.html源码文件:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <!-- <script src='/bundle.js' type='text/javascript'></script> --> </head> <body> <div id="demo">这是一个webpack的demo啊</div> <!--自动挂载内存中的js文件,因为在web.config.js文件中module.exports配置关联起来的--> <script type="text/javascript" src="bundle.js"></script></body> </html> |
webpack只能打包js文件,处理非js类型文件需要安装一些文件类型对应的第三方loader加载器
①安装cssloader加载器 npm install style-loader css-loader -D
②定义/src/css/main.css文件
#demo{ background-color: red; width:250px; height:250px; } |
③/src/main.js引入main.css内容
import $ from 'jquery' import './css/main.css' $(function(){ alert($('#demo').text()+'d2222dd'); }) |
④配置webpack.config.js文件中的module属性
const path=require('path') const webpack=require('webpack') //内存中生成html的插件 //只要是插件都一定要放到插件节点中去 const htmlWebpackPlugin=require('html-webpack-plugin') module.exports={ entry:path.join(__dirname,'./src/main.js'), //入口文件,标识,要打包的文件 output:{ path:path.join(__dirname,'./dist'), //指定打包好的文件,输出到哪个目录中 filename:'bundle.js' //输出的文件的名称 }, devServer:{ open:true, port:3000, contentBase:'src', hot:true }, plugins:[ //配置插件的节点 new webpack.HotModuleReplacementPlugin(), new htmlWebpackPlugin({ template:path.join(__dirname,'./src/index.html'), //指定模板页面,将来会根据指定的页面在内存中生成页面 filename:'index123.html' //指定生成的页面名称 }) ], module:{ //配置所有第三方模块加载器 rules:[ //所有第三方模块的匹配规则,如下匹配所有以css文件结尾的文件,使用style-loader和css-loader模块加载器,多个loader从右到左依次调用 {test: /\.css$/,use:['style-loader','css-loader']} ]} } |
这样就可以正常解析css文件,进行编译了.
更多第三方loader参考
https://webpack.js.org/loaders/
当css样式采用外部资源(字体库和图片之类的url地址)时,比如background-image: url(‘../images/zs.jpeg’);报错提示如下:
Module parse failed: C:\Users\Administrator\app\src\images\zs.jpeg Unexpected character ‘�’ (1:0)
You may need an appropriate loader to handle this file type.
(Source code omitted for this binary file)
我们需要安装第三方loader
npm install url-loader file-loader -D
module添加图片的rule规则,如下:
module:{ //配置所有第三方模块加载器
rules:[ //所有第三方模块的匹配规则,如下匹配所有以css文件结尾的文件,使用style-loader和css-loader模块加载器
{test: /\.css$/,use:[‘style-loader’,’css-loader’]},
{test:/\.(jpg|jpeg|png|gif|bmp)$/,use:’url-loader’}
]}
默认不限制图片的大小,对图片进行base64编码,解析如下:
background-image: url(data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgMCAgMDAwMEAwME…T3BnpHwmybZLioi6+IVb4dgu66iqqGhbUPEsN3g5KLpJXjaQ7KQ5jZHuc4XJJyjgillbTP/9k=); |
当前图片大小为112,601 字节,对编码大小进行限制如下:
{test:/\.(jpg|jpeg|png|gif|bmp)$/,use:'url-loader?limit=112600'} |
解析如下:
background-image: url(4a2ffe908d473eb7c4ae366eac5c3af6.jpeg); |
所以,如果图片大于或者等于limit设定值,则不会被转为base64编码,如果做如下配置
{test:/\.(jpg|jpeg|png|gif|bmp)$/,use:'url-loader?limit=112600&name=[hash:32]-[name].[ext]'} |
不转base64编码生成的图片路径:
url(4a2ffe908d473eb7c4ae366eac5c3af6-zs.jpeg) |
在webpack中只能处理一部分ES6的新语法,无法打包的ES6和ES7语法,需要借助第三方loader实现,当第三方loader把高级语法处理完之后,会把结果交给webpack去打包,Babel就是这样产生了。
在webpack中,我们可以运行如下两套命令,安装两套包,安装Babel相关的loader功能:
①npm install babel-core babel-loader babel-plugin-transfrom-runtime -D
②npm install babel-preset-env babel-preset-stage-0 -D
Render函数是Vue2.x版本新增的一个函数;使用虚拟dom来渲染节点提升性能,因为它是基于JavaScript计算。通过使用createElement(h)来创建dom节点。createElement是render的核心方法。其Vue编译的时候会把template里面的节点解析成虚拟dom;
什么是虚拟dom?虚拟dom不同于真正的dom,它是一个JavaScript对象。当状态发生变化的时候虚拟dom会进行一个diff判断/运算;然后判断哪些dom是需要被替换的而不是全部重绘,所以性能会比dom操作高很多。
<body> <div id="Container"> </div> </body> <script src="./js/vue.js" type="text/javascript"></script> <script> var login={template:'<h3>这是一个登陆组件</h3>'}; new Vue({ el: '#Container', data: { firstName:'', lastName:'' }, render:function(createElement){ return createElement(login); } }); </script> |
webpack中使用vue
安装vue模块
npm install vue -S
在webpack中,使用 import Vue from ‘vue’导入的vue构造函数,功能不完善,只提供了runtime-only的方式,并没有提供像网页中那样使用的方式。
包的查找规则:
1.项目根目录中有没有node_modules的文件夹
2.在node_modules中根据包名,找对应的文件夹
3.在文件夹中,找一个叫做package.json的包配置文件
4.在package.json文件中,查找一个main属性
vue下package.json的main属性,配置如下:
dist/vue.runtime.common.js
有以下两种方式在webpack中,使用Vue:
方法一:vue下package.json中修改”main”: “dist/vue.runtime.common.js”为”main”: “dist/vue.common.js” (不推荐)
方法二:import Vue from ‘../node_modules/vue/dist/vue.js’; (node_modules/vue/dist/vue.js等效)
方法三:依旧通过import Vue from ‘vue’;导入,但是需要在webpack.config.js中做一些配置,module.exports对象中添加如下键值对,修改vue导入包的路径:
resolve:{ alias:{ "vue$":'vue/dist/vue.js' } } |
vue runtime-only模式 渲染组件到容器中
①安装vue所需要loader
默认,webpack无法打包.vue文件,需要安装相关的loader
npm install vue-loader@14 vue-template-compiler -D
②创建.vue文件:
采用传统的方式(如下),使用组件(components属性定义),组件由三部分组成无法打包vue组件,需要使用render方式
<template> <div> <div>登录组件</div> </div> </template> <script> export default { data() { return { }; } } </script> <style> </style> |
创建/src/components/login.vue文件
<template> <div>登录组件</div> </template> |
③然后在main.js文件中导入模块和组件,代码如下:
import Vue from 'vue' import login from './components/login.vue' new Vue({ 'el':'#container', data:{ msg:'组件的使用' }, render:function(createElement){ //采用传统的方式,使用组件(components属性定义),无法打包vue组件,需要使用render方式 return createElement(login); } }); |
简写模式,效果同上:
import Vue from 'vue' import login from './components/login.vue' new Vue({ 'el':'#container', data:{ msg:'组件的使用' }, render:c => c(login) }); |
④package.json文件中配置模块rule规则:
{test:/\.vue$/,use:'vue-loader'} |
在node中,使用var 名称=require(‘模块标识符’)
module.exports和exports向外暴露成员
export default和export的区别
ES6导入模块:import 模块名称 from ‘模块标识符’ || import ‘路径’
ES6导出模块:使用export default 和 export向外暴露成员
使用注意事项:
export default向外暴露的成员,可以使用任意变量来接收成员.使用export导出的成员,必须按照严格方式相同的名称接收(可以自定义起别名).
export default在一个模块中只允许向外暴露一次,export可以向外多次暴露
在一个模块中可以同时使用export default 和 export向外暴露成员
使用export向外暴露的成员,只能使用{}的形式来接收,这种形式叫做按需导出
正是因为export default命令其实只是输出一个叫做default的变量,所以它后面不能跟变量声明语句,而export需要跟变量声明或者大括号作为输出
test.js文件 导出模块
export default{ name:'小明', age:20 } /* 无效方式,报错 var xiaoli='xiaoli'; export xiaoli; */ export var xiaoli='xiaoli'; export var xiaobaiInfo={name:'小白',age:30}; |
main.js文件 导入模块
import xiaomingInfo,{xiaoli as xiaoliInfo,xiaoli,xiaobaiInfo} from './js/test.js' console.log(xiaomingInfo); //输出 {name: "小明", age: 20} console.log(xiaoliInfo); //变量起别名 输出 xiaoli console.log(xiaoli); //输出 xiaoli console.log(xiaobaiInfo); //输出 {name: "小白", age: 30} |
结合webpack使用vue-router
index.html
<div id="container"> </div> |
main.js
import Vue from 'vue' import VueRouter from 'vue-router' import app from './components/app.vue' import login from './components/login.vue' import register from './components/register.vue' Vue.use(VueRouter) const routes = [ { path: '/login', component: login }, { path: '/register', component: register } ]; const router=new VueRouter({routes: routes}); new Vue({ el:'#container', data:{ }, render:function(createElement){ return createElement(app); }, router:router }) |
app.vue
<template> <div> <div>个人中心</div> <router-link to='./login'>登录</router-link> <router-link to='./register'>注册</router-link> <router-view></router-view> </div> </template> <script> export default { data() { return { }; } } </script> <style> </style> |
login.vue
<template> <div> <div>登录组件</div> </div> </template> <script> export default { data() { return { msg:'这是一个消息' }; }, methods:{ } } </script> <style> </style> |
register.vue
<template> <div> 注册组件 </div> </template> <script> export default { data() { return { }; } } </script> <style> </style> |
webpack中实现children子路由
index.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <div id="container"> </div> </body> </html> |
main.js
import Vue from 'vue' import VueRouter from 'vue-router' import app from './components/app.vue' import account from './components/account.vue' import login from './components/login.vue' import register from './components/register.vue' Vue.use(VueRouter) const routes = [{ path: '/account', component: account, children: [{ path: 'login', component: login, }, { path: 'register', component: register, } ] }]; const router = new VueRouter({ routes: routes }); new Vue({ el: '#container', data: { }, render: function(createElement) { return createElement(app); }, router: router }) |
app.vue
<template> <div> <div>个人中心</div> <router-link to='/account'>账户</router-link> <router-view></router-view> </div> </template> <script> export default { data() { return { }; } } </script> <style> </style> |
父组件 account.vue
<template> <div> <router-link to='/account/login'>登录</router-link> <router-link to='/account/register'>注册</router-link> <router-view></router-view> </div> </template> <script> export default { data() { return { }; } } </script> <style> </style> |
子组件 register.vue
<template> <div> 注册组件 </div> </template> <script> export default { data() { return { }; } } </script> <style> </style> |
子组件 login.vue
<template> <div> <div>登录组件</div> </div> </template> <script> export default { data() { return { msg:'这是一个消息' }; }, methods:{ } } </script> <style> </style> |
scoped 在style标签上添加scoped属性,以表示它的样式作用于当下的模块,很好的实现了样式私有化的目的,这是一个非常好的机制。但是为什么要慎用呢?在实际业务中我们往往会对公共组件样式做细微的调整,如果添加了scoped属性,那么样式将会变得不易修改。
<style scoped> div{ color:red; } </style> |
默认只支持普通样式,设置lang属性支持scss,sass样式
<style scoped lang="scss"> body{ div{ color:red; } } </style> |
117 118跳过
Mint-ui的使用(Mint UI 基于 Vue.js 的移动端组件库)
文档地址
https://mint-ui.github.io/#!/zh-cn
安装 npm i mint-ui -S
代码实例
main.js
import Vue from 'vue' import MintUI from 'mint-ui' import 'mint-ui/lib/style.css' import App from './App.vue' Vue.use(MintUI) new Vue({ el: '#app', data:{ msg:'模板消息' }, render:function(createElement){ return createElement(App) } }) |
CSS Components的使用示例(在App.vue中,通过以上引用可以直接使用):
<template> <div> <mt-button type="default" @click.native="show">点击按钮触发</mt-button> </div> </template> |
JS Components的使用示例(App.vue):
<template> <div> <mt-button type="default" @click.native="show">点击按钮触发</mt-button> </div> </template> <script> import { Toast } from 'mint-ui'; export default { data() { return { } }, methods:{ show(){ console.log('sdfjksdf'); Toast('提示信息'); } } } </script> <style> |
JS Components Toast组件,如果未引用会报如下错误:
Uncaught ReferenceError: Toast is not defined at VueComponent.show
Mint UI按需导入
npm install babel-plugin-component -D
win10下安装babel-plugin-component有个坑,默认创建或者修改文件必须包含名称(键名),也就是不能以.**命名文件,所以无法创建.babelrc,解决方案如下:
新建1.babelrc文件,然后重命名rename 1.babelrc .babelrc,然后配置如下:
{ "presets": [ ["es2015", { "modules": false }] ], "plugins": [["component", [ { "libraryName": "mint-ui", "style": true } ]]] }
main.js
import Vue from 'vue' import 'mint-ui/lib/style.css' import { Button } from 'mint-ui' import App from './App.vue' Vue.component(Button.name, Button) new Vue({ el: '#app', data:{ msg:'模板消息' }, render:c=>c(App) }) |
App.vue
<template> <div> <mt-button type="danger">danger</mt-button> </div> </template> |
Vue中mui的使用
main.js引入css文件
import Vue from 'vue' import app from './components/app.vue' import './lib/mui/css/mui.min.css' new Vue({ el: '#container', data: { }, render: function(createElement) { return createElement(app); } }) |
在组件中使用app.vue中使用:
<template> <div> <span class="mui-badge">1</span> <span class="mui-badge mui-badge-primary">12</span> <span class="mui-badge mui-badge-success">123</span> <span class="mui-badge mui-badge-warning">3</span> <span class="mui-badge mui-badge-danger">45</span> <span class="mui-badge mui-badge-purple">456</span> </div> </template> |
在加载mui css文件ttf文件时,出现以下错误:
./src/lib/mui/fonts/mui.ttf Module parse failed: C:\Users\Administrator\app\src\lib\mui\fonts\mui.ttf Unexpected character '
在webpack.config.js文件中的module属性中,配置如下模块解析规则,即可解决:
{test:/\.(jpg|jpeg|png|gif|bmp|eot|ttf|svg)$/,use:'url-loader?limit=112600&name=[hash:32]-[name].[ext]'} |
HBuilder X中同步代码到码云
在工具=>插件安装=>git插件,点击安装即可安装HBuilder X 的插件git
.gitignore文件设置
node_modules
.idea
.git
首先在码云新建仓库,新建仓库后,Git全局设置:
git config --global user.name "lansesuixiang" git config --global user.email "412198579@qq.com"
新建本地仓库
git init
添加远程库
git remote add origin https://gitee.com/lansesuixiang/vuedemo.git
git status
查询文件的状态
git add .
提交新文件(new)和被修改(modified)文件,不包括被删除(deleted)文件(提交到本地的版本库)
git commit -m “init my project” 报错如下:
*** Please tell me who you are. Run git config --global user.email "you@example.com" git config --global user.name "Your Name" to set your account's default identity. Omit --global to set the identity only in this repository. fatal: unable to auto-detect email address (got 'Administrator@CN-20170415JVTT.( none)')
执行以下两条命令即可解决解决
git config --global user.name "lansesuixiang" git config --global user.email "412198579@qq.com"
如何退出git bash vim编辑器:
ESC --》 退出编辑状态;接着 连续按两次大写字母键 Z,接着你会惊喜的发现,终于保存好退出来了!
在git bash中执行ssh-keygen -t rsa -C “412198579@qq.com”生成SSH公钥复制到码云中
Administrator@CN-20170415JVTT MINGW32 ~ $ ssh-keygen -t rsa -C "412198579@qq.com" Generating public/private rsa key pair. Enter file in which to save the key (/c/Users/Administrator/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /c/Users/Administrator/.ssh/id_rsa. Your public key has been saved in /c/Users/Administrator/.ssh/id_rsa.pub. The key fingerprint is: SHA256:wADt+pPL+kjhcvVxmsSczd97uAiwdMt2VwyWO0xe6Fg 412198579@qq.com The key's randomart image is: +---[RSA 2048]----+ | .o. | | .o o | | . o E . | | .o = O = | | ... O S . * o | | ..o + X o . o | |. +. .= = o o. | | + o+ . o o... | | oo+o . oo | +----[SHA256]-----+
git push -u origin master 上面命令将本地的master分支推送到origin主机,同时指定origin为默认主机,后面就可以不加任何参数使用git push了
HBuilder X中同步代码到码云
git修改文件后,git提交
①命令行传统方式
git add .
git commit -m “something”
git push
②HBuilder X中修改提交
选中项目 先git commit 后git push
mui自定义图标的使用
①import ‘./lib/mui/css/icons-extra.css’
②将mui-icons-extra.ttf复制到项目中
③根据demo中的样式使用即可
Promise对象解决回调地狱问题
Promise 对象是 JavaScript 的异步操作解决方案,为异步操作提供统一接口。它起到代理作用(proxy),充当异步操作与回调函数之间的中介,使得异步操作具备同步操作的接口。Promise 可以让异步操作写起来,就像在写同步操作的流程,而不必一层层地嵌套回调函数。
Promise 的设计思想是,所有异步任务都返回一个 Promise 实例。Promise 实例有一个then方法,用来指定下一步的回调函数。
回调地狱
首先创建1.txt 2.txt 3.txt
demo.js 文件内容 读取单个文件内容
const fs=require('fs') const path=require('path') function getFileInfo(filePath,callback){ fs.readFile(path.join(__dirname,filePath),'utf-8',(err,datastr)=>{ //回调异步方法 if(err){ return callback(err) } callback(null,datastr) }) } getFileInfo('1.txt',(err,datastr)=>{ if(err){ console.log(err) }else{ console.log(datastr) } }) |
按顺序读取1.txt 2.txt 3.txt内容
const fs = require('fs') const path = require('path') function getFileInfo(filePath, sucCallback, errCallback) { fs.readFile(path.join(__dirname, filePath), 'utf-8', (err, datastr) => { //回调异步方法 if (err) { return errCallback(err) } sucCallback(datastr) }) } //回调地狱案例 层层嵌套 //按顺序读取1.txt 2.txt 3.txt getFileInfo('1.txt', function(data){ console.log(data); getFileInfo('2.txt', function(data){ console.log(data); getFileInfo('3.txt', function(data){ console.log(data); }) }) }) |
单个promise demo
//promise const fs = require('fs') const path = require('path') // new出来Promise实例,只是代表形式上的异步操作,我们只知道它是一个异步操作,但是做什么事情,我们还不清楚 // var promise = new Promise(); //这是一个具体的异步操作,其中function指定了一个具体的异步操作 //每当new Promise就会执行一个异步操作,而且返回一个Promise实例 /* function getFileInfo(filePath) { var promise = new Promise( function() { fs.readFile(filePath, 'utf-8', function(err, data) { if (err) return console.log('发生了错误' + err); console.log('读取的数据:' + data); }); }); } getFileInfo(path.join(__dirname, '3.txt')); */ function getFileInfo(filePath) { var promise = new Promise( function(resolve,reject) { //形参 参数为成功和失败的回调函数 //异步操作 fs.readFile(filePath, 'utf-8', function(err, data) { if (err) return reject(err); //失败回调 resolve(data); //成功回调 }); }); return promise; } var p=getFileInfo(path.join(__dirname, '5.txt')); // .then定义 Promise 的成功和失败情况的回调函数。 p.then(function(data){ console.log('执行成功'+data); },function(err){ console.log('执行失败'+err.message); }) |
promise正确姿势 按顺序读取1.txt 2.txt 3.txt
const fs = require('fs') const path = require('path') function getFileInfo(filePath) { var promise = new Promise( function(resolve, reject) { //形参 参数为成功和失败的回调函数 //异步操作 fs.readFile(filePath, 'utf-8', function(err, data) { if (err) return reject(err); //失败回调 resolve(data); //成功回调 }); }); return promise; } var p = getFileInfo(path.join(__dirname, '1.txt')); p.then(function(data) { console.log('执行成功1--' + data); return getFileInfo(path.join(__dirname, '2.txt')) }).then(function(data) { console.log('执行成功2--' + data); return getFileInfo(path.join(__dirname, '4.txt')) }).then(function(data){ console.log('执行成功3--'+data); },function(err){ console.log('执行失败'+err) }) |
以上demo,无法正确执行错误回调,下边正确修改
const fs = require('fs') const path = require('path') function getFileInfo(filePath) { var promise = new Promise( function(resolve, reject) { //形参 参数为成功和失败的回调函数 //异步操作 fs.readFile(filePath, 'utf-8', function(err, data) { if (err) return reject(err); //失败回调 resolve(data); //成功回调 }); }); return promise; } var p = getFileInfo(path.join(__dirname, '1.txt')); p.then(function(data) { console.log('执行成功1--' + data); return getFileInfo(path.join(__dirname, '1.txt')) },function(err){ console.log('执行失败1--' + err); return getFileInfo(path.join(__dirname, '2.txt')) }).then(function(data) { console.log('执行成功2--' + data); return getFileInfo(path.join(__dirname, '2.txt')) },function(err){ console.log('执行失败2--' + err); return getFileInfo(path.join(__dirname, '3.txt')) }).then(function(data){ console.log('执行成功3--'+data); },function(err){ console.log('执行失败'+err) }) |
捕获错误,停止继续执行
const fs = require('fs') const path = require('path') function getFileInfo(filePath) { var p = new Promise(function(resolve, reject) { fs.readFile(filePath,'utf-8',function(err, data) { if (err) return reject(err); resolve(data); } ); }); return p; } var p = getFileInfo(path.join(__dirname, '1.txt')); p.then(function(data){ console.log(data); return getFileInfo(path.join(__dirname, '22.txt')); }) .then(function(data){ console.log(data); return getFileInfo(path.join(__dirname, '3.txt')); }) .then(function(data){ console.log('ok'); console.log(data) }) .catch(function(err){ console.log('发生错误'+err.message+'停止继续执行') }) |
jquery中ajax使用promise指定回调成功回调函数
var jsdom = require("jsdom"); var $ = require("jquery")(jsdom.jsdom().defaultView); $(function(){ $.ajax({ url:'http://www.liulongbin.top:3005/api/getlunbo', async:false, dataType:'json' }).then(function(response){ //这样就可以将data数据继续传递至调用该方法接下去执行的then()方法的回调函数中了。 console.log(JSON.stringify(response)) }); }); |
坑:在node中服务器端使用jquery遇到jQuery requires a window with a document,原因在于jquery的运行需要window的运行环境,在浏览器端是没问题的,而在服务器上就不包含了,需要jsdom创建一个window给它,就可以解决这个问题.
babel-plugin-transform-remove-strict-mode
使用babel进行es6转es5时,默认转化之后是严格模式,有些时候我们想去除严格模式就需要babel-plugin-transform-remove-strict-mode这个东西了。
https://www.npmjs.com/package/babel-plugin-transform-remove-strict-mode
制作顶部滑动条的坑:
需要借助于 MUI 中的 tab-top-webview-main.html
需要把 slider 区域的 mui-fullscreen 类去掉
滑动条无法正常触发滑动,通过检查官方文档,发现这是JS组件,需要被初始化一下:
导入 mui.js
调用官方提供的 方式 去初始化:
mui(‘.mui-scroll-wrapper’).scroll({
deceleration: 0.0005 //flick 减速系数,系数越大,滚动速度越慢,滚动距离越小,默认值0.0006
});
我们在初始化 滑动条 的时候,导入的 mui.js ,但是,控制台报错: Uncaught TypeError: ‘caller’, ‘callee’, and ‘arguments’ properties may not be accessed on strict mode
经过我们合理的推测,觉得,可能是 mui.js 中用到了 ‘caller’, ‘callee’, and ‘arguments’ 东西,但是, webpack 打包好的 bundle.js 中,默认是启用严格模式的,所以,这两者冲突了;
解决方案: 1. 把 mui.js 中的 非严格 模式的代码改掉;但是不现实; 2. 把 webpack 打包时候的严格模式禁用掉;
最终,我们选择了 plan B 移除严格模式: 使用这个插件 babel-plugin-transform-remove-strict-mode
刚进入 图片分享页面的时候, 滑动条无法正常工作, 经过我们认真的分析,发现, 如果要初始化 滑动条,必须要等 DOM 元素加载完毕,所以,我们把 初始化 滑动条 的代码,搬到了 mounted 生命周期函数中;
当 滑动条 调试OK后,发现, tabbar 无法正常工作了,这时候,我们需要把 每个 tabbar 按钮的 样式中 mui-tab-item 重新改一下名字;
获取所有分类,并渲染 分类列表;
webpack兼容性
{ "name": "meetwebpack", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "webpack" }, "author": "", "license": "ISC", "dependencies": { "vue": "^2.6.12" }, "devDependencies": { "babel-core": "^6.26.3", "babel-loader": "^7.1.5", "babel-preset-es2015": "^6.24.1", "css-loader": "^3.0.0", "file-loader": "^1.1.5", "html-webpack-plugin": "^2.30.1", "less": "^3.13.0", "less-loader": "^4.1.0", "style-loader": "^2.0.0", "uglifyjs-webpack-plugin": "^1.1.1", "url-loader": "^2.1.0", "vue-loader": "^13.0.0", "vue-template-compiler": "^2.6.12", "webpack": "^3.6.0" } } |
参考:https://blog.csdn.net/qq_44815747/article/details/
全局安装webpack(这里我们指定版本号为3.6.0,因为vue cli2依赖这个版本)
npm install webpack@3.6.0 -g
为什么全局安装后,还需要局部安装呢?
在终端执行webpack命令,使用的全局安装的webpack
当在package.json中定义了scripts时,其中包含了webpack命令,那么使用的是局部webpack
webpack ./src/main.js ./dist/bundle.js
npm init 生成 package.json文件
npm install webpack@3.6.0 –save-dev
package.json增加如下依赖 "devDependencies": { "webpack": "^3.6.0" } |
我们主要是用webpack来处理我们写的js代码,并且webpack之间会自动处理js之间相关的依赖,但是,在开发中我们不仅有基本的js代码处理,我们也需要加在css、图片,也包括一些高级的将ES6转成ES5代码,将typescript转换成ES5代码,将scss、less转成css,将.jsx、.vue文件转换成js文件等等。
对于webpack本身的能力来说,这些转换是不支持的,那怎么办呢?给webpack扩展对应的loader就可以了。大部分loader我们都可以在webpack官网找到,并且学习使用方法。
loader使用过程:
步骤一:通过npm安装loader
步骤二:在webpack.config.js中的modules关键字下进行配置
css-loader 解析 CSS 文件后,使用 import 加载,并且返回 CSS 代码
npm install css-loader –save-dev
style-loader 将模块的导出作为样式添加到 DOM 中
npm install style-loader –save-dev
npm install file-loader@1.1.5 –save-dev
npm install –save-dev babel-loader@7.1.5 babel-core@6.26.3 babel-preset-es2015@6.24.1 webpack
npm install vue@2.6.12 –save
bundle.js:1328 [Vue warn]: You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.
(found in
runtime-only 代码中不可以有任何template
runtime-compiler 代码中,可以有template,因为有compiler可以用于编译template
import Vue from 'vue' new Vue({ el: "#app", template: ` <div> <h2>{{message}}</h2> <button @click="btnClick">按钮</button> </div>`, data: { message: "我是中国人" }, methods: { btnClick() { alert('btnClick') } } }) const App = { template: ` <div> <h2>{{message}}</h2> <button @click="btnClick">按钮</button> </div>`, methods: { btnClick() { alert('btnClick') } }, data() { return { message: "我是中国人" } } } import Vue from 'vue' new Vue({ el: "#app", template: '<App/>', components: { App } }) |
npm install –save-dev vue-loader@15.4.2 vue-template-compiler@2.5.21
ERROR in ./src/vue/App.vue
vue-loader was used without the corresponding plugin. Make sure to include VueLoaderPlugin in your webpack config.
npm install –save-dev html-webpack-plugin@2.30.1
npm install –save-dev uglifyjs-webpack-plugin@1.1.1
npm install webpack-dev-server@2.9.0 –save-dev
npm install webpack-merge –save-dev
脚手架
npm install -g @vue/cli 拉取 2.x 模板 (旧版本) npm install -g @vue/cli-init 脚手架2.x创建项目 vue init webpack my-project |
runtime-compiler
template -> ast -> render -> vdom -> UI
如果在之后的开发中,你依然使用template,就需要选择Runtime-Compiler
runtimeonly(性能更高代码量更少)
render -> vdom -> UI
如果你之后的开发中,使用的是.vue文件夹开发,那么可以选择Runtime-only
vue-router.esm.js?fe87:2065 Uncaught (in promise) NavigationDuplicated: Avoided redundant navigation to current location: “/profile”.
Vue.use(Router)
// Avoided redundant navigation to current location 避免重复点击一个路由
const originalReplace = Router.prototype.replace; Router.prototype.replace = function replace(location) { return originalReplace.call(this, location).catch(err => err); }; |
npm install postcss-px-to-viewport –save-deve
postcss.config.js
vue.runtime.esm.js?2b0e:619 [Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop’s value. Prop being mutated: “currentIndex”