商城项目请求数据的逻辑思路
做法逻辑
总体思路:
服务器拿到数据-创建对应的标签-创建对应的元素-对数据进行展示
这需要首页发送网络请求,axios通过接口拿到商品数据products,存储,传递给容纳商品的组件…
首先获取商品数据要想到怎么获取?获取之后怎么处理
一、AXIOS
1 要请求数据就要先用到axios
我选择在src文件夹中建立一个net文件夹,专门放置关于网络请求相关的东西,然后新建文件request.js封装axios
import axios from 'axios'
export function request(config) {
// 1.创建axios的实例
const instance = axios.create({
//随便写的接口,并不存在
baseURL: 'http://123.456.789.123:4545/api/m6',
timeout: 5000
})
// 2.axios的拦截器
// 2.1.请求拦截的作用
instance.interceptors.request.use(config => {
return config
}, err => {
// console.log(err);
})
// 2.2.响应拦截
instance.interceptors.response.use(res => {
return res.data
}, err => {
console.log(err);
})
// 3.发送真正的网络请求
return instance(config)
}
2.封装模块home.js层
这里要用到模块化的思路,本身可以直接在home.vue中发送网络请求, 但是考虑到最后首页home中会有多个步骤的元素以及标签,直接引入request,但是这样会把url 等参数这些东西和首页中vue组件相关的东西耦合在一起,显得冗杂。所以要在request和home.vue之间增加一个层home.js,同样子放在net中,对首页的请求都放在这里,方便对所有请求的url进行统一的管理
import {request} from "./request"
//放在这里很简便逻辑,相当于增加了一个层,比在home.vue中更好,逻辑更好看写成函数方便传参调用
export function getHomeXXX() {
return request({
url: '/home/data',
}
})
}
3.逻辑思路
假定tab栏有3个:A,B,C,每个栏都有上万个数据,我的想法是是一次性请求到所有的数据然后存储起来。
既然每个栏都有多个数据,那么就可以把它们看作对象,而整个tab栏是容纳ABC,本身也是一个对象prodcuts:{A:{},B:{},C:{} }
Js得到对象是一组由键-值组成的无序集合,所以给ABC中添加 list:[],即商品列表:【详情】,考虑到商品数量很多,可以再增加一个页数,表示商品加载到了第几页 page:0 即prodcuts: {
‘A’: {page: 0, list: []},
'B: {page: 0, list: []},
‘C’: {page: 0, list: []},
}所以总而言之要获取到list和page,由于type 可以表示这String,Number,Boolean,Function,Object,Array,Symbol,而且是ABC三种类型,所以home.js中
import {request} from "./request";
export function getHomeProducts(type, page) {
return request({
url: '/home/data',
//传两个参数
params: {
type,
page
}
})
}
二、home.vue请求数据
1.请求的思维逻辑及代码分离思路
到了这一步首先要想到的是home.js是在首页组件创建完毕的时候发送的请求,这里要用到生命周期的概念,created函数表示创建完毕。
所以关于请求的函数应该放在create(){}中
<script>
import {getHomeProducts} from "network/home";
import ....
export default {
name: "Home",
components: {
//注册组件
},
create(){
getHomeProducts(type, page).then(res =>{
//直接.then,因为home.js中 return 把request的返回值值返回了
//而函数request的返回值是promise所以.then拿到结果res
console.log(res);
...
...
})
},
}
到这一步并没有结束,虽然可以继续写,但是基于逻辑性和代码的美观程度,首先要想到的是分离,因为 getHomeProducts()是个方法,而vue中data表示数据,methods表示方法,computed是计算属性…
所以完全可以将此函数具体的方法卸载methods中,在create中调用,存放主要逻辑
created() {
// 请求商品数据
//create中调用的函数名和methods中函数名一致,调用要加this
this.getHomeProducts('A')
this.getHomeProducts('B')
this.getHomeProducts('C')
},
methods:{
getHomeProducts(type) {
//page不能写死要动态获取,根据传入的type拿到page
const page = this.getHomeProducts[type].page + 1;
getHomeProducts(type, page).then(res => {
console.log(res)
//此时res是局部变量,会销毁,所以要主动传入data中存储起来
.......
})
}
}
但如此还没有结束,res这个变量需要保存起来,还要使用
2.res保存的原因和垃圾回收机制
由于函数调用是压入函数栈中,函数栈保存函数调用过程中所有变量,都是临时的,调用结束弹出函数栈,弹出后释放所有变量,内存回收
故拿到result ,执行完这个方法后res就没了 ,它是个局部变量,引用箭头指向请求到的数据data,执行完被回收,指向data的箭头消失,data变成孤独的对象,这时候垃圾回收机制会发现没有引用指向data,就会将整个data回收掉,res就没有任何意义 因此在执行完之前要保存起来
所以此时:
data() {
return {
//result=null 这样得到的结果比较冗杂,就提取出来部分内容。
//data中的变量result不会被回收是因为属于这个组件,永远被引用
Products:{
'A': {page:0,list: []},
'B': {page:0,list: []},
'C': {page:0,list: []}
}
}
},
created() {
// 请求商品数据
//create中调用的函数名和methods中函数名一致,调用要加this
this.getHomeProducts('A')
this.getHomeProducts('B')
this.getHomeProducts('C')
},
methods: {
getHomeProducts(type) {
//page不能写死要动态获取,根据传入的type拿到page
const page = this.goods[type].page + 1;
getHomeProducts(type, page).then(res => {
// this.result = res;
console.log(res)
// this在箭头函数中是往上找作用域,而create中的this就是当前的组件对象,所以此处this.result拿到的就是data中的result,对res进行了保存
//即使函数执行完,最终数据也未消失
//拿到list空数组,push进去
//因为是商品数据这里是要一个个拿出来再一个个传入前者中
this.Products[type].list.push(...res.data.list);
//此时多了一组数据,页码就要加1
this.Products[type].page += 1
})
}
},
如我的案例中请求到的数据A栏
总结
基本上的请求思路是这样,至于怎么展示出来的总体思路如下:
(仅针对单页展示不带切换,ABC三栏都展示且带切换的话又要写很多,还要涉及到点击事件、监听事件等等)
单页展示:逻辑思路
基于组件化的思想,需要再新建一个组件(ProductsList.vue),让首页home.vue将商品数据传给他,拿到商品才能展示出来,在拿到数据之后展示的是object中的image,price,title之类的东西,而这些综合起来也是一个组件,此时应再建一个组件ProductsListItem.vue,这里传递数据是home向ProductsList,ProductsList向ProductsListItem传,后面根据商品的数量,通过v-for决定有多少个item
有思维逻辑不合理的地方还请大佬们指正