vue基礎
template 是一個標籤可是在頁面不顯示 vue自帶的標籤
Vue.js(讀音 /vjuː/, 相似於 view)是一個構建數據驅動的 web 界面的漸進式MVVM框架。
設計模式(MVC/MVP/MVVM)的對比
MVC (Model View Controller ):
1.視圖(View):用戶界面。
2.控制器(Controller):業務邏輯
3.模型(Model):數據保存
MVC特色:
一、用戶能夠向 View 發送指令(DOM 事件),再由 View 直接要求 Model 改變狀態。
二、用戶也能夠直接向 Controller 發送指令,再由 Controller 發送給 View。
三、Controller 很是薄,只起到路由的做用,而 View 很是厚,業務邏輯都部署在 View。
MVP(Model View Presenter):
MVP 模式將 Controller 更名爲 Presenter,同時改變了通訊方向。
MVP特色:
一、各部分之間的通訊,都是雙向的。
二、View 與 Model 不發生聯繫,都經過 Presenter 傳遞。
三、 View 很是薄,不部署任何業務邏輯,稱爲"被動視圖"(Passive View),即沒有任何主動性,而 Presenter很是厚,全部邏輯都部署在那裏。
MVVM( Model-View-ViewModel ):
MVVM 模式將 Presenter 更名爲 ViewModel,基本上與 MVP 模式徹底一致。
MVVM特色:
惟一的區別是,它採用雙向綁定(data-binding):View的變更,自動反映在 ViewModel,反之亦然。VUE採用這種模式。
VUE初相識
Vue.js(讀音 /vjuː/, 相似於 view)是一個構建數據驅動的 web 界面的漸進式MVVM框架。正式發佈於2014年2月,2016年4月,發佈2.0版本,創造者-尤雨溪。
vue官網:https://cn.vuejs.org/
Vue的優勢:
一、性能好
二、簡單易用
三、先後端分離
四、單頁面應用(SPA)用戶體驗好,還能夠作轉場動畫
Vue的缺點:
一、不適合seo優化,解決方案服務端渲染(SSR)。
二、模板模式開發,封裝的比較厲害,代碼報錯信息不明確。
三、適合單人開發,適合中小型項目。
VUE數據驅動和雙向綁定
安裝vue
CDN引入:
對於製做原型或學習,你能夠這樣使用最新版本:
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
對於生產環境,咱們推薦連接到一個明確的版本號和構建文件,以免新版本形成的不可預期的破壞:
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
vue-cli3腳手架安裝:
npm install -g @vue/cli
建立項目:
vue create 項目目錄
初始化
<div id="app">
{{name}}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script>
new Vue({
el:"#app",//el根元素名稱
//初始化數據源方式一(推薦)
data(){
return {
name:"張三"
}
}
});
<div id="app">
{{name}}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script>
new Vue({
el:"#app",
//初始化數據源方式二
data:{
name:"張三"
}
});
data爲何要用一個方法而不用對象
由於vue是單頁面應用,是由多個組件組成的,每一個組件裏面都有data,若是data是個對象,對象是引用類型,一個組件裏面的data值改變了,其餘組件的值也都會改變,爲了不出現互相引用的問題,咱們要用方法來初始化數據造成一個做用域,防止各個組件互相引用
vue的數據驅動和雙向綁定
v-model:雙向綁定
v-cloak:解決加載閃爍時出現vue標籤或指令符號
雙向綁定的原理
實現雙向綁定的原理就是利用了 Object.defineProperty() 這個方法從新定義了對象獲取屬性值(get)和設置屬性值(set)的操做來實現的。
<input type="text">
<span id="text"></span>
let data={};
let val='';
let text=document.getElementById("text");
Object.defineProperty(data,"value",{
get:()=>{
return val;
},
set:(pVal)=>{
val=pVal;
text.innerHTML=pVal;
}
});
window.addEventListener("input",(e)=>{
data.value=e.target.value;
console.log(data.value);//若是get方法沒有返回值,獲取的是undefined
})
vue 中css樣式使用
在vue中使用css樣式:
普通寫法:
<div class=「box」></div>
對象語法:
<div :class=「{box:true,show:true}」></div>
數組語法:
<div :class=「[box,show]」></div>
內聯樣式
對象寫法:
<div :style=「{fontSize:’14px’,width:’100px;’,height:’100px’,badkgroundColor:’#FF0000’}」></div>
數組寫法:
<div :style=「[baseStyles, fonts]」></div>
data(){
return {
baseStyles:{
width:'100px',
height:'100px',
backgroundColor:'#FF0000'
},
fonts:{
fontSize:'14px',
color:'#FFFFFF'
}
}
}
模板語法與經常使用指令
v-cloak:防止閃爍解決顯示vue標籤
v-model:多用於表單元素實現雙向數據綁定
v-for:列表渲染
v-show:顯示內容
v-if:顯示與隱藏 (dom元素的刪除添加默認值爲false)
v-else-if:必須和v-if連用
v-else:必須和v-if連用 不能單獨使用 不然報錯 模板編譯錯誤
v-bind:動態綁定 做用: 及時對頁面的數據進行更改,縮寫:
v-html:解析html標籤
事件處理
v-on:click 給標籤綁定函數,能夠縮寫爲@,例如綁定一個點擊函數 函數必須寫在methods裏面
v-on:click.stop:阻止冒泡事件
v-on:click.once:點擊事件只容許一次
v-on:mouseover:鼠標移動元素上
v-on:mouseout:鼠標離開元素
v-on:mousemove:鼠標移動
v-on:touchstart:觸摸開始
v-on:touchmove:觸摸移動
v-on:touchend:觸摸結束
v-on:keyup:鍵盤事件
v-on:keyup.enter:回車鍵
computed計算屬性
computed用來監控本身定義的變量,該變量不在data裏面聲明,直接在computed裏面定義,而後就能夠在頁面上進行雙向數據綁定展現出結果,能夠作邏輯處理的變量。
舉例:購物車裏面的商品列表和總金額之間的關係,只要商品列表裏面的商品數量發生變化,或減小或增多或刪除商品,總金額都應該發生變化。這裏的這個總金額使用computed屬性來進行計算是最好的選擇。
<div id="app" v-cloak>
商品:html5
價格:{{price}}元
數量:<button type="button" @click="decrease()">減小</button>{{amount}}<button type="button" @click="increase()">增長</button>
金額:{{total}}元
</div>
new Vue({
el:"#app",
data(){
return {
amount:1,
price:10
}
},
computed:{
total(){
return this.amount*this.price
}
},
methods:{
//增長數量
increase(){
this.amount++;
},
//減小數量
decrease(){
if(this.amount>1){
this.amount--
}
}
}
});
watch監聽
watch主要用於監控vue實例的變化,它能夠監控一個data裏面的數據,computed,路由的變化。
特色:
一、監聽獲取兩個值一個是新值,另外一個是舊值
二、能夠深度監聽
三、能夠利用watch監聽路由的特性作轉場動畫
<div id="app" v-cloak>
<button @click="name='李四'">{{name}}</button>
<button @click="classify.title='品牌男裝'">{{classify.title}}</button>
<button @click="classify.children.title='下裝'" />{{classify.children.title}}</div>
</div>
new Vue({
el:"#app",
data(){
return {
name:"張三",
classify:{
title:"大媽女裝",
children:{
title:"上裝",
children:{
title:"韓都衣舍大媽女裝"
}
}
}
}
},
computed:{
getName(){
return this.name;
}
},
watch:{
//監聽data裏面的值
name(newVal,oldVal){
console.log("newVal:"+newVal,"oldVal:"+oldVal);
},
//監聽computed裏面的值
getName(newVal,oldVal){
console.log("computed-newVal:"+newVal,"computed-oldVal:"+oldVal);
},
//引用類型監聽
"classify.title"(newVal,oldVal){
console.log(newVal,oldVal);
},
//深度監聽
classify:{
handler(val){
console.log(JSON.stringify(val));
},
deep:true
}
}
});
全局組件
Vue.component(’組件名稱’,’組件’)
組件包括:
template
data
methods
生命週期鉤子函數
computed
watch
…….
//定義公共組件
let PublicComponent={
template:`
<div>
<span style="font-size:16px;color:#FF0000">我是公共組件</span>
</div>
`
};
//首頁
let HomePage={
template:`
<div>
我是{{name}}
<PublicComp></PublicComp>
</div>
`,
data(){
return {
name:"首頁"
}
}
};
//全局註冊組件
Vue.component("PublicComp",PublicComponent);
new Vue({
el:"#app",
//掛載要使用的模板
components:{
HomePage
},
//模板規範必須只能有一個惟一的根元素標籤
template:`
<div>
<PublicComp></PublicComp>
<HomePage></HomePage>
我是vue模板
</div>
`
});
全局filter過濾
Vue.filter("increase",function(value,num1,num2){
return parseInt(value)+parseInt(num1)+parseInt(num2);
});
var App={
data:function(){
return {
count:1
}
},
template:`<div>數量:{{count|increase(10,20)}}</div>`
};
局部filter過濾
var App={
data:function(){
return {
count:1
}
},
filters:{
formatDate:function(val){
if(val!==''){
val=val.split("-");
val=val[0]+"年"+val[1]+"月"+val[2]+"日"
}
return val;
}
},
template:`<div>日期:{{"2019-09-11"|formatDate}}</div>`
};
父子組件傳值
父組件給子組件傳值:
<ChildComponent title="我是子組件"></ChildComponent>
子組件用props接受:
第一種方式:
props:[‘title’] //數組方式接收
第二種方式(官方推薦):
props:{
title:{
type:String //數據類型
required:true //是否必須傳值,true:必須,false:可選
}
}
子組件給父組件傳值:
子組件代碼:
<button type="button" @click="sendParent()">給父組件傳值</button>
methods:{
sendParent(){
this.$emit("getChild","我是子組件傳過來的值");
}
}
父組件代碼:
<ChildComponent title=「我是子組件」 @getChild="getParent($event)"></ChildComponent>
methods:{
getParent(data){//接收父組件HomeComponent傳過來的值
console.log(data);
}
}
兄弟組件傳值
//定義一個總線bus
let bus=new Vue;
//A組件
let AComponent={
template:`
<div>
<button type="button" @click="sendB()">給B組件傳值</button>
</div>
`,
data(){
return {
}
},
methods:{
sendB(){
bus.$emit("getA","你好");//用$emit傳值
}
}
}
let BComponent={
template:`
<div>
A組件傳過來的值:{{text}}
</div>
`,
data(){
return{
text:""
}
},
created(){
//用$on接收
bus.$on("getA",(message)=>{
console.log(message);
this.text=message;
})
}
}
父組件與子組件實現雙向綁定
方法一:
父組件
new Vue({
el:"#root",
data(){
return{
value:」張三」
}
},
components:{Comp:component},
template:`<div><Comp v-model="value"></Comp>{{value}}</div>`
}
)
子組件
const component={
template:`
<div>
<input type="text" v-model="currentValue">
</div>
`,
props: {
// 接收一個由父級組件傳遞過來的值
value: {
type: String
}
},
created(){
console.log(this.value)//接收父組件的值
},
computed:{
currentValue: {
// 動態計算currentValue的值
get:function() {
return this.value; // 將props中的value賦值給currentValue
},
set:function(val) {
this.$emit('input', val); // 經過$emit觸發父組件
}
}
}
}
方法二:
父組件
new Vue({
el:"#root",
data(){
return{
name:"張三"
}
},
components:{Comp:component},
template:`
<div><Comp v-model="name"></Comp>{{name}}</div>
`
}
)
子組件
const component={
template:`
<div>
<input type="text" @input="changeName">
</div>
`,
model: {
prop:"name",//props裏面的name
event:"change"//$emit裏面的事件change
},
props: {
// 接收一個由父級組件傳遞過來的值
name: {
type: String
}
},
methods:{
changeName(e){
this.$emit("change",e.target.value);
}
}
}
ref的使用
<div class="box" ref="box1">box1</div>
<div class="box" ref="box2">box2</div>
<div class="box" ref="box3">box3</div>
console.log("當前:"+this.$refs.box1.innerHTML);
//父div
console.log("父div:"+this.$refs.box1.parentNode.innerHTML);
//下一個元素
console.log("下一個元素:"+this.$refs.box1.nextElementSibling.innerHTML);
//上一個元素
console.log("上一個元素:"+this.$refs.box2.previousElementSibling.innerHTML);
父組件調用子組件裏面的方法:
<ChildComponent ref="child"></ChildComponent>
一、給子組件加上ref=「child」
二、在父組件使用:
this.$refs.child.send();//send()就是子組件裏面的方法
Mixins混入
混入 (mixin) 提供了一種很是靈活的方式,來分發 Vue 組件中的可複用功能。
let base={
data(){
return {
visible:true
}
},
methods:{
toggle(){
this.visible=!this.visible
}
}
};
let Acomponent={
template:`
<div>
<button type="button" @click="toggle()">顯示/隱藏a組件</button>
<div v-show="visible">我是A組件</div>
</div>
`,
mixins:[base]
};
let Bcomponent={
template:`
<div>
<button type="button" @click="toggle()">顯示/隱藏b組件</button>
<div v-show="visible">我是b組件</div>
</div>
`,
data(){
return {
visible:true //覆蓋mixins裏面的visible
}
},
mixins:[base]
};
slot插槽
能夠獲取組件裏的內容。
應用場景:自定義組件使用,好比自定義button按鈕。
let ButtonComponent={
template:`
<button type="button" class="btn"><slot></slot></button>
`,
mounted:function(){
//獲取插槽裏的內容
if(this.$slots.default!=null){
console.log(this.$slots.default[0].elm.innerHTML);
}
},
};
new Vue({
el:"#app",
components:{
'my-button':ButtonComponent
},
template:`<div>
<my-button>提交</my-button>
</div>`
})
transition 過分/動畫
<transition name=「fade」>
<div class=「box」></div>
</transistion>
.fade-enter{ } 進入過渡的開始狀態,元素被插入時生效,只應用一幀後當即刪除。(運動的初始狀態)
.fade-enter-to{} (2.1.8版及以上) 定義進入過渡的結束狀態。
.fade-enter-active{ } 定義進入過渡生效時的狀態。在整個進入過渡的階段中應用,在元素被插入以前生效,在過渡/動畫完成以後移除。這個類能夠被用來定義進入過渡的過程時間,延遲和曲線函數。
.fade-leave{ } 離開過渡的開始狀態,元素被刪除時觸發,只應用一幀後當即刪除;
.fade-leave-to{} (2.1.8版及以上) 定義離開過渡的結束狀態。
.fade-leave-active{ } 定義離開過渡生效時的狀態。在整個離開過渡的階段中應用,在離開過渡被觸發時馬上生效,在過渡/動畫完成以後移除。這個類能夠被用來定義離開過渡的過程時間,延遲和曲線函數。
配合animate.css實現動畫效果:
animate官網:https://daneden.github.io/animate.css/
<button @click="isShow = !isShow">
Toggle render
</button>
<transition name="custom" enter-active-class="animated tada" leave-active-class="animated bounceInRight">
<div class="box" v-show="isShow"></div>
</transition>
data(){
return {
isShow:true
}
}
<transition-group name="slide">
<div class="banner-slide" v-show=」true" :key=」1"><img src=」1.jpg" alt=""></div>
<div class="banner-slide" v-show=」false" :key=」2"><img src=」2.jpg" alt=""></div>
</transition-group>
.slide-enter-active,.slide-leave-active{transition:all 1s;position:absolute;}
.slide-enter{
opacity:0;
}
.slide-enter-to{
opacity:1;
}
.slide-leave{
opacity:1;
}
.slide-leave-to{
opacity:0;
}
生命週期
beforeCreate:初始化以前
created:初始化完成(不能獲取dom,通常用於獲取ajax數據)
beforeMount:掛載以前
mounted:掛載完成以後
beforeUpdate:數據更新以前
updated:數據更新以後
beforeDestroy:解除綁定以前(頁面離開)
destroyed:解除綁定以後(頁面離開)
activated:keep-alive組件激活時調用。該鉤子在服務器端渲染期間不被調用。用於性能優化緩存dom和數據。
deactivated:keep-alive組件停用時調用。該鉤子在服務端渲染期間不被調用。
swiper插件和nextTick的使用
官網:https://www.swiper.com.cn/
nextTick:在下次 DOM 更新循環結束以後執行延遲迴調。在修改數據以後當即使用這個方法,獲取更新後的 DOM。
vue腳手架
安裝vue腳手架
npm install -g @vue/cli
卸載vue腳手架
npm uninstall vue-cli -g
查看版本號
vue -V
幫助建立項目
vue --help
建立項目
vue create 項目名稱
安裝第三方插件
之前安裝
npm install --save axios
如今能夠用
vue add axios
.env配置全局變量和區分開發者環境和生產環境
全局變量
在根目錄下面建立.env文件
內容:
VUE_APP_URL=http://vueshop.glbuys.com
注意命名規範:必須VUE_APP_開頭
開發者全局變量
在根目錄下建立.env.development文件
內容
VUE_APP_URL="http://vueshop.glbuys.com/api"
生產環境全局變量
在根目錄下建立.env.production文件
內容
VUE_APP_URL="https://vueshop.glbuys.com/api"
讀取值:
process.env.VUE_APP_URL
運行生成環境的文件
一、安裝serve服務器
npm install -g serve
二、運行方式一:
serve -s dist
運行方式二:
cd dist
serve
vue.config.js的配置
根目錄創建vue.config.js
在module.exports={}裏面配置
一、配置根目錄
publicPath:'/’
二、構建輸出目錄
outputDir:'dist'
三、 靜態資源目錄(js,css,image)
assetsDir:"assets"
四、是否開啓eslint檢測
lintOnSave:false //false不開啓,有效值:true || false
服務器配置:
devServer:{
open:false, //是否啓動打開瀏覽器
host:"localhost",//主機,0.0.0.0支持局域網地址,能夠用真機測試
port:8080, //端口
https:false,//是否啓動https
//配置跨域代理
proxy:{
"/api":{
target:"http://vueshop.glbuys.com/api",
changeOrigin:true,
pathRewrite:{
'^/api':""
}
}
}
}
mockjs的使用
mockjs的官網:http://mockjs.com/
mockjs是一個模擬json數據的測試工具。
安裝mockjs
npm install mockjs --save-dev
新建mork.js
import Mock from 'mockjs';
Mock.mock('/api/news',"get",{
'data|10':[
{
'id|+1':1,
'title|+1':Mock.Random.cword(8,20),
'image|+1':Mock.Random.image('200x100', Mock.Random.color()),
'date|+1':Mock.Random.date('yyyy-MM-dd')
}
]
});
});
導入mock.js
import "./js/mock.js";
$.ajax({
url:"/api/news",
type:"get",
dataType:"json",
success:function(res){
console.log(res.news);
}
}
})
eslint的使用 --和嚴格模式差很少
官網:http://eslint.cn
eslint的做用:
1. 提供編碼規範;
2. 提供自動檢驗代碼的程序,並打印檢驗結果:告訴你哪個文件哪一行代碼不符合哪一條編碼規範,方便你去修改代碼。
最經常使用的兩個命令:
/*eslint-disable*/ 禁用eslint檢測
/*eslint-enable*/ 開啓eslint檢測
移動端佈局及適配方式
viewport使用
<meta name="viewport" content="width=device-width,initial-scale=1.0, maximum-scale=1.0,user-scalable=no" />
width:設置layout viewport 的寬度,爲一個正整數,或字符串"device-width"
initial-scale:設置頁面的初始縮放值,爲一個數字,能夠帶小數
minimum-scale:容許用戶的最小縮放值, 爲一個數字,能夠帶小數
maximum-scale:容許用戶的最大縮放值,爲一個數字,能夠帶小數
height:設置layout viewport 的高度,這個屬性對咱們並不重要,不多使用
user-scalable:是否容許用戶進行縮放,值爲"no"或"yes", no 表明不容許,yes表明容許
format-detection使用
<meta name=「format-detection」 content=「telephone=no,email=no,date=no,address=no」 />
telephone:電話
eamil:郵箱
date:日期
address:地址
移動端如何作適配?
採用rem做爲佈局單位。
什麼是rem?
rem是CSS3新增的相對長度單位,是指相對於根元素html的font-size計算值的大小。
簡單可理解爲屏幕寬度的百分比。
rem與em的區別?
rem是針對根元素的html的font-size計算值大小計算的。
em是根據父元素的font-size大小計算的。
使用手淘flexible.js計算rem
好比:750px設計稿,那麼1rem=75px, div的高是50px ,50px換算成rem公式:
50px/75px=0.7rem;
解決1px細線問題
問題出現緣由:
在retina(視網膜)屏上面, devicePixelRatio(物理像素)這個值是2或3, 因此1px長度映射到物理像素上就有2px或3px那麼長。
解決方案:
viewport + rem 方案
<meta name=「viewport」 content=「initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no」 />
接下來的任務就是js的動態修改縮放比 以及 實現rem根元素字體大小的設置。
var viewport = document.querySelector("meta[name=viewport]");
if (window.devicePixelRatio == 1) {
viewport.setAttribute('content', 'width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no')
}
if (window.devicePixelRatio == 2) {
viewport.setAttribute('content', 'width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no')
}
if (window.devicePixelRatio == 3) {
viewport.setAttribute('content', 'width=device-width, initial-scale=0.333333333, maximum-scale=0.333333333, minimum-scale=0.333333333, user-scalable=no')
}
var docEl = document.documentElement;
var fontsize = 10 * (docEl.clientWidth / 320) + 'px';
docEl.style.fontSize = fontsize;
面試解答:
判斷devicePixelRatio物理像素若是爲1,設置viewport縮放大小爲1,若是爲2設置viewport縮放大小爲0.5,若是爲3設置viewport縮放大小爲0.33….。
自定義組件和axios與fetch的使用
自定義封裝組件
註冊組件
export default{
install(Vue){
Vue.component("my-button",Button);
}
}
使用組件
import Vue from 'vue';
import Button from '../components/button’
Vue.use(Button)
axios的介紹
axios是一款基於promise封裝的庫,能夠運行在瀏覽器端和node環境中。 vue官方開發組放棄了對其官方庫vue-resource的維護,直接推薦咱們使用axios庫。
官方文檔:https://github.com/axios/axios
一、get請求
二、post請求
三、使用URLSearchParams或qs作post提交處理
三、圖片上傳
使用URlSearchParams兼容ie
一、安裝url-search-params-polyfill
npm install url-search-params-polyfill --save
二、入口頁面導入url-search-params-polyfill
import 'url-search-params-polyfill';
fetch的介紹
fetch是ajax2.0,新的瀏覽器如今支持Fetch API,能夠無須其餘庫就能實現Ajax,使用的方式和axios差很少。
瀏覽器兼容性:
桌面瀏覽器
手機、平板電腦
fetch的使用
兼容低版本瀏覽器:https://github.com/github/fetch
安裝:npm install whatwg-fetch --save
引入:import fetch from 'whatwg-fetch'
一、get請求
二、post請求
三、使用URLSearchParams或qs作post提交處理
三、圖片上傳
fetch的get使用
fetch("/api/v1/news",{
method:"get"
}).then((res)=>{
return res.json();
}).then(res=>{
this.newsList=res.data;
});
fetch("/proxy/home/user/pwdlogin?token=1ec949a15fb709370f",{
method:"post",
headers:{
'Content-Type':"application/x-www-form-urlencoded"
}, body:"cellphone="+encodeURIComponent(this.username)+"&password="+encodeURIComponent(this.password)+""
}).then(res=>res.json()).then(res=>{
console.log(res);
})
fetch的文件上傳
let data=new FormData();
data.append("headfile",this.$refs["head"].files[0]);
fetch("/proxy/user/myinfo/formdatahead?token=1ec949a15fb709370f",{
method:"post",
body:data
}).then(res=>res.json()).then(res=>{
console.log(res);
});
vue的路由
安裝vue-router
npm install --save vue-router
路由嵌套
{
path:」/goods」,
component: ()=>import(‘./views/goods.vue’),
redirect:’/goods/info’,//頁面重定向
children:[//子路由
{
path:」info」,
component: ()=>import(‘./views/goods_info.vue’);
}
]
}
]
})
vue-router的配置
創建一個router.js文件,代碼以下:
import Vue from 'vue';
import Router from 'vue-router';//引用路由
import HomePage from './pages/index';
Vue.use(Router);//裝載路由
//路由實例化
let router=new Router({
mode:"hash", //一、hash哈希:有#號。二、history歷史:沒有#號
routes:[
{
path:"/",
name:"index",
component:HomePage
},
創建一個router.js文件,代碼以下:
import Vue from 'vue';
import Router from 'vue-router';//引用路由
import HomePage from './pages/index';
Vue.use(Router);//裝載路由
//路由實例化
let router=new Router({
mode:"hash", //一、hash哈希:有#號。二、history歷史:沒有#號
routes:[
{
path:"/",
name:"index",
component:HomePage
},
{
path:'/news',
name:"news",
component:()=>import("./pages/news")//路由懶加載
},
]
});
export default router;
動態路由
routes:[
{
path: '/news/:id',
name: 'news',
component: () => import('./views/News.vue'),
},
]
<router-link to=「/news/10">新聞頁面</router-link>
動態路由與接收參數
路由跳轉方式一:
<router-link to=「/about">About</router-link>
路由跳轉方式二:
this.$router.push({path:’/about’})
push進入跳轉歷史記錄
路由跳轉方式三:
this.$router.replace({path:’/about’})
replace不進入跳轉歷史記錄
路由傳參方式一:
<router-link to=「/about?id=10">About</router-link>
路由傳參方式二:
this.$router.push({name:’about’,params:{id:10}})
params:參數不顯示url地址上
路由傳參方式三(推薦):
this.$router.push({path:’/about’,query:{id:10}})
query:參數顯示在地址上
接收參數方式一:
this.$route.params.id
接收參數方式二(推薦):
this.$route.query.id
返回上一級:
this.$router.go(-1)
路由鉤子函數與路由認證
{
path:’/user/profile',
component: ()=>import(‘./user/profile.vue’),
meta: { title: '我的資料',auth:true }
}
auth:true表示這個頁面須要進行會員認證,auth就是一個標識。
路由守衛
beforeEach:全局前置守衛
const router = new VueRouter({ ... })
router.beforeEach(function (to, from, next) {
if(to.meta.auth){
if(Boolean(store.state.isLogin)==true){//已登陸
next();
}else{//未登陸
next({」/login/index"});
}
}else{
next()
}
});
beforeEnter:路由獨享的守衛(路由內鉤子)
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
//….
}
}
]
})
組件內的守衛-------組件內的鉤子
beforeRouteEnter (to, from, next) {
// 在渲染該組件的對應路由被 confirm 前調用
// 不!能!獲取組件實例 `this`
// 由於當守衛執行前,組件實例還沒被建立
},
beforeRouteUpdate (to, from, next) {
// 在當前路由改變,可是該組件被複用時調用
// 舉例來講,對於一個帶有動態參數的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉的時候,
// 因爲會渲染一樣的 Foo 組件,所以組件實例會被複用。而這個鉤子就會在這個狀況下被調用。
// 能夠訪問組件實例 `this`
},
beforeRouteLeave (to, from, next) {
// 導航離開該組件的對應路由時調用 // 能夠訪問組件實例 `this`
}
應用場景:
組件內的守衛(組件內鉤子)在實際的開發過程當中使用較少, 在實際的項目中beforeRouteLeave還算有用, 使用場景分別爲一下三類狀況:
(一) 清除當前組件中的定時器
當一個組件中有一個定時器時, 在路由進行切換的時候, 可以使用beforeRouteLeave將定時器進行清楚, 以避免佔用內存(能夠用destroyed生命週期鉤子函數代替):
beforeRouteLeave (to, from, next) {
window.clearInterval(this.timer) //清楚定時器
next()
}
(二) 當頁面中有未關閉的窗口, 或未保存的內容時, 阻止頁面跳轉
若是頁面內有重要的信息須要用戶保存後才能進行跳轉, 或者有彈出框的狀況. 應該阻止用戶跳轉。
beforeRouteLeave (to, from, next) {
if (this.isShow){
alert('必須關閉彈窗才能跳轉頁面');
next(false);
} else {
next();
}
}
(三) 保存相關內容到Vuex中或Session中
當用戶須要跳轉頁面時, 能夠將公用的信息保存到session或Vuex中(能夠用destroyed生命週期鉤子函數代替)。
beforeRouteLeave (to, from, next) {
localStorage.setItem(name, content); //保存到localStorage中
next()
}
history與hash模式的區別
hash模式:路由地址帶#號。適合作後臺管理系統
history模式:路由地址不帶#號。適合作前端宣傳頁面。可是history模式有個問題就是刷新頁面會出現404錯誤,解決方法須要配置服務器。
apache解決方案:
在根目錄下新建.htaccess文件,內容以下:
<IfModule mod_rewrite.c>
Options Indexes FollowSymLinks ExecCGI
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</IfModule>
nginx解決方案:
location / {
try_files $uri $uri/ /index.html;
}
Vuex狀態管理
Vuex 是一個專爲 Vue.js 應用程序開發的狀態管理模式。將數據分發給各個組件。
應用場景好比:購物車、會員登陸等須要跨頁面,跨組件實時傳遞數據的地方。
安裝vuex
vuex的使用
//導入vuex
import Vuex from 'vuex'
//啓用vuex
Vue.use(Vuex)
//實例化對象
let store=new Vuex.Store({
state:{}//初始化數據
mutations:{}//同步操做方法
actions:{}//異步操做,用於操做mutations裏面的方法,若是mutations裏面的方法操做量大最好寫在actions裏面。
getters:{}//有時候咱們須要從 store 中的 state 中派生出一些狀態,例如對列表進行過濾並計數
})
new Vue({
el: '#app',
router,
store,//掛載到vue裏使用
components: { App },
template: '<App/>'
})
state mutations actions gettters modules的介紹與使用
state:定義vuex的數據源。
state:{
total:0,
users:[
{id:1,name:"張三",age:18},
{id:2,name:"李四",age:20},
{id:3,name:"王五",age:22},
{id:4,name:"趙六",age:25}
]
}
頁面調用方式一:
this.$store.state.count
頁面調用方式二:
使用輔助函數
import { mapState } from 'vuex'
computed:{
...mapState({
total:state=>state.total
})
}
mutions :同步方式的方法提交,將改變的值賦給state數據源。
mutations:{
increment(state,payload){
state.total = payload.count;
}
}
mutions :同步方式的方法提交,將改變的值賦給state數據源。
mutations:{
increment(state,payload){
state.total = payload.count;
}
}
this.$store.commit(「increment」,{count:10});
輔助函數提交
import { mapMutations } from 'vuex’
methods: {
//方式一
...mapMutations([
'increment', // 將 `this.increment()` 映射爲 `this.$store.commit('increment')`
]),
//方式二
...mapMutations({
add: 'increment' // 將 `this.add()` 映射爲 `this.$store.commit('increment')`
})
}
actions :異步方式的方法提交,用於操做mutions裏面的方法,實際應用裏面獲取ajax異步數據。
actions:{
inc(conText,payload){
conText.commit("increment",payload);
}
}
輔助函數提交
import { mapActions } from 'vuex’
methods: {
//方式一
... mapActions ([
'increment', // 將 `this.increment()` 映射爲 `this.$store.commit('increment')`
]),
//方式二
... mapActions ({
add: 'increment' // 將 `this.add()` 映射爲 `this.$store.commit('increment')`
})
}
gettters :能夠認爲是 store 的計算屬性,相似於computed,例如對列表進行過濾並計數。
getters:{
getUsers(state){
let aUsers=state.users.filter((res)=>{
return res.age>18;
})
return aUsers;
}
}
this.$store.getters.getUsers
輔助函數
import {mapGetters} from 'vuex’
computed: {
//方式一
...mapGetters([
'getUsers'
]),
//方式二
...mapGetters({
getUsers:'getUsers'
})
}
modules: 將 store 分割成模塊(module)。每一個模塊擁有本身的 state、mutation、action、getter。
const moduleA = {
namespaced:true,//命名空間
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: { ... },
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的狀態
store.state.b // -> moduleB 的狀態
熱門的ui庫的使用
自定義指令
// 註冊一個全局自定義指令 `v-focus`
Vue.directive('focus', {
// 當被綁定的元素插入到 DOM 中時……
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
<input type=「text」 placeholder=「用戶名」 v-focus />
// 註冊一個局部指令 `v-position`
directives:{
position:{
bind:(el,binding)=>{
el.style.position="absolute";
el.style[binding.arg]=binding.value+"px";
}
}
}
<div v-position:left="'200'" class="box"></div>
鉤子函數
bind:只調用一次,指令第一次綁定到元素時調用。在這裏能夠進行一次性的初始化設置。
inserted:被綁定元素插入父節點時調用 (僅保證父節點存在,但不必定已被插入文檔中)。
update:所在組件的 VNode 更新時調用,可是可能發生在其子 VNode 更新以前。指令的值可能發生了改變,也可能沒有。可是你能夠經過比較更新先後的值來忽略沒必要要的模板更新 (詳細的鉤子函數參數見下)。
鉤子函數參數
name:指令名,不包括 v- 前綴。
binding裏面的參數:
value:指令的綁定值,例如:v-my-directive="1 + 1" 中,綁定值爲 2。
oldValue:指令綁定的前一個值,僅在 update 和 componentUpdated 鉤子中可用。不管值是否改變均可用。
expression:字符串形式的指令表達式。例如 v-my-directive="1 + 1" 中,表達式爲 "1 + 1"。
arg:傳給指令的參數,可選。例如 v-my-directive:foo 中,參數爲 "foo"。
modifiers:一個包含修飾符的對象。例如:v-my-directive.foo.bar 中,修飾符對象爲 { foo: true, bar: true }。
Mint-ui官網:http://mint-ui.github.io
Mint-ui介紹: Mint UI 包含豐富的 CSS 和 JS 組件,可以知足平常的移動端開發須要。經過它,能夠快速構建出風格統一的頁面,提高開發效率。
Element-ui官網: https://element.eleme.cn
Element-ui介紹:一套爲開發者、設計師和產品經理準備的基於 Vue 2.0 的桌面端組件庫。
Better-Scroll的使用
Better-Scroll官網:http://ustbhuangyi.github.io/better-scroll/doc/api.html
better-scroll 是一款重點解決移動端(已支持 PC)各類滾動場景需求的插件。它的核心是借鑑的 iscroll 的實現。
一、實現下拉刷新。
二、實現上拉加載數據
服務器渲染與Nuxt.js
Nuxt.js 是一個基於 Vue.js 的通用應用框架,利用 Vue開發服務端渲染的應用所須要的各類配置。解決vue不支持SEO優化的問題。
確保安裝了npx(npx在NPM版本5.2.0默認安裝了):
$ npx create-nuxt-app <項目名>
或者用yarn :
$ yarn create nuxt-app <項目名>
head配置:
head: {
title: process.env.npm_package_name || '',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1,maximum-scale=1.0,user-scalable=no' },
{
hid: 'description',
name: 'description',
content: process.env.npm_package_description || ''
},
{
name:"keywords",
content:"大碼女裝,好運買"
},
{
name:"description",
content:"好運買大碼女裝品牌網爲胖mm精選優質大碼女裝品牌旗艦店,是您身邊的專屬衣櫥,介紹各類流行的特大加肥加大時尚大碼女裝品牌,以及韓版大碼女裝,外貿大碼女裝,幫助胖妹妹儘快找到合適的服裝。"
},
{
name:"format-detection",content:"telephone=no,email=no,date=no,address=no"
}
],
link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }],
//引入手淘flexible.js
script: [{ src: './js/flexible.js', type: 'text/javascript', charset: 'utf-8'}]
},
全局CSS配置:
css: ['element-ui/lib/theme-chalk/index.css','./assets/css/common/public.css']
自定義插件配置:
plugins: [{src:'@/plugins/element-ui',ssr: true},'@/plugins/request'],
全局變量配置:
env: {
//ajax接口地址
baseUrl: process.env.NODE_ENV=='production'?"https://vueshop.glbuys.com/api":"/api",
//根目錄
basePath:"/",
token:"1ec949a15fb709370f"
},
配置代理解決跨域問題:
proxy: {
'/api': {
target: 'https://vueshop.glbuys.com/api', // 目標接口域名
pathRewrite: {
'^/api': '', // 把 /api 替換成 空
changeOrigin: true // 表示是否跨域
}
}
},
遠程服務器部署上線
阿里雲服務器官網: https://www.alibabacloud.com
阿里雲是阿里巴巴集團(紐交所代碼:BABA)旗下的子公司。經過提供全面完善的全球雲計算服務。
nginx下載地址:http://nginx.org/en/download.html
目前最流行最火的web服務器有:Apache、Nginx。
Nginx (engine x) 是一個高性能的HTTP和反向代理web服務器,同時也提供了IMAP/POP3/SMTP服務。
支持:php、nodejs、直播推流等。
使用nginx配置代理exproess服務器
一、啓動express服務器
supervisor app.js
http://localhost:300
二、nginx配置反向代理
打開nginx.conf
server {
listen 1920;
server_name localhost;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-Nginx-Proxy true;
proxy_set_header Connection "";
proxy_pass http://localhost:3003;
}
}