基于斗鱼的娱乐直播视频平台--Vue移动端页面

介绍

本次项目是移动应用网页课程的大作业,项目使用github上一开源项目学习开发而来。
https://github.com/axhello/douyu-vue
本项目基本就是斗鱼手机移动端的复刻,除了没有评论功能,以外功能都差不多,其后端也是对接的官方的api接口。
源码压缩包地址
https://download.csdn.net/download/david2000999/85656221

学习建议

  1. 本项目可以帮助初学者更好理解完整的前后端开发模式,如何进行前后端数对接,其中格外注意数据传输和展示的格式
  2. 对于想要业务功能的同学,可以直接搭建一个后端自己的数据库,承接自己新业务上的数据,比如开发自己的评论区,和一些数据统计页面,添加数据分析功能等等。

使用

  1. 首先建立空文件打开控制台克隆代码到本地
git clone https://github.com/axhello/douyu-vue.git
  1. 然后进行相关依赖安装(前提本地安装好了npm 和 node)
npm install

npm run serve
  1. 运行后就可以得到
    在这里插入图片描述
    浏览器直接访问即可
    其中第二个局域网地址,可以让电脑连接手机热点后再启动项目,就可以使用第二个的局域网地址再手机上浏览器上进行直接访问了,可以更好体验移动端的适配性。

业务分区

(1)首页:最新活动也展示和热度最高的直播间
(2)分区页:星势力,网游竞技,单机热游,手游休闲,娱乐天地,科技文化,语音互动,语音直播,正能量,赛车竞技,京斗云
(3)分类页:各个具体分区页中的再分类页
(4)推荐区:直播区和视频区下方还有类似内容推荐内容
(5)搜索区:搜索栏中进行定向内容的搜索

功能设计

(1)直播内容展示
(2)搜索相关内容
(3)直播内容分类
(4)推荐相关直播内容
(5)热点内容滚动展示
(6)获取斗鱼安装下载

软件架构

在这里插入图片描述

运行截图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

核心代码

category.vue

<template>
  <div class="n-list clearfix">
    <a
      v-for="(catelist, index) in catelists"
      :key="index"
      class="n-list-item"
      @click="rooms(catelist)">
      <img class="live-feature" :src="catelist.icon">
      <p class="title">
        {{ catelist.cate2Name }}
      </p>
    </a>
  </div>
</template>

<script>
import { category } from '@/api/mobile'
export default {
  name: 'Category',
  data() {
    return {
      catelists: []
    }
  },
  watch: {
    '$route.params.id'() {
      this.fetchData()
    }
  },
  created() {
    this.fetchData()
  },
  methods: {
    fetchData() {
      category({ type: '' }).then(response => {
        console.log(response.data)
        const cate1Id = this.$route.params.id
        const cate2Info = response.data.cate2Info
        const result = cate2Info.filter(cate2 => cate2.cate1Id === cate1Id)
        this.catelists = result
      })
    },
    rooms(catelist) {
      this.$cookie.set('gameName', catelist.cate2Name)
      this.$router.push({
        name: 'rooms',
        params: { name: catelist.shortName }
      })
    }
  }
}
</script>

<style lang="scss">
.n-list {
  width: 100%;
  height: 100%;
  overflow-y: auto;
  background-color: #f4f4f4;
  z-index: 4;
  .n-list-item {
    margin: 0;
    padding: 0;
    float: left;
    width: 3.3rem;
    height: 3.3rem;
    border-right: 1px dashed #ddd;
    border-bottom: 1px dashed #ddd;
    text-align: center;
    font-size: 0.32rem;
    color: #000;
    margin-left: 1px;
    &:nth-child(3n) {
      border-right: none;
    }
    img {
      margin-top: 0.66666666rem;
      margin-bottom: 0.133333333rem;
      width: 1.62666666rem;
      height: 1.62666666rem;
      border-radius: 0.8133333rem;
    }
  }
}
</style>

detail.vue

<template>
  <iframe
    class="dy-inframe"
    frameborder="0"
    :src="roomId"></iframe>
</template>
<script>
export default {
  name: 'RoomDetail',
  computed: {
    roomId() {
      return '//m.douyu.com/' + this.$route.params.id
    }
  }
}
</script>
<style lang="scss">
.dy-inframe {
  width: 100%;
  height: 1050px;
  overflow-x: hidden;
  overflow-y: auto;
}
</style>

home.vue

<template>
  <section class="content">
    <div class="m-row">
      <v-swiper />
      <div class="live-list">
        <router-link
          v-for="(livelist, index) in livelists"
          :key="index"
          :to="{name: 'detail', params: { id: livelist.rid }}"
          class="live">
          <img
            class="live-feature"
            :src="livelist.roomSrc">
          <div class="live-title">
            {{ livelist.roomName }}
          </div>
          <div class="live-info">
            <span class="dy-name">
              {{ livelist.nickname }}
            </span>
            <span class="popularity">
              {{ livelist.hn }}
            </span>
          </div>
        </router-link>
      </div>
    </div>
  </section>
</template>

<script>
import VSwiper from '@/components/v-swiper'
import { home } from '@/api/mobile'
export default {
  components: {
    VSwiper
  },
  data() {
    return {
      livelists: []
    }
  },
  created() {
    this.fetchData()
  },
  methods: {
    fetchData() {
      home().then(response => {
        console.log(response.data[0].list)
        this.livelists = response.data[0].list
        // this.livelists = response.data.data
      })
    }
  }
}
</script>

