因为一部遮天,我用三种语言实现了腾讯国漫评分系统(二):vue前端开发篇

前言

"仙路尽头谁为峰,一见无始道成空。"

2013年初读遮天,十年后遮天的动漫正式上线。依稀记得高中记忆力"三十年河东三十年河西"的萧炎和独断万古的荒天帝。不知道当年经典绝伦的小说,如今改成动漫口碑如何。

于是就打开腾讯视频看看评分,每个视频都要点开才能看到评分和介绍。随即就萌生了用技术整合国漫评分内容的想法。最后历经一周,完成了一个简单的评分展示系统。

上一篇文章写的是腾讯国漫数据获取的部分,这篇文章主要写的是使用vue生态构建前端的部分。

静态展示: 动态展示:

二. 前端设计

前端使用webpack + vue + ElmentPlus + TypeScript + scss,使用vue脚手架创建一个项目,导入到IDE。

页面左侧做一个垂直轮播,右侧显示评分、简介等信息,每次刷新

项目布局

首先使用ElementPlus的container进行布局,将整个页面分为aside和main左右两个区域。

左侧Aside的显示轮播组件<Carousel>,轮播使用的是ElementPlus的carousel组件,直接从官网针贴代码到组件中。

这时候访问前台页面。

从页面看,基本的布局就完成了,接下来就是对轮播优化、main区域展示设计以及css细节优化,先对轮播图进行样式调节。

轮播图

轮播图使用的是ElementPlus的el-carousel走马灯组件。动漫的封面是长图,像素是770 * 1080,这里进行50%的等比例缩放,来设置轮播框的宽高。

下载了一张封面图,通过img标签放在el-carousel-item中,然后进行css设置:

css 复制代码
$width: 385px;
$height: 540px;

img {
  width: $width;
  height: $height;
  box-shadow: 1px 1px 1px #888888;
  border-radius: 16px;
}

.carousel {
  bottom: 80px;
}

.el-carousel__item {
  width: $width;
  height: $height;
  padding-left: 50px;
  background-color: rgba(0, 0, 0, 0);
}

.el-carousel__mask {
  background-color: rgba(0, 0, 0, 0) !important;
}

主要是对img和el-carousel__item组件做了一些细节、定位的设计。这里提一下el-carousel__mask,必须要要加important来强制改变为透明颜色,这样才能和背景色颜色一样。

最后大概是这个样子。

再看看main区域的数据展示。

国漫名称展示

d这一块其实是在后面才设计的,但是布局是在最上方,这里就先说说这里实现。样例如下:

这里没有啥设计,定义了一个title.vue。评分星号是用ElementPlus的el-rate 实现的,标签使用el-tag实现的。

然后就是一些css的微调:

css 复制代码
 .header_div {
    width: 510px;
    height: 138px;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
  }

  .tags {
    color: white;
    font-size: 12px;
    opacity: 0.6;
    margin-left: -4px;

  }

  .rate-star {
    margin: 0px 0 0 20px
  }

  .mx-1 {
    margin: 4px 0 0 7px;
  }

  .title-name {
    color: white;
    font-size: 40px;
    box-shadow: #141414;
  }

评分数据展示

定义了一个score组件,来简单设计了一个评分推荐页面

没有前端设计的这种艺术细胞,所以这里打算复刻腾讯视频的评分展示页。评分数据展示我使用的是ElementPlus的el-card组件,

javascript 复制代码
<el-card class="box-card">

</el-card>

<style scoped lang="scss">
  $background_layout: rgb(236 217 217 / 5%);
  .box-card {
    width: 326px;
    height: 138px;
    background: $background_layout;
    border: none;
  }
</style>

这里只对长宽、颜色进行了简单的定义,el-card先不填充内容。

1. svg图标定义

评分两侧的两个svg是wheat图标,先去icons网站下载wheat svg。

因为想找个一模一样的比较麻烦,我就用Adobe Illustrator做了一个水平镜像。这样就获取了评分两侧的wheat,然后放到@/assets/svg下面。

接着在项目中定义Icon组件,用来引用svg图标。

javascript 复制代码
setup(props) {
    const iconStyle = computed(() => {
        const {size, color} = props
        let s = `${size.replace('px', '')}px`
        return {
            fontSize: s,
            color: color,
        }
    })
    if (props.name.startsWith('el-icon-')) {
        return () => h('el-icon', {
            class: 'icon el-icon',
            style: iconStyle.value
        }, [h(resolveComponent(props.name))])
        // svg图标
    } else if (props.name.startsWith('svg-icon')) {
        return () => h(svg, {name: props.name, size: props.size, color: props.color})
    } else {
        return () => h('i', {
            class: 'icon ' + props.name,
            style: iconStyle.value
        })
    }
  }

