从如下几个方面整理: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/