美食杰(个人主页) 下

逻辑:先实现tab切换在个人主页router的组件中加入子组件,通过绑定单击事件,编程式导航的形式,来跳转不同的子组件中显示不同的内容,之后从api里拿接口封装接口请求,拿到数据通过父传子的形式把请求的数据传给子组价

布局的话就使用element-ui组件的布局,这里注意使用的是element-ui组件绑定单击事件的时候,用@tab-cilck="事件()"

<el-tabs class="user-nav" v-model="activeName" @tab-click="myclick()">
      <el-tab-pane label="作品" name="works"></el-tab-pane>
      <el-tab-pane label="粉丝" name="fans"></el-tab-pane>
      <el-tab-pane label="关注" name="following"></el-tab-pane>
      <el-tab-pane label="收藏" name="collection"></el-tab-pane>
    </el-tabs>

在data设置activeName:"works",初始值设为works,利用v-model="activeName",点击不同的tab来改变activeName中的值,值为tab中的name属性,之后绑定事件利用编程式导航实现router跳转

myclick(){
      this.$router.push({  //编程式导航,跳到不同的子组件中
        name:this.activeName, 
        query:{
          ...this.$route.query
        }
      })
    }

问题:为什么要在写编程式导航是 要传query参数?                                                                          因为当我们访问别人的个人主页的时候首先都知道是需要userId值的,当我们在别人的个人主页,tab切换是会把之前的userId给覆盖,会直接跳到我自己的个人主页,所以要传query参数目的是为了你访问别人的个人主页,tab切换数就算把之前的userId的参数给覆盖,但我们又通过query传了userId值,就可以在别人的个人主页,实现tab切换啦!

/**
 * 拿到用户发布的菜谱,可做筛使用选
 * @export
 * @param {Object} [params] - 不填写,则获取所有的菜谱
 * @param {string} [params.userId] - 指定用户的菜单
 * @param {string} [params.classify] - 按照菜单分类,进行筛选
 * @param {string} [params.property] - 指定菜单属性进行筛选
 * @param {string} [params.property.craft] - 按工艺筛选
 * @param {string} [params.property.flavor] - 按口味筛选
 * @param {string} [params.property.hard] - 按难度筛选
 * @param {string} [params.property.people] - 按人数筛选
 * @param {string} [params.page] - 指定页码
 * @returns
 */
export async function getMenus(params){
  return await http.get('/menu/query', {params});
}

/**
 * 获取指定用户的粉丝
 * @export
 * @param {Object} [params] - 
 * @param {string} [params.userId] - 指定的用户id
 * @returns
 */
export async function fans(params){
  return await http.get('/user/fans', {params});
}

/**
 * 获取指定用户关注的人
 * @export
 * @param {Object} [params] - 
 * @param {string} [params.userId] - 指定的用户id
 * @returns
 */
export async function following(params){
  return await http.get('/user/following', {params});
}

/**
 * 获取指定用户的收藏的菜单
 * @export
 * @param {Object} [params] - 
 * @param {string} [params.userId] - 指定的用户id
 * @returns
 */
export async function collection(params){
  return await http.get('/user/collection', {params});
}

拿到我们数据的接口 引入到个人主页的组件中,因为接口较多,所以我们可以吧接口进行封装

import {getMenus, following, fans, collection} from '@/service/api';

const getOtherInfo ={
  async works(params){
  return (await getMenus(params)).data
  },
   async following(params){
   return (await following(params)).data
  },
    async fans(params){
    return (await fans(params)).data
  },
   async collection(params){
    return (await collection(params)).data
  }
}

有两种方式请求数据tab切换中不同的数据   一.自定义一个事件,在事件中进行请求数据,之后在 之前watch监听$route中直接调用先这个事件  二.直接之前watch监听$route中,进行数据请求---具体代码如下:

 async getinfo(){  //自定义事件
    //调用不同接口
     let data=await getOtherInfo[this.activeName]({userId:this.userInfo.userId})
    //  问题2:切换tab过快时,依然报错key重复,并且数据显示不正常
    //  原因:因为ajax返回数据的时候 快慢的问题,显示的是最后一次ajax返回的数据,无法识别对应的请求
    //  解决:在请求中定义一个标识,在返回的数据中添加标识,如果返回的数据和当前的标识相同,再渲染
      // console.log(data)
      if(this.activeName === data.flag){
       this.list=data.list
      }
    }
   