然后在vue.config.js中使用svg-sprite-loader加载器,将svg文件加载进来,Icon组件就可以引用svg。

javascript 复制代码
chainWebpack: (config) => {
    // 内置的svg处理排除指定目录下的文件
    config.module.rule('svg').exclude.add(resolve('src/assets/svg')).end()

    config.module
      .rule('svg-sprite-loader')
      .test(/\.svg$/)
      .include.add(resolve('src/assets/svg'))
      .end()
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({
        symbolId: 'svg-icon_[name]'
      })
  }

在原有的svg文件名前加上svg-icon_ 前缀。这样,wheat的svg就可以被Icon组件引用。这一块的具体实现我在之前拆解BuildAdmin的Icon组件和定义svg图标里面都有写,这里不做赘述,有兴趣的话可以参考之前的文章。

这样就能实现完成图标的引用了:

javascript 复制代码
<Icon class="nav-menu-icon"  name="svg-icon_wheat-left" />
<Icon class="nav-menu-icon"  name="svg-icon_wheat-right" />

通过Icon组件中name属性,就能使用刚刚加载的的svg图标。

从上图看,两个svg图标是垂直分布,而我想要得的水平分布,所以接下来就利用css进行布局。

2. 评分推荐区域设计

从整体分布来看,因为既有垂直又有水平分布,所以这里要用flex弹性布局,即display:flex。

从左到右,分为评分区域和推荐区域两个div。按照这个思路,这里先将html部分写出来。

html 复制代码
<template>
  <el-card class="box-card">
    <div class="user-rating-col__container">
      <div class="user-rating-card__left"></div>
      <div class="user-rating-card__right"></div>
    </div>
  </el-card>
</template>

定义了user-rating-card的左右div。left是评分区域,rigth是推荐区域。因为两个区域是水平分布的,这里先将父div设置为弹性分布:

css 复制代码
.user-rating-col__container {
    display: flex;
    flex-wrap: nowrap;
}

默认是row水平分布,所以这里可以不定义flex-direction

评分区域

left评分div从上到下分为垂直分布的三个部分,所以是布局方向flex-directioncolumn垂直分布。中间部分是由两个svg,一个评分span构成,使用默认水平分布。

user-rating-card__left中定义html:

html 复制代码
<div class="user-rating-card__left">
    <span class="user-rating-card__title">腾讯视频评分</span>
    <div class="card-wheat">
        <Icon class="nav-menu-icon_left" name="svg-icon_wheat-left2" size="38" color="silver"/>
        <div class="card-wheat__percent"> 9.7</div>
        <Icon class="nav-menu-icon_right" name="svg-icon_wheat-right2" size="38" color="silver"/>
    </div>
    <span class="user-rating-card__desc">83.4万人点评</span>
</div>

中间的三个部分看做一个整体,都放在一个card-wheat div进行flex布局。

然后先对user-rating-card__left作垂直分布的设置。

css 复制代码
.user-rating-card__left {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    margin-right: 10px;
    font-size: 10px;
    line-height: 16px;
}

将评分部分设置为column 列分布,居中对齐。再对中间部分card-wheat 做一个水平分布,并使用align-itemsjustify-content实现水平和垂直居中分布。

css 复制代码
.card-wheat {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin: 9px 0 15px;
}

水平分布就不用设置flex-direction,因为默认就是row。最后就是对评分和span文字的css定义:

css 复制代码
.card-wheat__percent {
    display: flex;
    justify-content: center;
    width: 52px;
    font-size: 22px;
    line-height: 36px;
    font-weight: 500;
    color: #ff7612;
    white-space: nowrap;
}

span {
  color: white;
  white-space: nowrap;
}

再看评分区域,已经初具雏形。

里面wheat的svg后来我又给设置成银色了。下面点评的span透明度也设置成了0.6。这个就从后面接着看吧。

弹性布局,贵在弹性二字,这里看着虽然居中,等定义user-rating-card__right区域后再看效果。

推荐区域

先将推荐区域user-rating-card__right进行flex水平布局。

css 复制代码
.user-rating-card__right {
    flex: 1 1 auto;
    display: flex;
    align-items: center;
}

