從如下幾個方面整理:html
new Vue({ data(){ return { name:'xx' } } }) // 常編寫的.vue文件 export default { data(){ return { name:'xx' } } }
<template> <div> test component </div> </template> <script> export default {} </script>
// main.js import Vue from 'vue'; import TestComp from './TestComp.vue' Vue.component('test-comp',TestComp);
以上 main.js 中也能夠經過 Vue.use 註冊,其實實質仍是調用 Vue.Component,對應的 use 的須要有一個 install 函數,使用 Vue.use 將觸發 install 執行,而後在 install 中執行 Vue.component 操做。
// my-components.js import TestComp from './TestComp.vue' export default { install(Vue){ Vue.component('test-comp',TestComp) // 這裏還能夠有多個註冊 vue.component vue.directive, vue.filter 等 } } // main.js import Vue from 'vue'; import MyComponents from './my-components.js'; Vue.use(MyComponents)
/* 一、 註冊指令 */ Vue.directive('') /* 二、註冊過濾器 */ Vue.filter('filterName',(val,...args)=>{ console.log(args); return val; }) // 過濾器使用 {{ 'abc' | filterName(1,2,3) }} // value = 'abc' args 爲 [1,2,3] /* 三、全局 mixin (不建議) */ Vue.mixin({ mounted(){ console.log('每一個組件中都將執行這裏') } })
<keep-alive :incude="['home','list']" :max="3"> <router-view></router-view> </keep-alive>
// Bus.js import Vue from 'vue' export const Bus = new Vue() // a.vue import Bus from './bus.js' Bus.$emit('event_add_cart',1) // b.vue import Bus from './bus.js' Bus.$on('event_add_cart',(num)=>{ this.cartNum += num })
a.vue 和 b.vue,引用 bus.js ,Bus 爲同一個實例,並不會重複建立,bus.js 就至關於一個調度中心,能夠無數個組件,都和它創建連接,發佈事件,而後 bus 將發佈到給每個創建連接的組件。
<template> <div> <template v-for="(item,index) in [1,2,3]"> <div :key="index"> {{item}} </div> </template> <template v-if="2>1"> <div> 2大於1 </div> <div> 2>1 </div> </template> </div> </template>
<template> <div> {{info.name}} {{info.age}} <div v-for="(item,index) in arr" :key="index">{{item}}</div> </div> </template> <script> export default { data(){ return { info:{ age:1 }, arr:[], } }, mounted(){ this.info.name = 'xx'; // 並不能觸發頁面更新 this.info.age = 2; // 這樣子能夠觸發頁面更新 this.info = {name:'xx'}; // 這樣子能夠觸發頁面更新 // 數組同理 this.arr[0] = 1; // 並不能觸發頁面更新 this.arr = [1]; // 這樣子能夠觸發頁面更新 } } </script>
由於 Vue 在初始化時須要對 data 進行使用 defineProperty 進行 set 和 get 的劫持,若是對象中的值爲空,那就不會存在相應的 set 和 get,因此二者方式,一個給對象裏面設置初值,二個將對象改成一個新對象,而不是直接在上面添加屬性和值。
基於以上,還有一個使用技巧,則是,一些表單若是依賴後臺返回的一些數據初始化選擇列表等,那麼能夠在賦值前,先在返回的數組中,加上一個屬性,例如 isChecked,而後再賦值給 datavue
<template> <div> <template v-for="(item,index) in checkboxs"> <input type="checkbox" v-model="item.isChecked" :key="index"> </template> </div> </template> <script> export default { data(){ return { checkboxs:[] } }, methods:{ getData(){ // 請求過程略 let data = [{name:'zs',name:'ls'}] // 原請求返回數據 this.checkboxs = data.forEach(item=>Object.assign(item,{isChecked:false})) } } } </script>
// child.vue <template> <header> <slot>all header</slot> </header> </template> // parent.vue <template> <child> <div>this is custom header</div> </child> </template>
slot 中能夠有默認值
// child.vue <template> <header> <slot name="left">left</slot> <slot name="right">right</slot> </header> </template> // parent.vue <template> <child> <div slot="left">custom left</div> <div slot="right">custom right</div> <div slot="right">custom right2</div> </child> </template>
具名插槽能夠有一個以上一樣 name 的填充。注意組件中用 slot + name ,使用時用 slot=name ,這裏容易搞混。
// child.vue <template> <header> <slot :user="userinfo" :address="address"></slot> </header> </template> <script> export default { data() { return { userinfo: { name: 'haokur' }, address: { city: 'guangzhou' }, } }, } </script> // parent.vue <template> <div> <Child> <template slot-scope="row"> {{JSON.stringify(row)}} => {"user":{"name":"haokur"},"address":{"city":"guangzhou"}} </template> </Child> </div> </template>
// List.vue <template> <ul class="table"> <li class="row" v-for="(item,index) in dataList" :key="index"> <slot :row="item"> {{item}} </slot> </li> </ul> </template> <script> export default { props: ['dataList'], } </script> /// parent.vue <template> <div> <TestList :dataList="[1,2,3,4,5,6]"> <template slot-scope="scope"> {{ scope.row * 2 }} </template> </TestList> </div> </template>
因而就實現了,子組件反向又像父組件傳遞值
<template> <div> <span v-once>{{dateNow}}</span> <span>{{dateNow}}</span> </div> </template> <script> export default { data(){ return { dateNow: Date.now() } }, mounted(){ setInterval(() => { this.dateNow = Date.now() }, 1000) } } </script>
測試可看到只有沒有加 v-once 的時間在變。
<script> export default { created(){ this.name = 'hello'; setTimeout(() => { this.name = 'haokur' }, 0) }, mounted(){ // this.name = 'xiao' //setTimeout(() => { // this.name = 'haokur' //}, 0) }, render(h){ console.log('執行渲染',this.name) return h('div',{},this.name) } } </script>
以上測試可知, 執行渲染 將進行兩次,也就是再快的數據返回,也是要進行兩次 render 的。由於請求和setTimeout 同樣都是異步的,因此它的執行結果是在事件隊列中等着的,而 render 是當前執行棧中的同步方法,它是執行在事件隊列中的方法以前的。註釋 created,放開mounted ,render 方法則會執行三遍。webpack
可是 created 和 mounted 中直接賦值則是有差異的,由於 render 會發生在 mounted 以前一次。也就是初始化時,created =》render =》 mounted =》(如有更改,再次 render) =》 請求返回 =》 再次 rendergit
因此最佳的處理方式是,同步更改數據的,放 created 中,這樣一些初值在第一次渲染就能正確呈現,且比在 mounted 中少執行一遍 render ,異步更改的無所謂。github
// UserItem.js <template> <li>this is useritem</li> </template> // container.js <template> <ul> <li is="user-item"></li> </ul> </template> <script> import UserItem from './UserItem.js' export default { components:{ 'user-item':UserItem } } </script>
import Vue from 'vue' import VueRouter from 'vue-router' import App from './app.vue' import Home from './home.vue' Vue.use(VueRouter); // 註冊 router-view,router-link 組件 new Vue({ el:'#app', router:new VueRouter({ routes:[ path:'/home', component:Home ] }), render:h=>h(App) })
以上僅是簡單使用,在實際項目中,能夠將 new VueRouter() 路由配置提出去,而後入口頁引入。
// router.config.js export const RouterConf = new VueRouter({ mode:'hash', // hash 默認,切換使用 # 模式,#/home; history 沒有 # ,須要服務器配合;abstract 暫未知 routes:[ path:'/home', component:Home ] }) // 以上還能夠把 routes 的值數組單獨提出去放一個文件 // main.js import { RouterConf } from './router.config.js' new Vue({ router:RouterConf })
// 接上面👆代碼,router.config.js import RouterConf from './router.config.js'; // to ,將要跳轉的地址信息;now,如今的路由配置信息;next 執行跳轉的方法,next(false)和沒有next頁面都將不跳轉,能夠 next('/login') 驗證用戶是否登陸而後跳轉登陸,也能夠 next(false) 阻止用戶進入沒有權限的頁面。 RouterConf.beforeEach((to,now,next)=>{ let token = localStorage.getItem('token') if(!token && to.name!=='login'){ // 防止路由登陸頁也一直跳轉登陸頁 next('/login') } else{ next(); } })
import Vue from 'vue'; // 接上面👆代碼,router.config.js import RouterConf from './router.config.js'; // now 表示當前路由配置對象,from 表示上一個路由配置對象 RouterConf.afterEach((now,from)=>{ document.title = now.meta.pageTitle; // 若是須要在頁面渲染完以後處理一些事情 Vue.nextTick(()=>{ window.scroll(0,0); }) })
<script> // home.vue export default { mounted(){ console.log('home mounted') }, beforeRouteUpdate(to,from,next){ next(); }, beforeRouteEnter(to,from,next){ next(); }, beforeRouteLeave(to,from,next){ // 能夠彈個窗提示,用戶是否確認離開,確認才離開當前頁面,更嚴謹一點,須要判斷是日後退仍是push新頁面提交等等具體狀況具體分析使用 let confirmStatus = this.confirmStatus confirmStatus && next(); }, } </script>
切記beforeRouteUpdate,beforeRouteLeave,都須要手動調 next 纔會進行下一步跳轉。beforeRouteUpdate 暫未遇到什麼使用場景。
定義路由容器,路由引發的變化的內容都將在這個容器之中,配合 keep-alive 使用可緩存頁面。web
<template> <div id="app"> <div> 不會隨路由變化而變化的內容,能夠存放一些全局使用內容,如提示信息等,經過使用 vuex 傳遞消息,或是 BusService 傳遞消息,使得內容顯示或者隱藏以及具體顯示內容 </div> <keep-alive :includes="['home','list']"> <router-view></router-view> </keep-alive> </div> </template>
定義路由跳轉,傳入 to 屬性,爲一個對象,能夠有 name(字符串),path(字符串),query(對象),params(對象)算法
<!-- 假若有配置路由 { name:'detail', path:'detail/:id' } --> <template> <router-link :to="{name:'detail',params:{id:1},query:{name:'xx'}}"></router-link> <!-- 上面渲染出的連接: #/detail/1?name=xx --> <router-link :to="{path:'/detail',params:{id:1},query:{name:'xx'}}"></router-link> <!-- 上面渲染出的連接: #/detail?name=xx --> <router-link :to="{name:'detail',path:'/detail',params:{id:1},query:{name:'xx'}}"></router-link> <!-- 上面渲染出的連接: #/detail/1?name=xx --> </template>
注意使用 name 時,vue 將根據路由配置找到對應的 name,而後還原出 path,這時候若是路由配置的 path 是 '/detail/:id' 相似的形式,則將按這規則,還原完整的地址。也就是當有 path 時,只照顧 query 參數。vue-router
有 name 時,對應路由配置信息找出 path,而後用 params 填充 path,再拼上 queryvuex
name 和 path 共存時,按 name 的規則走。(儘可能避免)element-ui
export default { mounted(){ this.$router.push('/detail/1'); // 直接字符串形式 this.$router.push({ name:'detail', query:{a:1}, params:{id:1} }); // 使用規則和 router-link 相似 // this.replace 相似 push this.$router.back() this.$router.go(-2) // 後退 this.$router.go(2) // 前進 } }
組件中獲取路由參數,經過 this.$route 獲取
// 能夠在 created 週期內獲取 export default { data(){ return { id:'', name:'' } } created(){ let { id } = this.$route.params; let { name } = this.$route.query; this.id = id || '' this.name = name || '' } }
之前使用 require.ensure 實現路由懶加載,如今能夠直接 ()=>import 實現了
// router.config.js export const RouterConf = [ { path:'/home', component:()=> import(/* webpackChunkName: "home" */ './home.js') } ]
打包時,將以 home 命名。
整理完以後,將發佈在 github 上
https://github.com/haokur/