this.getinfo()  //调用自定义事件 在监听路由中调用
watch:{
    $route:{
     async handler(){
        let {userId} =this.$route.query;    //自己的个人主页
        this.isOne= !userId || userId===this.$store.state.userInfo.userId;
        //这个this.isOne是 没有userId或者userId等于vuex的数据的userId
        if(this.isOne){ //如果为true就把vuex的数据重新赋值给data的userInfo
          this.userInfo=this.$store.state.userInfo
        }else{          
          const data=await userInfo({userId})  //别人的个人主页
          //需要请求接口通过传入参数userId来跳入不同的别人主页
          console.log(data)             
          this.userInfo=data.data
        }
        this.activeName=this.$route.name;
        // 还有一种方式:直接在这里调用封装的接口数据,来获取数据
        let data=await getOtherInfo[this.activeName]({userId:this.userInfo.userId})
          console.log(data)
          this.list=data.list
        
      },
      immediate:true //页面初始化立即执行
    }
  },

之后数据就请求出来了,在data设置list的一个空数组来接收数据,之后通过绑定自定义属性名值为我们请求的数据list,在子组件中通过props来接收(父传子) ,在各自的子组件中渲染数据即可,也把activeName也通过(父传子的方式) 传到子组件中(后说原因) -----------这里啰嗦一句:(父传子),在子组件中props中接收的格式有两种 1.props:['list']   2.props:{type:'指定类型',default:'默认值' }

<router-view :info="list" :activeName="activeName"></router-view>  

之后判断如果请求的数据有值得话直接渲染,没数据就提示  如图: 

 这个是没数据的时候的提示,有数据的渲染页面即可 !!! ---------  这是就要进行判断通过(父传子)的数据 在提示的标签中用v-if来判断传过来的值是否有长度,也就是判断是否有数据 v-if="!info.length"  判断他如果没有数据就显示提示标签,我们的作品页和收藏页是同一个页面,我们之前把activeName传过来过,在不同的标签中也用v-if判断 代码如下:

<div class="info-empty" v-if="!info.length">
			<div v-if="activeName==='works'">
				<p>私房菜不要偷偷享用哦~~制作成菜谱与大家分享吧!</p>
        	<a href="">发布菜单</a>
			</div>
		</div>
    <div class="info-empty" v-if="!info.length">
			<div v-if="activeName==='collection'">
				<p>还没有收藏任何的菜谱,去搜自己喜欢的菜谱,收藏起来吧。</p>
        <a href="">菜谱大全</a>
			</div>
		</div>

之后就完成了,不过有bug!!! 当我们tab切换的时候会提示我们一个这样的报错                   vue.runtime.esm.js?2b0e:619 [Vue warn]: Duplicate keys detected: '5d613120ac558b4d879824ba'. This may cause an update error. -->意思是检测到重复的键,可能导致更新错误 -----> 解决方法:我们发现我们进去的时候是不会报这样的错误的,当我们在tab切换的时候,才会报错,所以我们在他每次拿到数据渲染保存玩之后,把list里的数据清空

   //点击切换tab
    myclick(){
      //问题1:因为各个二级路由接收的字段,全是info,所有会造成数据重复
      //解决:第一次保存数据到数据中时,没有问题,所以,每次保存前,都清空一下数组
      this.list=[]
      this.$router.push({  //编程式导航,跳到不同的子组件中
        name:this.activeName, 
        query:{
          ...this.$route.query
        }
      })
    }

之后还有一个bug!,就是当我们过度使用tab切换时,还会报上面同样的错误,解决办法

async getinfo(){  //自定义事件
    //调用不同接口
     let data=await getOtherInfo[this.activeName]({userId:this.userInfo.userId})
    //  问题2:切换tab过快时,依然报错key重复,并且数据显示不正常
    //  原因:因为ajax返回数据的时候 快慢的问题,显示的是最后一次ajax返回的数据,无法识别对应的请求
    //  解决:在请求中定义一个标识,在返回的数据中添加标识,如果返回的数据和当前的标识相同,再渲染
      // console.log(data)
      if(this.activeName === data.flag){
       this.list=data.list
      }
    },

给每次请求的接口数据,设置一个标识,当他等于这个标签才会拿到数据,这样就不会出现重复的键的错误啦!
const getOtherInfo ={
  async works(params){
  let data=(await getMenus(params)).data
  data.flag="works"
  return data
  },
   async following(params){
    let data=(await following(params)).data
    data.flag="following"
    return data
  },
    async fans(params){
     let data=(await fans(params)).data
     data.flag="fans"
     return data
  },
   async collection(params){
     let data=(await collection(params)).data
     data.flag="collection"
     return data
  }
}

这里在啰嗦一句:在函数作用域中var是局部变量,函数销毁var也会更这销毁,var除了在函数中声明是局部的,在其他的地方声明的都是全局的,因为var可以跨块访问!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值