再对user-rating-card__right布局分析。文字垂直靠右对齐,比例条部分垂直分布,所以分左右两个div水平布局,div内垂直布局。

左侧就是文字lable,右侧就是比例展示,左侧就是一个简单的div:

html 复制代码
<div class="user-rating-card__labels">
    <div class="user-rating-card__label"> 强推</div>
    <div class="user-rating-card__label"> 推荐</div>
    <div class="user-rating-card__label"> 可看</div>
    <div class="user-rating-card__label"> 一般</div>
    <div class="user-rating-card__label"> 不推荐</div>
</div>

然后定义css样式:

css 复制代码
.user-rating-card__labels {
    display: flex;
    flex-direction: column;
    margin-right: 8px;
}

.user-rating-card__label {
    flex: 0 0 auto;
    display: flex;
    justify-content: flex-end;
    white-space: nowrap;
    height: 16px;
    margin: 1px 0;
    font-size: 10px;
    padding: 0 12px;
    color: white;
}

设置flex-direction为垂直对齐,将justify-content 设置为flex-end来尾部对齐,margin后面和比例条一起调整对齐。

右侧比例展示,我使用的是ElementPlus的Progress进度条组件,还可以设置各种颜色。

html 复制代码
<div class="user-rating-card__bars">
   <el-progress v-for="(item, index) in customColors" :percentage="item.percentage"
              :color="item.color" :key="index" :show-text="false"/>
</div>

<script setup lang="ts">
  import {reactive} from 'vue'
  const customColors = reactive([
    {color: '#f56c6c', percentage: 20},
    {color: '#e6a23c', percentage: 40},
    {color: '#5cb87a', percentage: 60},
    {color: '#1989fa', percentage: 80},
    {color: '#6f7ad3', percentage: 100},
  ])
</script>

在script中定义了颜色和百分比,v-for循环遍历创建了五个el-progress ,其中percentage 组件为显示的百分比,show-text设置为false,这样不显示进度文本。

然后对user-rating-card__bars垂直布局:

css 复制代码
.user-rating-card__bars {
    display: flex;
    flex-direction: column;
    margin-top: 11px;
}

.el-progress--line {
  margin-bottom: 12px;
  width: 200px;
}

el-progress--line要设置进度条宽度,margin-top和margin-bottom是为了和左侧文字对齐,自己调出来的。

后面将box-card的width改成了510px,同时对各个组件使用margin进行了微调。最后展示效果:

3. 介绍页设计

定义了一个description组件,展示了动漫简介、title、热度、剧集等基本信息。

这里分成了两个部分,动漫简介其实就是一个div。

动漫简介

这部分的html两三行,没什么好说的。主要实现就是当文本过长是,如何限制住文本,我这里用css设置,最多只显示4行,多余的就用...表示。

css 复制代码
.description {
    width: 510px;
    height: 138px;
    color: white;
    opacity: 0.75;
    font-size: 16px;
    margin-top: 40px;
    // 多行隐藏
    max-height: 5rem;
    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 4;
    line-height: 1.2rem;
}

热度、title

同样使用的是el-card卡片进行的展示,左边的图标是从网上下载的svg,右侧是简单的span文本展示,这里看看html。

html 复制代码
<el-card class="box-card">
  <div class="playlist-intro-info__item">
    <Icon name="svg-icon_title" size="12"/>
    <span class="title">少年不屈,异火不熄!</span>
  </div>

  <div class="playlist-intro-info__item">
    <Icon name="svg-icon_fire" size="12"/>
    <span class="hot">11935 · 内地 · 2015 · 虐心爱情 · 东方玄幻</span>
  </div>

  <div class="playlist-intro-info__item">
    <Icon name="svg-icon_time" size="12"/>
    <span class="title">共158集,会员看全集</span>
  </div>
</el-card>

然后就是定义css样式,对playlist-intro-info__item父div做一个flex弹性分布,用来调整居中。

css 复制代码
.playlist-intro-info__item {
  display: flex;
  justify-content: center;
  margin-top: 12px;
}

本来我将justify-content设置成了flex-start靠左分布,后来觉得设置成center更有趣些。

接着就是对svg和span进行css定义:

css 复制代码
span {
  color: white;
  font-size: 12px;
  opacity: 0.6;
  margin-left: 8px;
}

svg {
  margin-top: 2px;
}

基本上都是对细节和位置的细微调整。至此的页面设计就完成了就下来就是在main区域进行布局排版。最后效果如下:

