③Vue vue-ajax、UI组件库、vue-router


本人是个新手,写下博客用于自我复习、自我总结。
如有错误之处,请各位大佬指出。
学习资料来源于:尚硅谷


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组件库

常用

  1. Mint UI:
    a. 主页: http://mint-ui.github.io/#!/zh-cn
    b. 说明: 饿了么开源的基于 vue 的移动端 UI 组件库
  2. 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应用(单页应用),但实际上我们承载的功能页面是很多的,那就需要我们的页面在不断的变化,但是不能让页面跳转,所以这里就需要路由链接,让链接不发出请求,而只是更新显示不同的路由组件。

说明:

  1. 官方提供的用来实现 SPA 的 vue 插件
  2. github: https://github.com/vuejs/vue-router
  3. 中文文档: http://router.vuejs.org/zh-cn/
  4. 下载: 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 步

  1. 定义路由组件
  2. 注册路由
  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>属性携带数据。这就很简单了。
同时这里介绍一个用法,缓存路由组件对象

  1. 默认情况下, 被切换的路由组件对象会死亡释放, 再次回来时是重新创建的
  2. 如果可以缓存路由组件对象, 可以提高用户体验

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

  1. this.$router.push(path): 相当于点击路由链接(可以返回到当前路由界面)
  2. this.$router.replace(path): 用新路由替换当前路由(不可以返回到当前路由界面)
  3. this.$router.back(): 请求(返回)上一个记录路由
  4. this.$router.go(-1): 请求(返回)上一个记录路由
  5. 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>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

只爭朝夕不負韶華

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值