目录
在一个项目中,最重要的是要把项目目录结构理清楚,知道什么文件写在什么位置,这样,在多人开发时会方便很多。
1.node_modules:npm加载项目的依赖模块(包括安装的其他插件)
2.assets:资源文件
3.components:公共组件文件
4.router:前端路由文件(管理页面导航)
5.service:请求接口地址文件
6.store:仓库文件,应用级数据(管理共享数据)
7.utils:一些工具模块(request请求、日期处理、统一注册事件)
8.views:页面目录
9.App.vue:项目根组件
10.main.js:入口js文件(全局的使用的各种变量、js、插件 都在这里引入 、定义)
11.package.json:npm包配置文件
二、Vant UI 组件库的使用
UI 组件库的引入能大大提高项目的开发效率,很多方法组件以及表单的处理都已经为我们封装好。
第一步:安装 Vant 组件
npm i vant@latest-v2
第二步:安装按需引入 Vant 组件的 babel 插件
npm i babel-plugin-import -D
第三步:在根目录下新建 babel 配置文件 babel.config.js
module.exports = {
presets: ['@vue/cli-plugin-babel/preset'],
plugins: [
[
'import',
{
libraryName: 'vant',
libraryDirectory: 'es',
style: true,
},
'vant',
],
],
};
第四步:组件注册,在项目 main.js 文件中进行全局注册
import Vue from 'vue';
import { Button } from 'vant';
Vue.use(Button);
第五步:在需要此组件的文件中使用
<!-- 注册完成后,在模板中通过 <van-button> 或 <VanButton> 标签来使用按钮组件 -->
<van-button type="default">默认按钮</van-button>
三、请求库 Axios 二次封装
请求库的封装在一个前后端分离的项目中尤为重要。因为这样可以做到 api 统一管理,不管接口数量增加多少,所有的接口都可以统一经过一个地方做处理,逻辑会比较清晰。
第一步:安装 axios
npm i axios -S
第二步:在 src 目录下新建 utils 文件夹,在 utils 文件夹内新建 axios.js 文件
import axios from 'axios';
import { Toast } from 'vant';
axios.defaults.baseURL =
process.env.NODE_ENV == 'development'
? '//xxx.site/api/v1'
: '//xxx/api/v1';
axios.defaults.withCredentials = true;
axios.defaults.headers['X-Requested-With'] = 'XMLHttpRequest';
axios.defaults.headers['token'] = localStorage.getItem('token') || '';
axios.defaults.headers.post['Content-Type'] = 'application/json';
axios.interceptors.response.use((res) => {
if (typeof res.data !== 'object') {
Toast.fail('服务端异常!');
return Promise.reject(res);
}
if (res.data.resultCode != 200) {
if (res.data.message) Toast.fail(res.data.message);
if (res.data.resultCode == 416) {
window.vRouter.push({ path: '/login' });
}
return Promise.reject(res.data);
}
return res.data;
});
export default axios;
四、公共组件的封装
公共组件的封装也是很有必要,当多数页面需要的内容一样时,这时如果每个页面都去开发,那么会出现代码冗余等不必要的麻烦,出现这种情况为什么不去封装一个组件呢?在需要的页面进行引入就可以了。
第一步:在 components 文件夹下新建一个公共组件,比如 NavBar.vue ,开发一个底部导航的组件
第二步:在所需页面进行引入注册并使用
1)如果主页面都需要引入,可以在 App.vue 中进行引入判断:
<template>
<div id="app">
<router-view />
<!-- 3.使用 -->
<nav-bar v-if="isShowNav"></nav-bar>
</div>
</template>
<script>
//1.引入
import navBar from "@/components/NavBar";
export default {
data() {
return {
isShowNav: true,
ShowMenuList: ["/", "home", "category", "cart", "user"], // 该变量为需要导航栏的数组
};
},
//2.注册
components: {
navBar,
},
watch: {
$route(to, from) {
// 通过 ES6 提供的 includes 属性判断 to.name 是否包含在数组内
if (this.ShowMenuList.includes(to.name)) {
this.isShowNav = true;
} else {
this.isShowNav = false;
}
},
},
};
</script>
2)如果只有页面中某个位置需要使用,在页面中直接引入、注册、使用即可:
<template>
<div>
<!-- 3.使用 -->
<nav-bar></nav-bar>
</div>
</template>
<script>
//1.引入
import navBar from "@/components/NavBar";
export default {
//2.注册
components: {
navBar,
},
};
</script>
五、前端鉴权方式
1. cookie
利用服务器端的 session (会话) 和浏览器端的 cookie 来实现前后端认证。
在服务器端创建一个会话(session),将同一个客户端的请求都维护在各自的会话中,每当请求到达服务器端的时候,先去查一下该客户端有没有在服务器端创建 session ,如果有则认证成功,否则认证失败。
弊端:
- 服务器内存消耗大:用户每做一次应用认证,应用就会在服务器做一次记录,以方便用户下一次请求时使用,通常来讲 session 保存在内存中,随着认证用户的增加,服务器的消耗就会增大。
- 易受到 CSRF 攻击:基于 cookie 的一种跨站伪造攻击,基于 cookie 来进行识别用户的话,用户本身就携带了值,cookie 被截获,用户就很容易被伪造。
- 如果 session 保存在内存中,当增加为多台服务器时,会涉及到 session 共享问题,因此不利于服务器的扩展。
2. token
token 是用户身份的验证方式,我们通常叫它:令牌。当用户第一次登录后,服务器生成 token 并将此 token 返回给客户端,以后客户端只需带上这个 token 前来请求数据即可,无需再次带上用户名和密码。
验证流程:
- 客户端使用用户名和密码请求登录
- 服务端收到请求,去验证用户名和密码
- 验证成功后,服务端会签发一个 token ,再把这个 token 发送给客户端
- 客户端收到 token 以后可以把它存储起来,比如放在 Cookie 里或 Local Storage 里
- 客户端每次向服务端请求资源的时候需要带着服务端签发的token
- 服务端收到请求,然后去验证客户端请求里面带着的 token(请求头),如果验证成功,就向客户端返回请求的数据
它不需要在服务端去保留用户的认证信息或者会话信息,这就意味着基于token认证机制的应用不需要去考虑用户在哪一台服务器登录了,解决了 session 扩展性的弊端。
弊端:
- 占带宽:正常情况下token要比 session_id 更大,需要消耗更多流量,挤占更多带宽。(不过几乎可以忽略)
- 性能问题:相比于 session-cookie 来说,token 需要服务端花费更多的时间和性能来对 token 进行解密验证.其实 Token 相比于 session-cookie 来说就是一个"时间换空间"的方案。
六、前端调用后端接口流程
在对 axios 进行二次封装之后,前端请求的所有接口都会经过这个地方。在请求接口地址的文件中引入即可使用。
第一步:在 service 文件夹下新建一个js文件,比如:good.js
import axios from '../utils/axios';
export function getCategory() {
return axios.get('/categories');
}
export function search(params) {
return axios.get('/search', { params });
}
export function getDetail(id) {
return axios.get(`/goods/detail/${id}`);
}
第二步:在页面中进行引入并使用
<template>
<div>
<div class="good" v-for="(item, index) in categoryData">
...
</div>
</div>
</template>
<script>
import { getCategory } from "../service/good";
export default {
data() {
return {
categoryData: []
}
},
async mounted() {
const { data } = await getCategory();
this.categoryData = data;
},
}
</script>
以上代码在mounted生命周期函数中使用 async...await... 进行请求数据的目的是:为了能够等数据请求完全之后再赋值显示。
注意事项:
- 在请求地址文件中使用时要注意请求方式:get、post、delete等。
- 注意接口参数的传递。