感觉右边空荡荡的,我直接反手修改布局。设置了左右两个el-aside。

这样就有两个炫酷的轮播框了...

轮播图优化

1. 镜像

但是这时候问题就又来了,左右轮播图是镜像 关系。左侧轮播框指示器在右侧,右侧轮播框的也在右侧,这样就不对称了,调了一阵儿也没成功,后来索性直接使用indicator-position将指示器去掉了。

html 复制代码
<el-carousel indicator-position="none" />

但是图片的box-shadow 阴影都在右侧,也不是镜像关系,所以我直接复制了一个carousel-right.vue

然后修改box-shadow,让其在左侧显示阴影。

css 复制代码
img {
  box-shadow: -1px 1px 1px #888888;
}

这样就完成进行两个轮播图的镜像。

2. 轮播同步

这时候两侧轮播图是各玩各的,在el-carousel 有一个属性:pause-on-hover,即鼠标悬浮时暂停自动切换,这个默认值为true。当我悬停在一个轮播框的时候,这个轮播图其实就已经不动了,但另一个还在轮播。所以这里就要想着如何将两个轮播图同步起来。

这时候我就想到了el-carousel的autoplay自动属性了。当我悬停在一个轮播图的时候,就触发一个hover事件,将另一轮播图的autoplay设置为false,这样两个轮播图都不会动了。所以,这里得先定义一个全局状态变量,这里我用的是pinia。

定义状态

定义了一个useCarousel 状态,里面有autoplay属性,初始值为true,自动播放并定义了鼠标进入悬停的mouseEnter和鼠标离开的mouseLeave两个方法。

当鼠标悬停在轮播框,会触发轮播图的pause-on-hover停止播放属性,同时调用mouseEnter,将autoplay设置为false.当鼠标离开,轮播图恢复播放,这时候调用mouseLeave(),将autoplay设置为true。所以两个事件需要绑定在轮播图组件上。

cartoonData变量是为后面存储后台请求预留的字段。

绑定事件

在两个轮播图的el-carousel组件中做以下修改。

html 复制代码
<el-carousel 
    :autoplay="carouselStore.state.autoplay"
    @mouseenter="carouselStore.mouseEnter"
    @mouseleave="carouselStore.mouseLeave"
/>

<script setup lang="ts">
  import {useCarousel} from '@/stores/carousel'
  const carouselStore = useCarousel()
</script>

el-carousel的autoplay属性由全局状态控制,并用v-on(@)来绑定鼠标悬停和离开事件。通过修改autoplay来通知另一个轮播框是否暂停/恢复播放。

效果如下:

这样,前端部分就涉及完成了,虽然也没什么美感。。接下来就是从后台写一个获取数据的接口,来根据轮播图修改对应的评分等展示信息。

结语

本篇文章主要使用vue、Element Plus构建了前端页面,并对vue生态中常用的技术做了详细的使用场景介绍。通过代码和动图的结合,实现了初版的腾讯国漫评分展示系统。

下一篇文章就是开发后端的API接口,从后台获取国漫数据实时渲染轮播,实时更新国漫介绍、评分等。

相关推荐
长天一色9 分钟前
【ECMAScript 从入门到进阶教程】第三部分:高级主题(高级函数与范式,元编程,正则表达式,性能优化)
服务器·开发语言·前端·javascript·性能优化·ecmascript
NiNg_1_23427 分钟前
npm、yarn、pnpm之间的区别
前端·npm·node.js
秋殇与星河29 分钟前
CSS总结
前端·css
BigYe程普1 小时前
我开发了一个出海全栈SaaS工具,还写了一套全栈开发教程
开发语言·前端·chrome·chatgpt·reactjs·个人开发
余生H1 小时前
前端的全栈混合之路Meteor篇:关于前后端分离及与各框架的对比
前端·javascript·node.js·全栈
花花鱼1 小时前
@antv/x6 导出图片下载,或者导出图片为base64由后端去处理。
vue.js
程序员-珍1 小时前
使用openapi生成前端请求文件报错 ‘Token “Integer“ does not exist.‘
java·前端·spring boot·后端·restful·个人开发
axihaihai1 小时前
网站开发的发展(后端路由/前后端分离/前端路由)
前端
流烟默1 小时前
Vue中watch监听属性的一些应用总结
前端·javascript·vue.js·watch
2401_857297912 小时前
招联金融2025校招内推
java·前端·算法·金融·求职招聘