本人是个新手,写下博客用于自我复习、自我总结。
如有错误之处,请各位大佬指出。
学习资料来源于:尚硅谷
vue 项目中常用的 2 个 ajax 库
vue-resource
vue 插件, 非官方库, vue1.x 使用广泛
axios
通用的 ajax 请求库, 官方推荐, vue2.x 使用广泛
免费测试接口
接口 1: https://api.github.com/search/repositories?q=v&sort=stars
接口 2: https://api.github.com/search/users?q=aa
vue-resource
安装:
npm i vue-resource --save
简单例:
main.js
import Vue from 'vue'
import VueResource from 'vue-resource'
import App from './App.vue'
//声明使用插件
Vue.use(VueResource)//内部会给vm对象和组件对象添加一个属性:$http
new Vue({
el: '#app',
components: {App}, // 映射组件标签
template: '<App/>', // 指定需要渲染到页面的模板
})
App.vue
<template>
<div>
<div v-if="!repoUrl">loading</div>
<div v-else>most star repo is<a :href="repoUrl">{{repoName}}</a></div>
</div>
</template>
<script>
export default {
data(){ //组件对象的属性,必须是函数形式
return{
repoUrl: '',
repoName: ''
}
}
},
mounted(){
//发ajax请求获取数据
const url = `https://api.github.com/search/repositories?q=v&sort=stars`
this.$http.get(url).then(
response => {
//成功了
const result = response.data
//得到最受欢迎的repo
const mostRepo = result.items[0]
this.repoUrl = mostRepo.html_url
this.repoName = mostRepo.name
},
response => {
alert('请求失败')
}
)
}
</script>
<style>
</style>
axios
npm i axios --save
简例:
<template>
<div>
<div v-if="!repoUrl">loading</div>
<div v-else>most star repo is<a :href="repoUrl">{{repoName}}</a></div>
</div>
</template>
<script>
import axios from 'axios'
export default {
data(){ //组件对象的属性,必须是函数形式
return{
repoUrl: '',
repoName: ''
}
},
mounted(){
//发ajax请求获取数据
const url = `https://api.github.com/search/repositories?q=v&sort=stars`
//使用axios发送ajax请求
axios.get(url).then(response => {
//成功了
const result = response.data
//得到最受欢迎的repo
const mostRepo = result.items[0]
this.repoUrl = mostRepo.html_url
this.repoName = mostRepo.name
}).catch(error =>{
alert('请求失败')
})
}
}
</script>
<style>
</style>
例
项目结构 (忽略main.js index.html 和 css文件)
App.vue
<template>
<div class="container">
<Search/>
<UsersMain/>
</div>
</template>
<script>
import Search from './components/Search.vue'
import Main from './components/Main.vue'
export default {
components: {
Search,
UsersMain: Main
}
}
</script>
<style>
</style>
Main.vue
<template>
<div>
<h2 v-show="firstView">请输入关键字搜索</h2>
<h2 v-show="loading">请求中...</h2>
<h2 v-show="errorMsg">{{errorMsg}}</h2>
<div class="row" v-show="users.length>0">
<div class="card" v-for="(user, index) in users" :key="index">
<a :href="user.url" target="_blank">
<img :src="user.avatarUrl" style='width: 100px'/>
</a>
<p class="card-text">{{user.username}}</p>
</div>
</div>
</div>
</template>
<script>
import PubSub from 'pubsub-js'
import axios from 'axios'
export default {
data () {
return {
firstView: true, // 是否显示初始页面
loading: false, // 是否正在请求中
users: [], // 用户数组[{url: '',avatarUrl: '',username: ''}]
errorMsg: '' //错误信息
}
},
mounted () {
// 订阅消息(search)
PubSub.subscribe('search', (message, searchName) => { // 点击了搜索, 发ajax请求进行搜索
// 更新数据(请求中)
this.firstView = false
this.loading = true
this.users = []
this.errorMsg = ''
// 发ajax请求进行搜索
const url = `https://api.github.com/search/users?q=${searchName}`
axios.get(url).then(response => {
// 成功了, 更新数据(成功)
this.loading = false
this.users = response.data.items.map(item => ({
url: item.html_url,
avatarUrl: item.avatar_url,
username: item.login
}))
}).catch(error => {
// 失败了, 更新数据(失败)
this.loading = false
this.errorMsg = '请求失败!'
})
})
}
}
</script>
<style>
.card {
float: left;
width: 33.333%;
padding: .75rem;
margin-bottom: 2rem;
border: 1px solid #efefef;
text-align: center;
}
.card > img {
margin-bottom: .75rem;
border-radius: 100px;
}
.card-text {
font-size: 85%;
}
</style>
Search.vue
<template>
<section class="jumbotron">
<h3 class="jumbotron-heading">Search Github Users</h3>
<div>
<input type="text" placeholder="enter the name you search" v-model="searchName"/>
<button @click="search">Search</button>
</div>
</section>
</template>
<script>
import PubSub from 'pubsub-js'
export default {
data () {
return {
searchName: ''
}
},
methods: {
search () {
const searchName = this.searchName.trim()
if(searchName) {
// 分发一个search的消息
PubSub.publish('search', searchName)
}
}
}
}
</script>
<style>
</style>
UI组件库
常用
- Mint UI:
a. 主页: http://mint-ui.github.io/#!/zh-cn
b. 说明: 饿了么开源的基于 vue 的移动端 UI 组件库 - Elment
a. 主页: http://element-cn.eleme.io/#/zh-CN
b. 说明: 饿了么开源的基于 vue 的 PC 端 UI 组件库
首先安装:npm i --save mint-ui
npm i --save-dev babel-plugin-component
实现按需打包,修改 babelrc 配置
"plugins": ["transform-runtime",["component", [
{
"libraryName": "mint-ui",
"style": true
}
]]]
这个component
插件就是专门用来按需打包的。按需打包就是,mint-ui里有很多组件,我们只用了其中的几个,那我们肯定不会把里面所有的内容全部打包下来,我们只把我们使用到的打包下来。
使用:
(所有的组件如何使用,如何导入,在官网有详细说明,在这里就简单演示一下)
main.js
import Vue from 'vue'
import App from './App.vue'
import {Button} from 'mint-ui'
// 注册成标签(全局)
Vue.component(Button.name, Button)
/* eslint-disable no-new */
new Vue({
el: '#app',
components: {App}, // 映射组件标签
template: '<App/>' // 指定需要渲染到页面的模板
})
App.vue
<template>
<mt-button type="primary" @click.native="handleClick" style="width: 100%">Test</mt-button>
</template>
<script>
import { Toast } from 'mint-ui'
export default {
methods: {
handleClick () {
Toast('提示信息')
}
}
}
</script>
<style>
</style>
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" />
<link rel="stylesheet" href="/static/css/bootstrap.css">
<title>vue_demo</title>
<script src="https://as.alipayobjects.com/g/component/fastclick/1.0.6/fastclick.js"></script>
<script>
if ('addEventListener' in document) {
document.addEventListener('DOMContentLoaded', function() {
FastClick.attach(document.body);
}, false);
}
if(!window.Promise) {
document.writeln('<script src="https://as.alipayobjects.com/g/component/es6-promise/3.2.2/es6-promise.min.js"'+'>'+'<'+'/'+'script>');
}
</script>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
vue-router
在真实的应用中,我们做的都是SPA应用(单页应用),但实际上我们承载的功能页面是很多的,那就需要我们的页面在不断的变化,但是不能让页面跳转,所以这里就需要路由链接,让链接不发出请求,而只是更新显示不同的路由组件。
说明:
- 官方提供的用来实现 SPA 的 vue 插件
- github: https://github.com/vuejs/vue-router
- 中文文档: http://router.vuejs.org/zh-cn/
- 下载:
npm install vue-router --save
路由器:管理路由,
路由:一个映射关系(key - value),key是path,value是前台路由(组件)或后台路由(处理请求的回调函数)
相关 API 说明
1) VueRouter(): 用于创建路由器的构建函数
new VueRouter({
// 多个配置项
})
2) 路由配置
routes: [
{ // 一般路由
path: '/about',
component: About
},
{ // 自动跳转路由
path: '/',
redirect: '/about'
}
]
3) 注册路由器
import router from './router'
new Vue({
router
})
4) 使用路由组件标签
1. <router-link>: 用来生成路由链接
<router-link to="/xxx">Go to XXX</router-link>
2. <router-view>: 用来显示当前路由组件界面
<router-view></router-view>
基本路由
项目结构:(忽略了index.html和样式文件)
About.vue
<template>
<div>
<h2>About</h2>
</div>
</template>
<script>
export default {}
</script>
<style>
</style>
Home.vue
<template>
<div>
<h2>Home</h2>
</div>
</template>
<script>
export default {}
</script>
<style>
</style>
第一步、index.js 定义路由器
/*
路由器对象模块
*/
import Vue from 'vue'
import VueRouter from 'vue-router'
import About from '../pages/About.vue'
import Home from '../pages/Home.vue'
// 声明使用vue-router插件
Vue.use(VueRouter)
export default new VueRouter ({
// 注册应用中所有的路由
routes: [
{
path: '/about',
component: About
},
{
path: '/home',
component: Home
},
{ //自动跳转路由
path: '/',
redirect: '/about'
}
]
})
第二步、main.js 注册路由器
/* 入口JS */
import Vue from 'vue'
import App from './App.vue'
import router from './router'
/* eslint-disable no-new */
new Vue({ //配置对象的属性名都是一些确定的名称,不能随便修改
el: '#app',
components: {App}, // 映射组件标签
template: '<App/>', // 指定需要渲染到页面的模板
router // 注册路由器
})
第三步、在某个组件中写这几个标签
App.vue
<template>
<div>
<div class="row">
<div class="col-xs-offset-2 col-xs-8">
<div class="page-header"><h2>Router Test</h2></div>
</div>
</div>
<div class="row">
<div class="col-xs-2 col-xs-offset-2">
<div class="list-group">
<!--生成路由链接-->
<router-link to="/about" class="list-group-item">About</router-link>
<router-link to="/home" class="list-group-item">Home</router-link>
</div>
</div>
<div class="col-xs-6">
<div class="panel">
<div class="panel-body">
<!--显示当前组件-->
<keep-alive>
<router-view msg="abc"></router-view>
</keep-alive>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {}
</script>
<style>
</style>
总结: 编写使用路由的 3 步
- 定义路由组件
- 注册路由
- 使用路由
<router-link>
<router-view>
嵌套路由
项目结构:(忽略index.html、样式,App、About和上面的一样,Message.vue和News.vue是Home.vue下的两个子组件)
根据步骤,定义、注册、使用。
index.js
/*
路由器对象模块
*/
import Vue from 'vue'
import VueRouter from 'vue-router'
import About from '../pages/About.vue'
import Home from '../pages/Home.vue'
import News from '../pages/News.vue'
import Message from '../pages/Message.vue'
// 声明使用vue-router插件
Vue.use(VueRouter)
export default new VueRouter ({
// 注册应用中所有的路由
routes: [
{
path: '/about',
component: About
},
{
path: '/home',
component: Home,
children: [
{
path: '/home/news', //path最左侧的 / 永远代表根路径
component: News
},
{
path: 'message', //简化写法,省略 /
component: Message
},
{ //自动配置路由
path: '',
redirect: '/home/news'
}
]
},
{ //自动配置路由
path: '/',
redirect: '/about'
}
]
})
main.js
/* 入口JS */
import Vue from 'vue'
import App from './App.vue'
import router from './router'
/* eslint-disable no-new */
new Vue({
el: '#app',
components: {App}, // 映射组件标签
template: '<App/>', // 指定需要渲染到页面的模板
router // 注册路由器
})
Home.vue
<template>
<div>
<h2>Home</h2>
<div>
<ul class="nav nav-tabs">
<li><router-link to="/home/news">News</router-link></li>
<li><router-link to="/home/message">Message</router-link></li>
</ul>
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {}
</script>
<style>
</style>
News.vue
<template>
<ul>
<li v-for="(news, index) in newsArr" :key="index">{{news}}</li>
</ul>
</template>
<script>
export default {
data () {
return {
newsArr: ['News001', 'News002', 'News003']
}
}
}
</script>
<style>
</style>
Message.vue
<template>
<ul>
<li v-for="m in messages" :key="m.id">
<a href="???">{{m.title}}</a>
</li>
</ul>
</template>
<script>
export default {
data () {
return {
messages: []
}
},
mounted () {
//模拟ajax请求从后台获取数据
setTimeout(() => {
const messages = [
{id: 1, title: 'Message001'},
{id: 3, title: 'Message003'},
{id: 5, title: 'Message005'}
]
this.messages = messages
}, 1000)
}
</script>
<style>
</style>
向路由组件传递数据
方式 1:<router-view>
属性携带数据。这就很简单了。
同时这里介绍一个用法,缓存路由组件对象。
- 默认情况下, 被切换的路由组件对象会死亡释放, 再次回来时是重新创建的
- 如果可以缓存路由组件对象, 可以提高用户体验
App.vue
<template>
<div>
<div class="row">
<div class="col-xs-offset-2 col-xs-8">
<div class="page-header"><h2>Router Test</h2></div>
</div>
</div>
<div class="row">
<div class="col-xs-2 col-xs-offset-2">
<div class="list-group">
<!--生成路由链接-->
<router-link to="/about" class="list-group-item">About</router-link>
<router-link to="/home" class="list-group-item">Home</router-link>
</div>
</div>
<div class="col-xs-6">
<div class="panel">
<div class="panel-body">
<!--缓存路由组件对象-->
<keep-alive>
<router-view msg="abc"></router-view>
</keep-alive>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {}
</script>
<style>
</style>
About.vue
<template>
<div>
<h2>About</h2>
<p>{{msg}}</p>
<input type="text">
</div>
</template>
<script>
export default {
props: {
msg: String
}
}
</script>
<style>
</style>
可以发现能够传递数据,同时缓存数据对象,无论怎么切换,输入框内数据可以保持不变。
方式 2: 路由路径携带参数(param)
1)配置路由
children: [
{
path: 'mdetail/:id',
component: MessageDetail
}
]
2)路由路径
<router-link :to="'/home/message/mdetail/'+m.id">{{m.title}}</router-link>
3)路由组件中读取请求参数
this.$route.params.id
实现:
项目结构:
index.js
/*
路由器对象模块
*/
import Vue from 'vue'
import VueRouter from 'vue-router'
import About from '../pages/About.vue'
import Home from '../pages/Home.vue'
import News from '../pages/News.vue'
import Message from '../pages/Message.vue'
import MessageDetail from '../pages/MessageDetail.vue'
// 声明使用vue-router插件
/*
内部定义并注册了2个组件标签(router-link/router-view),
给组件对象添加了2个属性:
1. $router: 路由器
2. $route: 当前路由
*/
Vue.use(VueRouter)
export default new VueRouter ({
// 注册应用中所有的路由
routes: [
{
path: '/about',
component: About
},
{
path: '/home',
component: Home,
children: [
{
path: '/home/news', //path最左侧的 / 永远代表根路径
component: News
},
{
path: 'message', //简化写法,省略 /
component: Message,
children: [
{
path:'detail/:id',
component: MessageDetail
}
]
},
{ //自动配置路由
path: '',
redirect: '/home/news'
}
]
},
{ //自动配置路由
path: '/',
redirect: '/about'
}
]
})
Message.vue
<template>
<div>
<ul>
<li v-for="m in messages" :key="m.id">
<router-link :to="`/home/message/detail/${m.id}`">{{m.title}}</router-link>
</li>
</ul>
<hr>
<router-view></router-view>
</div>
</template>
<script>
export default {
data () {
return {
messages: []
}
},
mounted () {
//模拟ajax请求从后台获取数据
setTimeout(() => {
const messages = [
{id: 1, title: 'Message001'},
{id: 3, title: 'Message003'},
{id: 5, title: 'Message005'}
]
this.messages = messages
}, 1000)
}
}
</script>
<style>
</style>
MessageDetail.vue
<template>
<ul>
<li>id: {{$route.params.id}}</li>
<li>title: {{detail.title}}</li>
<li>content: {{detail.content}}</li>
</ul>
</template>
<script>
const messageDetails = [
{id: 1, title: 'Message001', content: 'message content00111....'},
{id: 3, title: 'Message003', content: 'message content00222....'},
{id: 5, title: 'Message005', content: 'message content00333....'}
]
export default {
data() {
return {
detail: {}
}
},
mounted () {// 改变当前路由组件参数数据时, 不会重新创建组件对象, mounted不会重新执行
const id = this.$route.params.id
this.detail = messageDetails.find(detail => detail.id===id*1)
},
watch: {
$route: function () { // 改变当前路由组件参数数据时自动调用
console.log('$route()')
const id = this.$route.params.id
this.detail = messageDetails.find(detail => detail.id===id*1)
}
}
}
</script>
<style>
</style>
编程式路由导航
相关 API
- this.$router.push(path): 相当于点击路由链接(可以返回到当前路由界面)
- this.$router.replace(path): 用新路由替换当前路由(不可以返回到当前路由界面)
- this.$router.back(): 请求(返回)上一个记录路由
- this.$router.go(-1): 请求(返回)上一个记录路由
- this.$router.go(1): 请求下一个记录路由
对Message.vue进行修改
<template>
<div>
<ul>
<li v-for="m in messages" :key="m.id">
<router-link :to="`/home/message/detail/${m.id}`">{{m.title}}</router-link>
<button @click="pushShow(m.id)">push查看</button>
<button @click="replaceShow(m.id)">replace查看</button>
</li>
</ul>
<button @click="$router.back()">回退</button>
<hr>
<router-view></router-view>
</div>
</template>
<script>
export default {
data () {
return {
messages: []
}
},
mounted () {
//模拟ajax请求从后台获取数据
setTimeout(() => {
const messages = [
{id: 1, title: 'Message001'},
{id: 3, title: 'Message003'},
{id: 5, title: 'Message005'}
]
this.messages = messages
}, 1000)
},
methods: {
pushShow (id) {
this.$router.push(`/home/message/detail/${id}`)
},
replaceShow(id) {
this.$router.replace(`/home/message/detail/${id}`)
}
}
}
</script>
<style>
</style>