今天是2018年12月30,雖不是2018年的最後一天,可是倒是本身在2018年寫的最後一篇博客了,昨天下班在地鐵上閒來無事,翻起了關注的一些公衆號發的技術博文,裏面就提到寫博客的重要性,其實這樣的內容看了N多了,可是,裏面有一句感受說的很對,如今的博客變了味了,由於咱們能夠Ctrl+c、Ctrl+v,短短几秒鐘就是一遍幾千字的博文,真正本身寫出的博文須要花費很長的時間。說內心話,本身的博客中也有,大概有三分之一吧,忽然莫名的恐慌,由於極可能就是這三分之一的博客,就會掩蓋本身花費精力完成的其餘的博客,被別人冠上這麼一個標籤,這人也是一個充數的、裝大半蒜的傢伙。其實心裏已經一萬個草泥馬了,由於咱們都是人,說話說的好,一我的一直作好事,可是忽然有一天作了一件壞事,你們就定義這我的是壞人,好人難作啊,一樣的,寫博客亦如此。javascript
不感慨了,看到的小夥伴們支持一下,固然歡迎轉載,歡迎Ctrl+c,可是有一個請求,在文章的最上方請註明文章來源,很是感謝。css
接下來,說今天的正事,本篇博客的正事,Vue的進階篇,進階,談不上,也算是一點稍微不那麼基礎的基礎吧,更基礎的歡迎瀏覽本人的另外一篇博客Vue基礎篇html
老習慣,開始正文以前,先來了解一些必知必會的小知識點前端
1,組件和插件的區別(組件是一個項目的必須組成部分,而插件是沒必要須的,動態的,即插即用)vue
2,在一個項目中,一個文件以.開頭表示電腦系統的隱藏文件。java
3,在前端中,一個項目中的index文件或main文件,默認爲一個項目的入口node
備註:在vue-cli項目中會有一個包含不少包的文件,這個文件的文件名就是node_modules,還有一個.gitignore的文件,這個隱藏文件的意思就是git忽視的一個文件,打開這個文件,裏面的有這些內容:webpack
.DS_Store
node_modules
/dist
在這個文件中,咱們能夠配置當前項目一些忽略的文件,支持部分正則匹配。好比,node_modules項,若是項目上傳git,或者GitHub時,會自動忽略掉這個文件,因此咱們上傳到GitHub上的項目中是不包含這個node_modules文件的,這也是GitHub的一個侷限性,大的文件沒法上傳,致使咱們從GitHub上下載的一些開源的項目,並不能直接使用,對於vue的項目,還須要使用一個命令:npm install 將包含不少包的這個文件下載下來。ios
所以,咱們從GitHub上下載下來的vue的開源代碼,第一步就是運行一個命令:npm install (通常在當前目錄下) git
GitHub中,每一個開源文件都有一個文件READMI.md(markdown文件),這個文件中,會告訴咱們怎麼使用這個項目。
贈送的小技巧:另外的咱們在一個項目名中,看到帶有awesome的,表示一個生態系統,裏面在這個基礎上封裝了不少插件和模塊。
在vue中,一個.vue文件就是一個vue的組件。
一個標準的可重用的vue組件的格式:
<!--一個組件包含html、css、js--> <template> <!--組件的結構--> </template> <script> // 處理業務邏輯 export default {
name: "Vheader",
} </script> <style> /*頁面的樣式*/ </style>
備註:
1,在template模板中,必須有一個包裹的標籤。 須要注意的是:template不是一個標籤,是vue中的一個模板
2,在vue中,一個組件的命名規範是:首字母必須大寫,好比:全部的組件以「V」開頭。一個組件中的data(數據屬性)必須是函數,這個函數必須return一個對象。
3,在一個項目中的MP3文件,因爲webpack的打包編譯,是沒法直接引入到src中,因此導入MP3文件時,必須當作模塊來引入
import song1 from './assets/薛之謙 - 一半 [mqms2].mp3'
<audio src="song1" autoplay controls></audio>
總之,全部的靜態資源均可以做爲模塊導入 。
組件的引入很簡單 ,分三步:
1,導入組件 import Vheader from './components/Vheader.vue'
2,掛載組件 在export default 中 定義一個key爲components,值爲一個對象,這個對象中放着導入鍵值對;鍵爲變量名,值爲組件名,在es6中,鍵值相同時,能夠縮寫爲一個單一的值。
好比:components:{ Vheader }
3,在template模板中使用組件: <Vheader> </Vheader>
備註:在父組件中定義的樣式類,默認爲全局的樣式類,因此若是要保證自身元素的樣式,在子組件的style標籤中加入:scoped便可 <style scoped><style>
父子組件的傳值:
1,綁定自定義的屬性 : 在父組件中對應的子組件的模板上綁定屬性。
好比:<Vcontent :menu=「menus」><Vcontent> #menu爲定義的屬性名 menus爲數據屬性
2,在子組件中接收這個自定義的屬性,而且屬性必需要驗證 ,接收的屬性放在props中
好比:props:{ menu:Array } 備註:接收的變量名必須與自定義的變量名保持一致
3,這時子組件中的數據值就是這個對應的menu變量,咱們也能夠在數據屬性中從新賦值
好比:data(){ return { menus:this.menu } } #這時咱們在子組件用的值就是menus了
備註:這裏的this是指當前的子組件的Vue對象,Vue建立組件時:Vue.component()
1,在子組件中定義一個事件: 好比:在Vheader中定義一個點擊事件。
<template> <div class="header"> // 定義一個點擊事件 addOne <button @click="addOne">添加一個菜單</button> </div> </template> <script> export default { name: "Vheader", data(){ return { } }, methods:{ // 事件觸發自定義的事件 addOne(){ this.$emit('addMenu','酸菜魚'); #this.$emit(「自定義事件名」,「往父組件傳的值」) } } } </script> <style scoped> </style>
2,觸發自定義的事件,this.$emit("自定義的事件名","要向父組件傳的值") #備註:固定寫法,並且自定義的事件名必須與父組件中自定義的事件名一致
3,在父組件中對應的子組件模板中,定義好這個自定義事件,好比:<Vheader @addMenu="addHand"></Vheader>
並在對應的事件中,接收傳的值,並作相應處理。
methods:{
addHand(value){
this.menus.push(value); #接收傳的值,並將值添加到父組件的menus數組中
}
}
vue主作單頁面應用
好比:餓了麼、掘金、網易雲音樂、豆瓣、知乎等等
在vue中,能夠給每個單頁面(組件)配置一個路由,這個是由vue-router來控制的
首先,要在咱們的項目中下載安裝這個vue-router
npm install vue-router
若是在一個模塊化工程中使用它,必需要經過 Vue.use()
明確地安裝路由功能:
在項目的入口 main.js中
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
接着就能夠在這個main.js中配置組件
1. 定義 (路由) 組件。
// 好比:
const Foo = { template: '<div>foo</div>' } const Bar = { template: '<div>bar</div>' }
// 也能夠從其餘文件 import 進來
import Vhome from './components/Vhome.vue' import Vuser from './components/Vuser.vue'
2. 定義路由
2. 定義路由每一個路由應該映射一個組件。 其中"component" 能夠是經過 Vue.extend() 建立的組件構造器,或者,只是一個組件配置對象。
每一個路由應該映射一個組件。 其中"component" 能夠是經過 Vue.extend() 建立的組件構造器,或者,只是一個組件配置對象。
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
]
3. 建立 router 實例,而後傳 `routes` 配置
// 你還能夠傳別的配置參數, 不過先這麼簡單着吧。
const router = new VueRouter({
routes // (縮寫) 至關於 routes: routes
}
4. 建立和掛載根實例。
// 記得要經過 router 配置參數注入路由,
// 從而讓整個應用都有路由功能
const app = new Vue({
router
}).$mount('#app')
如今,應用能夠啓動了!
Tips: 經過注入路由器,咱們能夠在任何組件內經過 this.$router
訪問路由器,也能夠經過 this.$route
訪問當前路由:
console.log(this.$router) #打印$router的結果:
[]
app:Vue {_uid: 0, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: Vue, …}
apps:[Vue]
beforeHooks:[]
fallback:false
history:HashHistory {router: VueRouter, base: "", current: {…}, pending: null, ready: true, …}
matcher:{match: ƒ, addRoutes: ƒ}
mode:"hash"
options:{routes: Array(2)}
resolveHooks:[]
currentRoute:(...)
__proto__:Object
點擊打開__proto__(父級中聲明的方法,在子級中均可以使用):
addRoutes:ƒ addRoutes(routes)
afterEach:ƒ afterEach(fn)
back:ƒ back()
beforeEach:ƒ beforeEach(fn)
beforeResolve:ƒ beforeResolve(fn)
forward:ƒ forward()
getMatchedComponents:ƒ getMatchedComponents(to)
go:ƒ go(n)
init:ƒ init(app /* Vue component instance */)
match:ƒ match( raw, current, redirectedFrom )
onError:ƒ onError(errorCb)
onReady:ƒ onReady(cb, errorCb)
push:ƒ push(location, onComplete, onAbort)
replace:ƒ replace(location, onComplete, onAbort)
resolve:ƒ resolve( to, current, append )
constructor:ƒ VueRouter(options)
currentRoute:(...)
get currentRoute:ƒ ()
__proto__:Object
console.log(this.$route) 打印$route的結果:
備註:$router中,push方法經常使用,在$route中,path(獲取當前訪問的路徑)和fullpath(獲取當前訪問的全路徑)方法經常使用
配置好了路由,接下來就該在HTML中使用了
<div id="app"> <h1>Hello App!</h1> <p> <!-- 使用 router-link 組件來導航. --> <!-- 經過傳入 `to` 屬性指定連接. --> <!-- <router-link> 默認會被渲染成一個 `<a>` 標籤 --> <router-link to="/foo">Go to Foo</router-link> <router-link to="/bar">Go to Bar</router-link> </p> <!-- 路由出口 --> <!-- 路由匹配到的組件將渲染在這裏 --> <router-view></router-view> </div>
備註:路由出口 --> 路由匹配到的組件將渲染在這裏 --> <router-view></router-view> 這是路由的出口
使用 router-link 組件來導航. -->經過傳入 `to` 屬性指定連接. --><router-link> 默認會被渲染成一個 `<a>` 標籤
注意:router-link和router-view也能夠放置在不一樣的子組件中
<router-view></router-view> 能夠簡寫成 <router-view/>
一個「路徑參數」使用冒號 :
標記。當匹配到一個路由時,參數值會被設置到 this.$route.params
,能夠在每一個組件內使用。因而,咱們能夠更新 User
的模板,輸出當前用戶的 ID:
const User = { template: '<div>User {{ $route.params.id }}</div>' }
你能夠在一個路由中設置多段「路徑參數」,對應的值都會設置到 $route.params
中。例如:
模式 | 匹配路徑 | $route.params |
---|---|---|
/user/:username | /user/evan | { username: 'evan' } |
/user/:username/post/:post_id | /user/evan/post/123 | { username: 'evan', post_id: 123 } |
除了 $route.params
外,$route
對象還提供了其它有用的信息,例如,$route.query
(若是 URL 中有查詢參數)、$route.hash
除了使用 <router-link>
建立 a 標籤來定義導航連接,咱們還能夠藉助 router 的實例方法,經過編寫代碼來實現。
router.push(location, onComplete?, onAbort?)
注意:在 Vue 實例內部,你能夠經過 $router
訪問路由實例。所以你能夠調用 this.$router.push
。
想要導航到不一樣的 URL,則使用 router.push
方法。這個方法會向 history 棧添加一個新的記錄,因此,當用戶點擊瀏覽器後退按鈕時,則回到以前的 URL。
當你點擊 <router-link>
時,這個方法會在內部調用,因此說,點擊 <router-link :to="...">
等同於調用 router.push(...)
。因此經過這個方法咱們能夠實現重定向的效果,
好比:登陸後跳轉到首頁,能夠把首頁的路徑push到$router中便可
聲明式 | 編程式 |
---|---|
<router-link :to="..."> |
router.push(...) |
該方法的參數能夠是一個字符串路徑,或者一個描述地址的對象。例如:
// 字符串
router.push('home')
// 對象
router.push({ path: 'home' })
// 命名的路由
router.push({ name: 'user', params: { userId: 123 }})
// 帶查詢參數,變成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
在使用動態路由或者編程式的路由時,會有這樣一個問題,路由切換後,頁面不切換,解決方法:
使用watch監聽路由的變化,並作數據的覆蓋處理
<template> // 兩種方式觸發切換
<!--方式一:經過點擊事件的切換--> <div v-for="(item,index) in theshow.recommend_courses" @click="toaimcourse(item)"><a href="javascript:vild(0);">{{item.title}}</a></div> <!--方式二:經過動態路由的切換--> <router-link v-for="(item,index) in theshow.recommend_courses" :to="{ name: 'coursedetail', params: { id:item.id }}">{{item.title}}</router-link> </template> <script> export default { name: "vcoursedetail", data(){ return { showdetail:this.$store.state.allCourseDetail, theshow:'', currcourse:'', courseall:this.$store.state.allCourse, descurl:'', charperurl:'' } }, created(){ this.courseshowdetail(this.$route.params.id); this.getcurrentcourse(this.$route.params.id); }, methods:{ courseshowdetail(nid){ for (var i=0;i<this.showdetail.length;i++){ if (this.showdetail[i].course.id === nid){ this.theshow = this.showdetail[i]; return this.showdetail[i] } } }, getcurrentcourse(nid){ for (var i=0;i<this.courseall.length;i++){ if (this.courseall[i].id === nid){ this.currcourse = this.courseall[i].title; this.descurl = "/course/coursedetail/"+nid; this.charperurl = '/course/coursedetail/'+nid+'/charper'; console.log(this.descurl,'文章摘要的url'); return this.courseall[i] } } }, toaimcourse(item){ this.$router.push({ name: 'coursedetail', params: { id:item.id }}) } }, computed:{ }, watch:{ "$route"(to,from){ this.courseshowdetail(to.params.id); this.getcurrentcourse(to.params.id); } } } </script>
咱們也能夠作一個全局的路由操做,好比:在每一個組件加載或者路由切換時,判斷有沒有登陸
詳情參考:https://router.vuejs.org/zh/guide/advanced/navigation-guards.html
beforeEach
守衛。beforeRouteUpdate
守衛 (2.2+)。beforeEnter
。beforeRouteEnter
。beforeResolve
守衛 (2.5+)。afterEach
鉤子。beforeRouteEnter
守衛中傳給 next
的回調函數。單個組件:
能夠在mounted方法中作攔截,經過判斷全局變量中的token值,來判斷有無登陸。
多個組件:能夠在全局作攔截
# 在main.js中配置
router.beforeEach(function (to,from,next) {
// meta 用於設置一個標識 因此必須在須要驗證是否登陸的組件中加一個meta參數 meta:{requireAuth:true}
if (to.meta.requireAuth){
// 表示此時路徑是要判斷是否登陸的
if (store.state.token){
next()
}else{
// query 用於給這個重定向路由設置一個參數 用於在登陸成功後重定向的路徑
// 設置此參數後須要在登陸成功後作一個判斷 this.$route.query.backUrl 獲取設置的參數
// 有值,表示是須要跳轉回的,而後經過重定向將取的值,定位便可
next({path:'/login',query:{backUrl:to.fullPath}})
}
}else{
next()
}
});
在項目中,使用bootstrap時,先在package.json中查看開發環境依賴:
"dependencies": {
"bootstrap": "^3.3.7",
"marked": "^0.4.0",
"vue": "^2.5.16",
"vue-router": "^3.0.1"
},
若是沒有,先在當前項目中 npm install xxx
配置好依賴後,再在須要的地方導入: 導入時,對於node_modules文件下的文件,直接導入便可。好比:import 'bootstrap/dist/css/bootstrap.min.css' 在vue-cli中,已經配置了路徑,因此直接導入便可。
備註:使用vue-router時,路由的切換會在路徑前默認加一個#/,顯得url很很差看,因此,能夠在實例router對象時加一個mode:"history"
const router = new VueRouter({
mode: 'history',
routes: [...]
})
在使用a標籤時,會有一個默認的跳轉事件,在vue中,咱們能夠在相應的事件後加一個.native用來阻止原生的默認事件
@click.native = "xxxx"
下圖展現了實例的生命週期。你不須要立馬弄明白全部的東西,不過隨着你的不斷學習和使用,它的參考價值會愈來愈高。
在vue的實例的生命週期中,vue爲咱們提供了八個方法:
beforeCreate(在建立以前)、created(建立時的初始化操做,創鍵的是虛擬DOM)、beforeMount、mounted(掛載,將虛擬DOM轉化爲真實DOM)、beforeUpdate、updated、beforeDestroy、destroyed(銷燬)
咱們經常使用的是 created和mounted這兩個方法,其中created方法適用於頁面的初始化操做,mounted適用於發送ajax請求數據的操做。
好比:切換路由,頁面樣式在在此刷新時會出錯,可使用created方法進行一些初始化操做
created(){ for (var i=0;i<this.routes.length;i++){ if (this.routes[i].src === this.$route.path){ this.current=i; return; } } },
在2x版本中:
在3x版本中:
在3x版本中,vue-cli不推薦咱們直接在模塊中修改配置
推薦這樣:在當前項目的目錄下直接建立一個js文件 ,文件名必須是 vue.config.js 的形式
在這個js文件中寫入:
module.exports = {
devServer: { open: process.platform === 'darwin', host: '0.0.0.0', port: 8088 , https: false, hotOnly: false, proxy: null, // 設置代理 before: app => {} } }
修改完成後重啓項目便可。
生產環境中,咱們都會講項目中的文件打包壓縮再上線,vue-cli中提供了一種快捷的打包方式。
在咱們項目的根目錄下運行 npm run build 就會將項目打包,打包後會在項目中多處一個文件夾dist,打開這個dist文件夾
備註:在項目中替換文件時,最好是先將原文件刪除,在拖進去,不要直接替換,放置文件合併
在打包時,必定要配置壓縮文件中的路徑參數。好比:前綴加/static/
vue中的全家桶:vue、vue-router、vuex構成了vue的全家桶,vue是MVVM的架構,vuex--->M vue--->V vue-router--->VM
Vuex 是一個專爲 Vue.js 應用程序開發的狀態管理模式。
補充:在vue中專門用來發送ajax請求的是axios,詳細用法參考:https://www.kancloud.cn/yunye/axios/234845
咱們能夠在全局的main.js或者store.js中定義一個axios ,將這個axios掛到vue的實例對象中,這樣,在vue的子對象中均可以經過this.$axios調用到axios對象。使用axios時,能夠經過返回的參數response.data取得返回的數據
import axios from 'axios'
import Vue from 'vue'
Vue.prototype.axios = axios
特別注意:使用jQuery的$.ajax發送post請求發送數據時,內部會自動轉化爲json字符串的形式發送到後端,而使用vue中的axios時,則不行,axios post提交數據時,發送的是普通的值,全部在使用axios發送數據時,若是後端須要json形式的字符串,則須要藉助一個模塊 qs (npm install qs) 轉化或者,JSON.stringfity
還有一個值得注意的地方,在vue的中,咱們能夠經過this拿到vue的實例對象,可是在axios中因爲做用域的緣由則不行,console.log(this)獲得的是一個undefined,因此咱們要在axios的外面聲明一個變量接收這個this var _this = this
vue中的mutation:更改 Vuex 的 store 中的狀態的惟一方法是提交 mutation。
使用vue-cli時,會在src文件夾下默認建立views、components的兩個文件夾,views中存放每個vue-router(路由)對應的視圖,components中存放父子嵌套的組件。
使用v-html指令時,若是咱們要獲取渲染的文本內容,能夠給當前標籤綁定一個屬性ref="變量名",而後在vue的實例中能夠經過this.$refs.變量名取得這個標籤,在經過DOM方法.innerText取得內容,this.$refs是一個對象
<div id="show" v-html="currentmsg" ref="mark"> // 這個div的文本內容爲: var content = this.$refs.mark.innerText;
備註:不要濫用ref,對性能有損耗,多個標籤時,可使用js方法或者jQuery方法獲取文本值 $("show").text()
Action 相似於 mutation,不一樣在於:
備註:mutation是同步的,action是異步的, action是用來提交的
用法:
mutation的用法:接收一個state參數做爲第一個參數,有其餘參數能夠直接跟在後面,在mutation的方法中能夠直接操做state中的數據,有多個參數時,最好能夠將其他的參數做爲一個對象,做爲方法的第二個參數傳值。
在vue的視圖中能夠直接this.$store.commit("方法名"),喚醒這個方法的執行
action的用法:接收一個context參數做爲第一個參數,一樣的,後能夠跟其餘參數,多個參數時,合併爲一個object對象。經過context.commit("mutation方法名") 提交, 能夠喚醒mutation中的方法
在vue的視圖中能夠經過this.$store.dispatch('action方法名'),觸發action中的對應方法執行
mutation和action的關係圖以下:
1.價格後面加上符號‘元’。
2.價格後面的單位也要動態的傳值。(如:元、¥、$)
代碼:
<!DOCTYPE html> <html > <head> <meta charset="UTF-8"> <title>過濾器</title> <script src="bli/vue.js"></script> </head> <body> <div id="app"> <input type="text" v-model="price"> <!-- {{ price | currency }} --> {{ price | currency('美圓') }} </div> </body> <script src="js/14.main.js"></script> </html>
// 過濾器 Vue.filter('currency',function(data,unit){ data = data || 0; // data有值就等於data,沒值就爲0. unit = unit || '元'; // unit有值就等於unit,沒值就爲'元'. return data + unit; // return data + '元'; }); new Vue({ el:'#app', data:{ price:10, }, });
3.毫米與米的轉換。
4.毫米與米的轉換,保留兩位小數。
1.自定義指令
2.給只爲true的元素定位(固定定位)
3.加一個按鈕,切換是否認位。
默認都是沒有定住的。點擊以後定住,再點擊以後就是取消定住。
默認、取消定住
定住
4.能夠給不少按鈕就加上。
默認、取消定位
定位
自定義指令-配置傳參及修飾符
以上例子只能定位到左上角,不夠靈活。位置應該動態傳參。
1.定位到右下角:
打印 var position = binding.modifiers;
console.log('position',position) // position {bottom: true, right: true}
運行結果:已定位到右下角
2.定位到左下角,只要改一個值便可。
3.讓一些卡片樣式有所不一樣,突出。
獲取該值(:true),設置樣式。
1.點擊切換顯示隱藏。
默認不顯示div.
點擊後顯示div,再次點擊有隱藏div.
2.鼠標移入、移出切換顯示隱藏。
默認、移出
移入:
3.點擊顯示的div應該有個能夠關閉的按鈕。
注意:這兩個組件有好多重複的代碼!
點擊後隱藏div
功能是同樣的。注意:本身寫的會覆蓋mixins的。
1.定義一個樣式
2.內容都是相同的。動態傳參(插槽)
3.若是頭部、底部都要動態傳參呢???定義name!!!
4.指定默認值。
在Vue的項目中使用了Vue-Router,當某個路由有子級路由時,以下寫法:
export default new Router({
routes: [
{
path: '/',
name: 'home',
component: Home,
children:[
{
path:'/',
name: 'console',
component: Console,
}
]
}
]
})
由於當某個路由有子級路由的時候,這時候父級路由須要一個默認的路由,因此父級路由不能定義name
屬性,SO解決辦法是:即去除父級的name
屬性便可。