_______________________________________________________________________________________________
4、兄弟组件通信
兄弟组件的通信,借助于一个Vue的实例(eventBus 事件总线)作为一个中介,组件通过监听该实例去完成事件的绑定和触发(仅)
varbus= new Vue(); //新建一个Vue实例,并接收这个实例,当作事件总线
Vue.component("发送方组件",{
methods:{
handleClick: function(){
bus.$emit('event自定义事件名','arg1','arg2'...)
} //触发当前实例上的事件,第二个参数是触发时附加的参数,会传给监听器回调
},
template: `<button @click="handleClick">触发事件,进行通信</button>`
})
Vue.component("接收方组件",{
created:function(){ //放在'组件实例创建完成后'的函数中,可以自动接收
bus.$on('event自定义事件名',function(arg1,arg2...){ }
} //绑定监听当前实例上的自定义事件,事件由.emit触发
//第二个参数是触发事件成功的回调函数,会接收所有传入'事件触发函数'的额外参数
template: `<div>接收通信</div>`
})
_______________________________________________________________________________________________
路由
使用 vueRouter 插件可以实现SPA
单文件: 在webpack环境下使用路由模块: 或者在项目初始化时提前设置自动安装
var Vue=require('vue')
var VueRouter=require('vue-router')
Vue.use(VueRouter)
VueRouter
① 引入 vue-router.js 文件
② 指定容器
<div id="example">
<router-view></router-view> //指定组件插入的容器
</div>
③ 创建各个子组件
var Test01Component=Vue.component("test01",{ //组件定义在最上面,才能加载路由
template:`<div>
<h1>这是子组件test01</h1>
</div>`
});
④ 配置路由地址(分为三段)
constmyRoutes= [ //① 配置路由地址: 创建一个对象数组,每个对象指定path/component
{ path:'/myPath1',component:Test01Component },
{ path:'/myPath2',component:Test01Component},
{ path: "/",component: Test01Component } //没有path,只有一个/时跳转的地址
];
constmyRouter= new VueRouter({ //② 创建一个VueRouter的实例,并接收
routes:myRoutes //指定 routes 属性为配置的路由地址,与①可合为一个
});
new Vue({
router:myRouter //③ 在vue的实例中指定router属性为路由 VueRouter 的实例
<=> new VueRouter({routes:myRoutes}); //但不建议这样写,跳转不便
})
跳转:
html的方式 <router-link to="/myPath1">跳转到myPath1</router-link> //渲染出来是一个 a 标签
js的方式:
jump:function(){ myRouterVueRouter的实例.push("/myPath1"); }
<button @click="jump">跳转到myPath1</button>
传参:
① 明确发送方、接收方
② 配置接收方的路由地址path
{path: "/myPath1/:arg",component:Test01Component }
③ 接收方取得传递过来的参数
created:function(){
this.resArgdata数据=this.$route.params.arg;
}
④ 发送方发送参数
<router-link to='/myPath1/20'> <router-link v-bind:to="'/myPath1/'+value"></router-link>
<a href='#/myPath1/20'></a> <a v-bind:href="'#/myPath1/'+value"></a>
jump:function(){ myRouter.push('/myPath1/20'); }
jump:function(){ myRouter.push("/myPath1"+this.value); } //通过'该组件的数据'传参
jump:function(key){ myRouter.push("/myPath1/"+key);} //通过'方法传来的参数'传参
触发事件绑定的方法: <any @click="jump(key)"><any>
嵌套路由:
var MyMail = Vue.component("mail",{
template: `<div>
<h1>这是邮箱主页面</h1>
<router-link to="/inbox">收件箱</router-link>
<router-link to="/outbox">发件箱</router-link>
<router-view></router-view> //① 为子路由指定容器
</div>`
});
② 在配置路由地址时,为子路由指定path/component
constmyRoutes=[
{ path:'/myPath1',component:Test01Component },
{path:"/myMail", component:MyMail, children:[
{ path:"/inbox",component:inBox },
{ path:"/outbox",component:outBox}] },
{ path: "/",component: Test01Component }
];
注意: 子路由的跳转链接不是必须加在父路由中。可以加在项目的任一页面,都可跳向子路由,同时也会显示其父路由的内容
_______________________________________________________________________________________________
三、网络请求(使用vue-resource或者axios插件)
① 引入vue-resource.js文件
Vue.component('test',{
data: function(){
return { List:[] }
},
methods:{
loadData: function(){ //this.$http.get()第一个参数是请求的url,第二个参数是传递的参数
this.$http.get('data/stu.json请求url',{"id":123}) //② 发起网络请求 get/post
.then(function(response){ //响应成功的回调函数,参数是返回的数据
this.List = response.data; //③ 对响应到的数据进行操作
})
}
},
template:`<div>
<ul><li v-for="tmp in List">{{tmp.name}}</li></ul> //将返回的数据显示在视图上
<button @click="loadData">加载数据</button> //绑定请求事件
</div>`
})
axios(爱可西柚子)******************************************************************************
特色: ① 浏览器端发起XMLHttpRequests请求 ② node端发起http请求 ③ 支持Promise API
④ 监听请求和返回 ⑤ 转化请求和返回 ⑥ 取消请求 ⑦ 自动转化json数据 ⑧ 客户端支持抵御
安装使用:
npm: npm install axios --save-dev
cdn: <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
src/main.js: 引入axios
import axios from 'axios'
Vue.prototype.$axios = axios
src/App.vue: 拦截器,在请求或者返回被then或catch处理之前对它们进行拦截
created(){
var loading = null;
this.$axios.interceptors.request.use(config => { //发出请求之前进行拦截
if(store.state.token){ //判断是否存在token,如果存在的话,则每个http header都加上token
config.headers.Authorization = `token ${store.state.token}`;
}
loading = this.$loading({ text:'请求中...' });
return config;
}, err => {
this.$message({ message:'请求接口失败...', type:'warning', duration: 1333 });
return Promise.reject(err);
})
this.$axios.interceptors.response.use(res => { //对返回的数据进行拦截
loading.close();
return res;
}, err => {
loading.close();
if(err.response){
switch (err.response.status) {
case 401:
store.commit(types.LOGOUT);//返回401(未授权),清除token信息并跳转到登录页面
router.replace({ path: 'login',
query: {redirect: router.currentRoute.fullPath}
})
}
}
return Promise.reject(err);//返回接口返回的错误信息
})
}
跨域请求:
config/index.js:
proxyTable:{
'/api':{ // '/api'文件中的匹配项
target: 'http://erpserver.mgupiao.com', //请求接口的地址
secure: false, //如果是https接口,需要配置此参数
changeOrigin: true, //如果需要跨域,需要配置此参数
pathRewrite:{ '^/api':'' } // 因为在ajax的url中加了前缀 '/api'用于匹配,而原本的接口是没有这个前缀的,所以需要通过pathRewrite来重写地址,将前缀'/api'转为'/'
},
'/station': {
target: 'http://erpserver.mgupiao.com',
changeOrigin: true,
pathRewrite: { '^/station': 'station' }
}
},
axios的功能特性:
在浏览器中发送XMLHttpRequests请求
支持Promise API
拦截请求和响应
转换请求和响应数据
自动转换JSON数据
客户端支持保护安全免受XSRF攻击
请求方式:
var axios = this.$axios
axios(config)
axios.request(config)
axios.get(url[,config])
axios.delete(url[,config])
axios.head(url[,config])
axios.post(url[,data[,config]])
axios.put(url[,data[,config]])
axios.patch(url[,data[,config]])
get请求:
axios.get('/user',{param:{id:1}}) //可以取param参数
.then(res=>{console.log(res)})
.catch(err=>{console.log(err)})
post请求:
axios.post('/user',{id:2}) //会转换为json格式
.then(res=>{console.log(res)})
.catch(err=>{console.log(err)})
发送并发请求:
axios.all([axios.get('/profile'), axios.post('/user')])
.then(axios.spread((res1,res2)=>{
console.log(res1); console.log(res2);
}
))
*.vue单文件************************************************************************************
每一个*.vue文件都是组件使用大驼峰命名法
每个组件分为3个部分: <template></template>、<script></script>、<style></style>
template中只能有一个根标签
*.vue中的data是一个方法,该方法需要返回一个对象,在对象中初始化数据
<template>
<divclass="hello"> //只能有一个根标签(如div/section)
<head-top></head-top> //③ 使用组件
...
</div>
</template>
<script>
import headTop from './Header' //① 引入组件
export default{
name: 'SelectBall', //导出组件名
data () {
return {}
},
components: { //② 注册组件(使用components属性)
headTop //headTop: ES6的简写,相当于ES5: headTop:headTop
}
}
</script>
<style lang="less" type="text/less" scoped> //若不写type="text/less",WebStorm可能会报错
//scoped: 使style中的样式(如less)只作用于当前组件(若不写,则样式会作用于全局)
@import 'other.less'; //导入的也遵守此规则
.tilte{
font-size: 1.2rem;
}
</style>
src/router/index.js: 每一个*.vue文件都需要在此文件中引入才能使用(配置路由)
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld' //引入组件
//@: 在build/webpack.base.conf.js中的alias配置的别名
Vue.use(Router) //使用路由
constrouter= new Router({
mode:'history', //配置此参数后,路径不会带#(可使用pushState/replaceState来管理记录)
//否则需要在跳转地址前加 /#
routes: [{path: '/helloWorld', //配置路由地址
name: 'helloWorld', //name和path使用小驼峰命名法
component: HelloWorld,
children:[{ path:"/inbox",component:InBox },
{ path:"/outbox",component:OutBox}]},
{path: '/xiaoliang',
name: 'xiaoliang',
component: Xiaoliang,
meta: {
title: '标题',
requireAuth: true, //自定义字段,表示进入这个路由需要登录
}, }]
})
利用vue-router提供的钩子函数beforeEach对路由进行判断,进行登录验证、修改title等操作
router.beforeEach((to, from, next) => {
if(to.meta.requireAuth){ //判断该路由是否需要登录权限
if(store.state.token){ //通过vuex state获取当前的token是否存在
next();
}else{
next({ path: '/login',
query: {redirect: to.fullPath} //将跳转的路由path作为参数,登录成功后跳回该路由
})
}
}else{ next(); }
if(to.meta.title){
document.title = to.meta.title; //设置网页标题
}
next();
})
export default router
跳转: 使用路由跳转,可跳到子组件或兄弟组件
注意:
① 若不在域名的根目录下时,需要在routes中的每个路由下添加 /目录名
② 应使用<router-link to="/home">Home</router-link>跳转,若用a跳转则会刷新页面
③ 若使用mode: 'history',应将服务期所有404页面重定向回index.html,使用前端路由跳转
如nginx: error_page 404 /index.html;
④ 因为所有的404都会重定向到index.html,所以可以在Vue应用里覆盖所有的路由,给出一个404页面
{ path: '*', component: NotFoundComponent }
⑤ 在IE中,页面大小<1024b会被认为不友好,会将该页面替换成自己的错误提示页面,所以应避免index.html小于1024b
⑥ 登录应做双重判定,首先应由前端路由控制(router.beforeEach),为确保token失效后确保无法访问需要登录的页面,应使用http拦截器+后台接口返回的http状态码来判断(axios拦截器)
vue技巧*****************************************************************************************
路由动画效果:
src/App.Vue:
<div id="app">
<transition :name="transitionName">
<router-view class="child-view"></router-view>
</transition>
</div>
export default {
name: 'App',
data(){
return {
transitionName: 'slide-left'
}
},
watch: {
'$route'(to, from){//监听路由的路径,可以通过不同的路径去选择不同的切换效果
const toDepth = to.path.split('/').length;
const fromDepth = from.path.split('/').length;
this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left';
}
}
}
#app,.child-view{ //防止切换路由时出现滚动条
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
#app{
overflow-x: hidden;
}
.child-view{
transition: all .8s cubic-bezier(.55, 0, .1, 1);
}
.slide-left-enter, .slide-right-leave-active{
opacity: 0;
-webkit-transform: translate(100%, 0);
transform: translate(100%, 0);
}
.slide-left-leave-active, .slide-right-enter{
opacity: 0;
-webkit-transform: translate(-100%, 0);
transform: translate(-100%, 0);
}
配置资源路径:
方法①
config/index.js:
assetsPublicPath:'/', //可发布到网络上,资源使用的是根路径
assetsPublicPath: '/dist/', //在dist中创建一个WebStorm项目即可查看(根路径)
assetsPublicPath:'', //输出相对路径,不用服务器也能打开(引用直接写的文件名)
assetsPublicPath:'./', //输出相对路径,不用服务器也能打开(引用写的./文件名)
方法②
build/webpack.prod.conf.js:
output: { publicPath:'./', }, //添加此语句,调试打包时,都输出相对路径(引用使用./文件名)
基于vue的ui库***********************************************************************************
PC端:
① element 饿了么前端出品的基于Vue 2.0的桌面端组件库
https://github.com/ElemeFE/element //github仓库地址
② iview 基于Vuejs的开源UI组件库
https://github.com/iview/iview //github仓库地址
③ muse-ui 三端样式一致的响应式UI库
https://github.com/museui/muse-ui //github仓库地址
移动端:
① Vux 基于Vue和微信官方WeUI的组件库
https://github.com/airyland/vux //github仓库地址
② mint-ui 饿了么前端推出的基于Vue.js的移动端组件库
https://github.com/ElemeFE/mint-ui //github仓库地址
http://elemefe.github.io/mint-ui/#/ //demo地址
③ vue-material 基于Vue Material和Vue 2精美的app应用(英文文档)
https://github.com/marcosmoura/vue-material //github仓库地址