<style lang="scss">
.m-row {
  background: #fff;
}
.live-list {
  position: relative;
  box-sizing: border-box;
  padding: 0 0.13333333rem 0.13333333rem;
  width: 100%;
  &:after {
    display: block;
    content: '';
    clear: both;
  }
  .live {
    float: left;
    position: relative;
    display: block;
    margin: 0.13333333rem;
    width: 4.6rem;
    height: 3.28rem;
    color: #333;
    font-size: 12px;
    .live-feature {
      position: absolute;
      display: block;
      top: 0;
      left: 0;
      width: 100%;
      height: 2.61333333rem;
      background-color: #000;
      border-radius: 0.1rem;
    }
    .live-title {
      position: absolute;
      bottom: 0;
      left: 0.2rem;
      width: 4rem;
      color: #000;
      white-space: nowrap;
      text-overflow: ellipsis;
      overflow: hidden;
      line-height: 0.66666667rem;
    }
    .live-info {
      position: absolute;
      bottom: 0.66666667rem;
      left: 0;
      width: 100%;
      color: #fff;
      /*padding: .1rem 0;*/
      border-bottom-left-radius: 0.2rem;
      border-bottom-right-radius: 0.2rem;
      background: linear-gradient(
        rgba(0, 0, 0, 0) 0%,
        rgba(0, 0, 0, 0.1) 30%,
        rgba(0, 0, 0, 0.8) 100%
      );
      .dy-name {
        white-space: nowrap;
        text-overflow: ellipsis;
        overflow: hidden;
        max-width: 2.746666666rem;
        display: inline-block;
        padding-left: 0.1rem;
      }
      .popularity {
        float: right;
        padding-right: 0.2rem;
      }
    }
  }
}
</style>

rooms.vue

<template>
  <div class="m-row">
    <div class="title">
      <svg-icon icon-class="tv" />
      <span>{{ cateName }}</span>
      <strong>{{ gameName }}</strong>
    </div>
    <div class="live-list clearfix">
      <router-link
        v-for="(roomlist, index) in roomlists"
        :key="index"
        :to="{name: 'detail', params: {id: roomlist.rid}}"
        class="live">
        <img class="live-feature" :src="roomlist.roomSrc">
        <div class="live-title">
          {{ roomlist.roomName }}
        </div>
        <div class="live-info">
          <span class="dy-name">
            {{ roomlist.nickname }}
          </span>
          <span class="popularity">
            {{ roomlist.hn }}
          </span>
        </div>
      </router-link>
    </div>
    <v-more-button>
      <div v-if="!hidden" class="more-button">
        <div v-show="!loading" @click="loadMore">
          加载更多
        </div>
        <div v-show="loading" class="ball-pulse">
          <div></div>
          <div></div>
          <div></div>
        </div>
      </div>
    </v-more-button>
  </div>
</template>
<script>
import VMoreButton from '@/components/v-more-button'
import { rooms } from '@/api/mobile'
export default {
  name: 'Rooms',
  components: {
    VMoreButton
  },
  props: {
    name: {
      type: String,
      default: ''
    }
  },
  data: () => ({
    roomlists: [],
    params: {
      name: '',
      page: 1
    },
    hidden: false,
    loading: false,
    cateName: '',
    gameName: ''
  }),
  created() {
    this.fetchData()
  },
  mounted() {
    this.cateName = this.$cookie.get('cateName')
    this.gameName = this.$cookie.get('gameName')
  },
  methods: {
    fetchData() {
      rooms({ page: this.params.page, type: this.name }).then(response => {
        this.loading = false
        this.roomlists = response.data.list
      })
    },
    loadMore() {
      this.loading = true
      this.params.page = ++this.params.page
      this.fetchData()
    }
  }
}
</script>
<style lang="scss" scoped>
.m-row {
  .play-icon {
    width: 0.3999999rem;
    height: 0.3999999rem;
    vertical-align: sub;
  }
  .title {
    font-size: 12px;
    margin-left: 10px;
    line-height: 0.8333333rem;
    strong {
      margin-left: 4px;
      color: #fa7122;
    }
  }
}
.live-list {
  .live {
    float: left;
    position: relative;
    display: block;
    margin: 0.13333333rem;
    width: 4.6rem;
    height: 3.28rem;
    color: #333;
    font-size: 12px;
    .live-feature {
      position: absolute;
      display: block;
      top: 0;
      left: 0;
      width: 100%;
      height: 2.61333333rem;
      background-color: #000;
      border-radius: 0.2rem;
    }
    .live-title {
      position: absolute;
      bottom: 0;
      left: 0.2rem;
      width: 4rem;
      color: #000;
      white-space: nowrap;
      text-overflow: ellipsis;
      overflow: hidden;
      line-height: 0.66666667rem;
    }
    .live-info {
      position: absolute;
      bottom: 0.66666667rem;
      left: 0;
      width: 100%;
      color: #fff;
      /*padding: .1rem 0;*/
      border-bottom-left-radius: 0.2rem;
      border-bottom-right-radius: 0.2rem;
      background: linear-gradient(rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.1) 30%, rgba(0, 0, 0, 0.8) 100%);
      .dy-name {
        white-space: nowrap;
        text-overflow: ellipsis;
        overflow: hidden;
        max-width: 2.746666666rem;
        display: inline-block;
        padding-left: 0.2rem;
      }
      .popularity {
        float: right;
        padding-right: 0.2rem;
      }
    }
  }
}
</style>

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值