模板內能夠放表達式,可是設計它們的初衷是用於簡單運算的。在模板中放入太多的邏輯會讓模板太重且難以維護。例如:html
<div id="example"> {{ message.split('').reverse().join('') }} </div>
因此,對於任何複雜邏輯,都應當使用計算屬性。前端
<div id="example"> <p>Original message: "{{ message }}"</p> <p>Computed reversed message: "{{ reversedMessage }}"</p> </div>
computed: { // 計算屬性的 getter reversedMessage: function () { // `this` 指向 vm 實例 return this.message.split('').reverse().join('') } }
computed計算屬性實質上就是對模版語法的增強,可讓咱們編寫更爲複雜的邏輯。
傳入的靜態屬性會綁定在組件內最外層元素上vue
<blog-post title="My journey with Vue"></blog-post>
數字、字符串、對象、數組等node
<blog-post v-bind="post"></blog-post>
<a @select="selectItem"></a>
├── src │ ├── const │ │ ├── const.js │ │ │ └── main.js └── ...
在 const.js 文件下,設置常量react
// const.js export default { install(Vue,options){ Vue.prototype.global = { title:'全局', isBack: true, isAdd: false, }; } }
引入webpack
//引入全局常量 import constant from './const/const.js' Vue.use(constant);
而後咱們就能夠在任何地方使用了web
//經過js方式使用: this.global.title //或在 html 結構中使用 {{global.title}}
一、計算屬性必須返回值
二、計算屬性是基於他的依賴來自動執行的,只有當依賴屬性發生變化了,它纔會從新計算
三、method能夠不須要返回值,它依賴事件的調用,不會自動執行
四、當你在抉擇的時候,你要注意你是否須要緩衝數據,若是須要那你就使用計算屬性。面試
一般咱們自定義一些指令是知足咱們對DOM操做的需求Vue裏面有許多內置的指令,好比v-if和v-show,這些豐富的指令能知足咱們的絕大部分業務需求,不過在須要一些特殊功能時,咱們仍然但願對DOM進行底層的操做,這時就要用到自定義指令。vue-router
自定義指令的幾個鉤子函數:express
鉤子函數的參數:
name:指令名,不包括 v- 前綴。
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 }。
vnode:Vue 編譯生成的虛擬節點。
<div id="hook-arguments-example" v-demo:foo.a.b="message"></div>
Vue.directive('demo', { bind: function (el, binding, vnode) { var s = JSON.stringify el.innerHTML = 'name: ' + s(binding.name) + '<br>' + 'value: ' + s(binding.value) + '<br>' + 'expression: ' + s(binding.expression) + '<br>' + 'argument: ' + s(binding.arg) + '<br>' + 'modifiers: ' + s(binding.modifiers) + '<br>' + 'vnode keys: ' + Object.keys(vnode).join(', ') } }) new Vue({ el: '#hook-arguments-example', data: { message: 'hello!' } })
Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,讓構建單頁面應用變得易如反掌。
// router.js import Vue from "vue"; import Router from "vue-router"; // 【1】引入router import Home from "./views/Home.vue"; // 組件引入 Vue.use(Router); // 【2】使用 // 【3】new Router(param) // param 是一個路由配置對象 export default new Router({ routes: [ { path: "/", name: "home", component: Home }, { path: "/about", name: "about", // 懶加載 component: () => import(/* webpackChunkName: "about" */ "./views/About.vue") } ] });
引入路由配置
// main.js import Vue from "vue"; import App from "./App.vue"; import router from "./router"; // 【1】引入 new Vue({ router, // 【2】綁定路由 render: h => h(App) }).$mount("#app");
// app.vue <template> <div id="app"> <router-link to="/">首頁</router-link> <router-link to="/about">Abour</router-link> <p> <router-view></router-view> </p> </div> </template> <script> export default { name: "APP", data () { return { } } }; </script>
這樣就能夠實現簡單的路由切換。
經過Home組件來區分$route和$router的區別:
<template> <div class="home"> Home <button @click="goBack">返回</button> </div> </template> <script> export default { name: "home", mounted () { console.log(this.$route); }, methods: { goBack() { this.$router.go(-1); } } }; </script>
this.$router來訪問路由器,進行一些路由跳轉等操做。this.$route能夠拿到當前路由信息。
好比: this.$router.go(-1);
來實現回退,console.log(this.$route);
來查看當前路由。
咱們能夠在this.$route中拿到路由信息,好比一些參數和查詢條件等。
vue-router提供了params、query、meta三種頁面間傳遞參數的方式。
// 字符串,不帶參數 /home this.$router.push('home') // 對象,不帶參數 /home this.$router.push({ path: 'home' }) // params(推薦):命名的路由,params 必須和 name 搭配使用 /user/123 this.$router.push({ name:'user',params: { userId: 123 }}) // 這裏的 params 不生效 this.$router.push({ path:'/user',params: { userId: 123 }}) // query:帶查詢參數,變成 /register?plan=private this.$router.push({ path: 'register', query: { plan: 'private' }}) //meta方式:路由元信息 export default new Router({ routes: [ { path: '/user', name: 'user', component: user, meta:{ title:'我的中心' } } ] })
//經過 $route 對象獲取,注意是route,麼有r this.$route.params this.$route.query this.$route.meta
咱們常常須要把某種模式匹配到的全部路由,全都映射到同個組件。例如,咱們有一個 User 組件,對於全部 ID 各不相同的用戶,都要使用這個組件來渲染。這時候咱們須要設置動態路由參數來實現:
{ // // 動態路徑參數 以冒號開頭 path: '/user/:id', name: 'user', component: User }
一個「路徑參數」使用冒號 : 標記。當匹配到一個路由時,參數值會被設置到 this.$route.params,能夠在每一個組件內使用。因而,咱們能夠更新 User 的模板,輸出當前用戶的 ID:
const User = { template: '<div>User {{ $route.params.id }}</div>' }
你能夠在一個路由中設置多段「路徑參數」,對應的值都會設置到 $route.params 中。例如:
注意點
當使用路由參數時,例如從/user/foo
導航到/user/bar
,原來的組件實例會被複用。由於兩個路由都渲染同個組件,比起銷燬再建立,複用則顯得更加高效。不過,這也意味着組件的生命週期鉤子不會再被調用。
使用watch監聽:
const User = { template: '...', watch: { '$route' (to, from) { // 對路由變化做出響應... } } }
<template> <div class="user"> <h1>This is an user page</h1> <p>{{$route.params.id}}</p> <router-link to="/user/22">去22</router-link> </div> </template> <script> export default { created() { console.log("created"); }, // 使用導航守衛 beforeRouteUpdate (to, from, next) { // react to route changes... // don't forget to call next() console.log(to, from , next); } } </script>
若是咱們想實現/user/12/more或者是user/userother這類的路由,並且要在user組件下去動態匹配內容的顯示。這時候就可使用咱們的嵌套路由。
const router = new VueRouter({ routes: [ { path: '/user/:id', component: User, children: [ { // 當 /user/:id/profile 匹配成功, // UserProfile 會被渲染在 User 的 <router-view> 中 path: 'profile', component: UserProfile }, { // 當 /user/:id/posts 匹配成功 // UserPosts 會被渲染在 User 的 <router-view> 中 path: 'posts', component: UserPosts } ] } ] })
這時候對咱們的User組件也須要作必定的處理,添加一個<router-view></router-view>
const User = { template: ` <div class="user"> <h2>User {{ $route.params.id }}</h2> <router-view></router-view> </div> ` }
這時候咱們匹配/user/12/profile
這些都是能夠的了~
觸發跳轉能夠是:
<router-link :to="'/userprofile'+ $route.params.id +'/'"></router-link> // 或者是 <router-link :to="profile" append></router-link>
若是沒匹配到,咱們想要讓他顯示一個提示性的頁面的時候,在怎麼作呢?
定義一個空白子路由,若是匹配不到路由會匹配該路由。
const router = new VueRouter({ routes: [ { path: '/user/:id', component: User, children: [ // 當 /user/:id 匹配成功, // UserHome 會被渲染在 User 的 <router-view> 中 { path: '', component: UserHome }, // ...其餘子路由 ] } ] })
有時候咱們須要js去動態的跳轉路由,編程式路由很合適。
在 Vue 實例內部,你能夠經過 $router 訪問路由實例。所以你能夠調用 this.$router.push。這個方法會向 history 棧添加一個新的記錄,因此,當用戶點擊瀏覽器後退按鈕時,則回到以前的 URL。
// 字符串 router.push('home') // 對象 router.push({ path: 'home' }) // 命名的路由,提供路由的名稱 router.push({ name: 'user', params: { userId: 123 }}) // 帶查詢參數,變成 /register?plan=private router.push({ path: 'register', query: { plan: 'private' }})
注意點: 若是提供了 path,params 會被忽略,上述例子中的 query 並不屬於這種狀況。取而代之的是下面例子的作法,你須要提供路由的 name 或手寫完整的帶有參數的 path:
const userId = 123 router.push({ name: 'user', params: { userId }}) // -> /user/123 router.push({ path: `/user/${userId}` }) // -> /user/123 // 這裏的 params 不生效,因此不要這麼寫 router.push({ path: '/user', params: { userId }}) // -> /user
router.replace(location, onComplete?, onAbort?)
跟 router.push 很像,惟一的不一樣就是,它不會向 history 添加新記錄,而是跟它的方法名同樣 —— 替換掉當前的 history 記錄。以後回退是不會回退回去的,由於history隊列中已經沒了
router.go(n)
這個方法的參數是一個整數,意思是在 history 記錄中向前或者後退多少步,相似 window.history.go(n)。
// 在瀏覽器記錄中前進一步,等同於 history.forward() router.go(1) // 後退一步記錄,等同於 history.back() router.go(-1) // 前進 3 步記錄 router.go(3) // 若是 history 記錄不夠用,那就默默地失敗唄 router.go(-100) router.go(100)
vue-router路由提供了兩種路由模式:hash模式和history模式。
hash模式
它是利用hash來模擬完整的Url,經過hashChange來監聽hash變化,當頁面變化的時候不會刷新頁面。
history模式
若是不想要很醜的 hash,咱們能夠用路由的 history 模式,這種模式充分利用 history.pushState API 來完成 URL 跳轉而無須從新加載頁面。
//設置mode屬性,設置路由模式 const router = new VueRouter({ mode: 'history', routes: [...] })
不過這種模式要玩好,還須要後臺配置支持。由於咱們的應用是個單頁客戶端應用,若是後臺沒有正確的配置,當用戶在瀏覽器直接訪問 http://oursite.com/user/id 就會返回 404,這就很差看了。
vue-router提供了一些導航守衛來,控制咱們的路由跳轉和守衛導航。有多種機會植入路由導航過程當中:全局的, 單個路由獨享的, 或者組件級的。
全局守衛【全局前置守衛】
const router = new VueRouter({ ... }) router.beforeEach((to, from, next) => { // ... })
導航守衛是異步的,所以導航在守衛完成以前都是等待狀態,所以須要 咱們手動resolve.
next();必定要調用該方法來 resolve 這個鉤子
next(false): 中斷當前的導航。若是瀏覽器的 URL 改變了 (多是用戶手動或者瀏覽器後退按鈕),那麼 URL 地址會重置到 from 路由對應的地址。
next('/') 或者 next({ path: '/' }): 跳轉到一個不一樣的地址。當前導航中斷。
確保要調用 next 方法,不然鉤子就不會被 resolved。
路由獨享的守衛
const router = new VueRouter({ routes: [ { path: '/foo', component: Foo, beforeEnter: (to, from, next) => { // ... } } ] })
參數同全局前置守衛。
組件內守衛
const Foo = { template: `...`, beforeRouteEnter (to, from, next) { // 在渲染該組件的對應路由被 confirm 前調用 // 不!能!獲取組件實例 `this` // 由於當守衛執行前,組件實例還沒被建立 }, beforeRouteUpdate (to, from, next) { // 在當前路由改變,可是該組件被複用時調用 // 舉例來講,對於一個帶有動態參數的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉的時候, // 因爲會渲染一樣的 Foo 組件,所以組件實例會被複用。而這個鉤子就會在這個狀況下被調用。 // 能夠訪問組件實例 `this` }, beforeRouteLeave (to, from, next) { // 導航離開該組件的對應路由時調用 // 能夠訪問組件實例 `this` } }
使用場景:
beforeRouteEnter (to, from, next) { next(vm => { // 經過 `vm` 訪問組件實例 }) }
// 路由發生變化的時候 beforeRouteUpdate (to, from, next) { // just use `this` this.name = to.params.name next() }
這個離開守衛一般用來禁止用戶在還未保存修改前忽然離開。該導航能夠經過 next(false) 來取消。
beforeRouteLeave (to, from , next) { const answer = window.confirm('Do you really want to leave? you have unsaved changes!') if (answer) { next() } else { next(false) } }
導航被觸發。 在失活的組件裏調用離開守衛。 調用全局的 beforeEach 守衛。 在重用的組件裏調用 beforeRouteUpdate 守衛 (2.2+)。 在路由配置裏調用 beforeEnter。 解析異步路由組件。 在被激活的組件裏調用 beforeRouteEnter。 調用全局的 beforeResolve 守衛 (2.5+)。 導航被確認。 調用全局的 afterEach 鉤子。 觸發 DOM 更新。 用建立好的實例調用 beforeRouteEnter 守衛中傳給 next 的回調函數。
好長呀,感受記不住:
咱們來簡化如下,記住一些關鍵步驟。
本組件調用離開守衛 -- 全局的beforeEach -- 全局的before Resolve -- 導航確認,-- 調用全局的afterEach -- DOM更新 --