因为一部遮天,我用三种语言实现了腾讯国漫评分系统(二):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接口,从后台获取国漫数据实时渲染轮播,实时更新国漫介绍、评分等。

相关推荐
天天向上102414 分钟前
Vue 配置打包后可编辑的变量
前端·javascript·vue.js
芬兰y30 分钟前
VUE 带有搜索功能的穿梭框(简单demo)
前端·javascript·vue.js
好果不榨汁37 分钟前
qiankun 路由选择不同模式如何书写不同的配置
前端·vue.js
小蜜蜂dry37 分钟前
Fetch 笔记
前端·javascript
拾光拾趣录38 分钟前
列表分页中的快速翻页竞态问题
前端·javascript
小old弟39 分钟前
vue3,你看setup设计详解,也是个人才
前端
Lefan43 分钟前
一文了解什么是Dart
前端·flutter·dart
Patrick_Wilson1 小时前
青苔漫染待客迟
前端·设计模式·架构
写不出来就跑路1 小时前
基于 Vue 3 的智能聊天界面实现:从 UI 到流式响应全解析
前端·vue.js·ui
OpenTiny社区1 小时前
盘点字体性能优化方案
前端·javascript