一、代码展示  
< template>  
  < div  class = " article-ranking" >  
    < div  class = " header" >  
      < h2  class = " title" >  {{ title }}</ h2>  
    </ div>  
    < div  class = " ranking-list" >  
      < div  v-for = " (article, index) in articles"   :key = " index"   class = " article-item" >  
        < div  class = " article-info" >  
          < h3  class = " article-title" >  {{ truncateTitle(article.title, 25) }}</ h3>  
          < p  class = " article-content" >  {{ truncateContent(article.summary, 50) }}</ p>  
          < div  class = " details" >  
            < div  class = " info-row" >  
              < p  class = " info-text" >  
                时间: < span  class = " time" >  {{ formatPublishTime(article.createTime) }}</ span>     |  
                浏览量: < span  class = " count" >  {{ formatViews(article.likeCount).formattedValue }}</ span>  
              </ p>  
            </ div>  
          </ div>  
        </ div>  
        < div  class = " divider" > </ div>   
      </ div>  
    </ div>  
    < div  class = " footer" >  
      < a  @click = " viewFullRanking"   href = " #"   class = " full-ranking-link" >  查看完整榜单</ a>  
    </ div>  
  </ div>  
</ template>  
< script  setup > 
import  {  defineProps }  from  'vue' ; 
const  props =  defineProps ( [ 'title' ,  'articles' ] ) ; 
const  viewFullRanking  =  ( )  =>  { 
  console. log ( 'View Full Ranking' ) ; 
} ; 
const  truncateContent  =  ( content,  maxLength )  =>  { 
  return  content. length >  maxLength ?  content. substring ( 0 ,  maxLength)  +  '...'  :  content; 
} ; 
const  truncateTitle  =  ( title,  maxLength )  =>  { 
  return  title. length >  maxLength ?  title. substring ( 0 ,  maxLength)  +  '...'  :  title; 
} ; 
const  formatPublishTime  =  ( publishTime )  =>  { 
  const  currentDate =  new  Date ( ) ; 
  const  articleDate =  new  Date ( publishTime) ; 
  const  timeDiff =  currentDate -  articleDate; 
  const  oneDay =  24  *  60  *  60  *  1000 ; 
  const  oneMonth =  oneDay *  30 ; 
  if  ( timeDiff <  oneDay)  { 
    const  hours =  Math. floor ( timeDiff /  ( 60  *  60  *  1000 ) ) ; 
    return  ` ${ hours} 小时前 ` ; 
  }  else  if  ( timeDiff <  oneMonth)  { 
    const  days =  Math. floor ( timeDiff /  oneDay) ; 
    return  ` ${ days} 天前 ` ; 
  }  else  { 
    const  months =  Math. floor ( timeDiff /  oneMonth) ; 
    return  ` ${ months} 个月前 ` ; 
  } 
} ; 
const  formatAbbreviation  =  ( value )  =>  { 
  if  ( value >=  10000 )  { 
    return  { 
      formattedValue :  Math. floor ( value /  1000 )  +  'w+' , 
      isLargeCount :  true , 
    } ; 
  }  else  { 
    return  { 
      formattedValue :  value, 
      isLargeCount :  false , 
    } ; 
  } 
} ; 
const  formatViews  =  ( views )  =>  formatAbbreviation ( views) ; 
const  formatLikes  =  ( likes )  =>  formatAbbreviation ( likes) ; 
 </ script>  
< style  scoped > 
.article-ranking  { 
  width :  300px; 
  border :  1px solid #ccc; 
  border-radius :  8px; 
  padding :  16px; 
  margin :  16px; 
  font-family :  'Arial' ,  sans-serif; 
} 
.article-title  { 
  font-size :  18px; 
  margin-bottom :  8px; 
  color :  #333; 
  text-align :  left;   
} 
.article-content  { 
  font-size :  14px; 
  color :  #777; 
  margin-bottom :  8px; 
  overflow :  hidden; 
  text-overflow :  ellipsis; 
  white-space :  nowrap; 
  text-align :  left;   
} 
.ranking-list  { 
  display :  flex; 
  flex-direction :  column; 
} 
.article-item  { 
  padding :  8px; 
} 
.article-info  { 
  display :  flex; 
  flex-direction :  column; 
} 
.details  { 
  flex-grow :  1; 
} 
.info-row  { 
  display :  flex; 
  flex-wrap :  wrap; 
  justify-content :  space-between; 
} 
.time  { 
  font-weight :  bold; 
  color :  #1890ff; 
} 
.count  { 
  font-weight :  bold; 
  color :  #1890ff; 
} 
.large-count  { 
  font-size :  12px;  
} 
.divider  { 
  height :  1px; 
  background-color :  #ddd; 
  margin :  8px 0; 
} 
.footer  { 
  text-align :  center; 
  margin-top :  16px; 
} 
.full-ranking-link  { 
  font-size :  14px; 
  color :  #1890ff; 
  text-decoration :  none; 
} 
.full-ranking-link:hover  { 
  text-decoration :  underline; 
} 
 </ style>  
  
 二、代码解读  
 <template> 部分:
 
  整个模板包含一个名为 “article-ranking” 的 div,宽度为300像素,具有圆角边框和一些内外边距,呈现为一个简单的排行榜容器。 模板包含标题(“header”)、排行列表(“ranking-list”)、文章项(“article-item”)、文章信息(“article-info”)、详细信息(“details”)、分隔线(“divider”)和页脚(“footer”)。     <script setup> 部分:
 
  使用 import { defineProps } from 'vue'; 导入 defineProps 方法,以定义组件的属性。 使用 defineProps(['title', 'articles']); 定义了两个属性:title 和 articles。 定义了一个 viewFullRanking 方法,用于在点击 “查看完整榜单” 链接时输出一条日志。 定义了 truncateContent 和 truncateTitle 方法,用于截断文章内容和标题,以确保它们不会超过指定的长度。 定义了 formatPublishTime 方法,用于根据发布时间计算并返回相对于当前时间的时间差,以便显示多久前发布的文章。 定义了 formatAbbreviation 方法,用于根据数值的大小返回格式化后的数值,并标记是否为较大的计数。 定义了 formatViews 和 formatLikes 方法,这两个方法分别使用 formatAbbreviation 处理浏览量和点赞数。     <style scoped> 部分:
 
  对排行榜容器及其子元素进行样式定义。 调整了标题和文章内容的样式,使其居左对齐。 使用了 flex 布局来组织文章项和详细信息。 设置了一些通用的样式,如字体大小、颜色、边框等。 使用了一些特定样式,如 divider 类,用于添加分隔线效果。 样式中还包含了一些交互效果,如链接的鼠标悬停样式。      
 三、结果展示