7-1前后端分离开发是什么?
什么是RESTful API?
patch(update)在服务i去更新资源
delete从服务器删除资源
7-4使用swagger在线文档查看接口详情
endpoints具体路径
使用什么样的数据
swagger在线文档查看接口详情
axios的基本用法和独家后端api使用
import App from './App.vue'
import 'easymde/dist/easymde.min.css'
axios.defaults.baseURL = process.env.NODE_ENV === 'development' ? '/' : 'http://api.vikingship.xyz/api/'
axios.interceptors.request.use(config => {
store.commit('setLoading', true)
store.commit('setError', { status: false, message: '' })
return config
})
axios.interceptors.response.use(config => {
setTimeout(() => {
store.commit('setLoading', false)
}, 1000)
return config
}, e => {
const { error } = e.response.data
store.commit('setError', { status: true, message: error })
store.commit('setLoading', false)
return Promise.reject(e.response.data)
})
const app = createApp(App)
app.use(router)
app.use(store)
app.mount('#app')
mutation当中的数据必须是同步的
actions:{
fetchColumns(context){
axios.get('/cloums').then(res=>{
context.commit(fetchColumns',resp.data)})
fetchColumns(state,rawData){
state.columsn=rawData.
setup(){
const store=useStore<Global
interface ImageProps{
_id?:string;
url?:string;
createdAt?:string;}
else{
coljjms.awater.url=columns.
7-7-使用vue-action发送异步请求
export interface GlobalDataProps{
state:{
onMounted(()==>{
store.dispatch('fetchColum',currentId)})
PostList.vue
<template>
<div class="post-list">
<article v-for="post in posts" :key="post._id" class="card mb-3 shadow-sm">
<div class="card-body">
<h4><router-link :to="`/posts/${post._id}/`">{{post.title}}</router-link></h4>
<div class="row my-3 align-items-center">
<div v-if="post.image && typeof post.image !== 'string'" class="col-4">
<img :src="post.image.fitUrl" :alt="post.title" class="rounded-lg w-100">
</div>
<p :class="{'col-8': post.image}" class="text-muted">{{post.excerpt}}</p>
</div>
<span class="text-muted">{{post.createdAt}}</span>
</div>
</article>
</div>
</template>
<script lang="ts">
import { defineComponent, PropType, computed } from 'vue'
import { PostProps, ImageProps } from '../store'
import { generateFitUrl } from '../helper'
export default defineComponent({
props: {
list: {
required: true,
type: Array as PropType<PostProps[]>
}
},
setup(props) {
const posts = computed(() => {
return props.list.map(post => {
generateFitUrl(post.image as ImageProps, 200, 110, ['m_fill'])
return post
})
})
return {
posts
}
}
})
</script>
<style scoped>
.post-list h4 a {
text-decoration: none;
color:#1a1a1a;
}
.post-list h4 a:hover {
color:#0d6efd;
}
</style>
const getAndCommit=async(url:string,mutationNmae:string,commit.commit){
const{data}=
7-10使用axios拦截器添加loading效果
setLoading
const getAndCommit=async(url:string,mutationName:string){{
const isLaoding=computed(()=>store
axios.interceptors.request.use(config=>{
store.commit('setLoading',true)
7-11loader组件编码
<template>
<teleport to="#back">
<div
class="d-flex justify-content-center align-items-center h-100 w-100 loading-container"
:style="{backgroundColor: background || ''}"
>
<div class="loading-content">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">{{ text || 'loading'}}</span>
</div>
<p v-if="text" class="text-primary small">{{text}}</p>
</div>
</div>
</teleport>
</template>
<script lang="ts">
import { defineComponent, onUnmounted } from 'vue'
export default defineComponent({
props: {
text: {
type: String
},
background: {
type: String
}
},
setup() {
const node = document.createElement('div')
node.id = 'back'
document.body.appendChild(node)
onUnmounted(() => {
document.body.removeChild(node)
})
}
})
</script>
<style>
.loading-container {
background: rgba(255, 255, 255, .5);
z-index: 100;
position: fixed;
top: 0;
left: 0;
}
.loading-container {
text-align: center;
}
</style>
7-12-loader组件编码teleport
后端Icode终极使用方案
慕课网提供的 Icode 经过几次升级,现在把最终的解决方案整理如下,供同学们参考。
可以在 main.ts 中的拦截器里面一劳永逸的添加。
// 替换 baseURL
axios.defaults.baseURL = 'http://apis.imooc.com/api/'
// 下面的 icode 值是从慕课网获取的 token 值,可以在课程右侧的项目接口校验码找到
axios.interceptors.request.use(config => {
... 其他代码
// get 请求,添加到 url 中
config.params = { ...config.params, icode: '******' }
// 其他请求,添加到 body 中
// 如果是上传文件,添加到 FormData 中
if (config.data instanceof FormData) {
config.data.append('icode', '******')
} else {
// 普通的 body 对象,添加到 data 中
config.data = { ...config.data, icode: '******' }
}
return config
})
如果同学们这时候去回顾 CreatePost 页面的话,由于 ColumnProps 对应的更新,这里的 CreatePost页面 暂时没有同时更新(由于现在不会用到该功能,但是以后升级 CreatePost 的时候我们会修改这些代
码),会发现一些类型错误。如图所示:
这里如果同学们要追求类型的完美,可以在这里提前暂时修改它,根本原因就是类型不匹配,由于在 ColumnProps 中我们把 id 修改成了 _id,类型成了 string,columnId 修改为了 column,类型变成了 string。
所以这里可以简单对应一下
const { columnId } = store.state.user
if (columnId) {
const newPost: PostProps = {
// 转成 string 类型
_id: new Date().getTime().toString(),
title: titleVal.value,
content: contentVal.value,
// 转成 string 类型
column: columnId.toString(),
createdAt: new Date().toLocaleString()
}
store.commit('createPost', newPost)
router.push({ name: 'column', params: { id: columnId } })
}
当然这个创建文章的页面这样修改以后,暂时会没有办法工作,创建成功以后跳转到对应的column也没有数据,这是因为我们接入了真实的后端数据,假设数据暂时会有问题,等后面学到了对应的用户和创建真实的数据的时候就没有问题了
第7章 前后端结合 - 项目整合后端接口
#7-2 RESTful API 设计理念
[en.wikipedia.org/wiki/Repres… API)是目前比较成熟的一套互联网应用程序的API设计理论。 Endpoint
在RESTful架构中,每个网址代表一种资源(resource),所以网址中不能有动词,只能有名词,而且所用的名词往往与数据库的表格名对应。一般来说,数据库中的表都是同种记录的"集合"(collection),所以API中的名词也应该使用复数。
https://api.examples.com/teams
https://api.examples.com/players
Verb 动词
- GET(SELECT):从服务器取出资源(一项或多项)
- POST(CREATE):在服务器新建一个资源
- PUT(UPDATE):在服务器更新资源
- PATCH(UPDATE):在服务器更新资源
- DELETE(DELETE):从服务器删除资源
举例
// endpoints
https://api.example.com/teams
https://api.example.com/players
// verbs
GET /teams:列出所有球队
POST /teams:新建一个球队
GET /teams/ID:获取某个球队的信息
PUT /teams/ID:更新某个球队的信息(提供球队的全部信息)
PATCH /teams/ID:更新某个球队的信息(提供球队的部分信息)
{
name: 'new team name'
}
DELETE /teams/ID:删除某个球队
// 复杂结构 一对多
GET /teams/ID/players:列出某个指定球队的所有球员
// 常见状态码
200 OK - [GET]:服务器成功返回用户请求的数据
201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
204 NO CONTENT - [DELETE]:用户删除数据成功。
401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作。
// 项目使用的 endpoints
GET /columns:列出所有专栏
GET /columns/ID:列出某个专栏的信息
GET /columns/ID/posts:列出某个专栏的所有文章
POST /columns/ID/posts 在某个专栏创建文章(需要权限)
GET /posts/ID: 列出某个文章的信息
POST /users/login 用户登录
GET /users/current 获取当前用户登录信息(需要权限)
#7-3 使用 swagger在线文档查看接口详情
接口文档需要包括的点
- 第一 endponits,是具体的路径,或者说是网址。
- 第二 使用什么样的 method,get,post,put,patch 或者 delete
- 第三 发送请求要有什么样的参数,参数是在 url 上的 query还是 body 里面的复杂信息。
- 第四 请求返回的格式是什么样的。
如果使用文档,有可能是这样的
### endpoints
GET /teams/${ID}/players
### parameters
{
name: 'ID',
desc: '当前球队的 ID',
type: 'string'
}
### responses
**200响应**
{
"code": 0,
"data": [
{
"createdAt": "2020-06-05 16:45:22",
"description": "有一段非常有意思的简介,可以更新一下欧",
"name": "洛杉矶湖人",
"_id": "5eda0622acb0d2280c10385e"
},
{
"createdAt": "2020-06-05 16:45:22",
"description": "有一段非常有意思的简介,可以更新一下欧",
"name": "金州勇士",
"_id": "5eda0544ce65c327d718e57b"
}
],
"msg": "请求成功"
}
**401响应**
文档地址:(api.vikingship.xyz/)[http://ap…] 基于 (swagger)[swagger.io/]
#7-4 axios 的基本用法和独家后端API 使用(必看) 7-5 后端Icode终极使用方案
地址:coding.imooc.com/lesson/449.…
慕课网提供的 Icode 经过几次升级,现在把最终的解决方案整理如下,供同学们参考。 可以在 main.ts 中的拦截器里面一劳永逸的添加。
// 替换 baseURL
axios.defaults.baseURL = 'http://apis.imooc.com/api/'
// 下面的 icode 值是从慕课网获取的 token 值,可以在课程右侧的项目接口校验码找到
axios.interceptors.request.use(config => {
... 其他代码
// get 请求,添加到 url 中
config.params = { ...config.params, icode: '******' }
// 其他请求,添加到 body 中
// 如果是上传文件,添加到 FormData 中
if (config.data instanceof FormData) {
config.data.append('icode', '******')
} else {
// 普通的 body 对象,添加到 data 中
config.data = { ...config.data, icode: '******' }
}
return config
})
#7-6 使用vuex action 发送异步请求
官方文档地址:vuex.vuejs.org/zh/guide/ac…
Action 类似于 mutation,不同在于:
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作。
代码提交地址:git.imooc.com/coding-449/…
#7-7 使用vuex action 发送异步请求第二部分
代码提交地址:git.imooc.com/coding-449/…
#7-8 使用 async 和 await 改造异步请求
async 和 await 是基基于promises的语法糖,使异步代码更易于编写和阅读。通过使用它们,异步代码看起来更像是老式同步代码,因此它们非常值得学习。
文档地址:developer.mozilla.org/en-US/docs/…
代码示例:
// 例一
function hello() { return "Hello" };
hello();
async function hello() { return "Hello" };
hello();
hello().then((value) => console.log(value))
// 例二
async function hello() {
const greeting = await Promise.resolve("Hello");
return greeting
};
hello().then((value) => console.log(value));
代码提交地址:git.imooc.com/coding-449/…
#7-9 使用axios拦截器添加loading效果
Axios 拦截器文档地址:axios-http.com/docs/interc…
axios.interceptors.request.use(config => {
store.commit('setLoading', true)
return config
})
axios.interceptors.response.use(config => {
store.commit('setLoading', false)
return config
})
#7-10 7-11 Loader 组件编码
Bootstrap 提供的 Spinner:getbootstrap.com/docs/5.1/co…
Loader 第一部分编码地址:git.imooc.com/coding-449/…
Vue3 关于 Teleport 的官方文档:vuejs.org/guide/built…
Loader 第二部分编码地址:git.imooc.com/coding-449/…