赞
踩
目录
在移动应用开发领域,列表展示是最常见的需求之一,无论是新闻列表、商品目录还是社交动态,一个清晰、响应迅速的列表组件是提升用户体验的关键。
Uni-App作为一款优秀的跨平台开发框架,提供了丰富的组件库,其中uni-list组件就是专为列表展示而设计的高效解决方案。本文将深入介绍uni-list组件的使用方法、特点及应用场景,帮助开发者快速掌握这一利器。
uni-list组件广泛应用于各种场景,如:新闻资讯列表,展示新闻标题、摘要和配图。商品列表,展示商品图片、名称、价格和评价。社交动态,展示用户头像、用户名、动态内容和互动按钮。设置页面,展示各类开关、选项等。
uni-list是Uni-App框架内置的一个列表组件,它以简洁、灵活的方式封装了列表展示逻辑,支持多种列表项布局,如文本、图标、图片等组合展示。通过uni-list,开发者可以轻松创建美观、响应式的列表界面,无需从零开始编写复杂的布局代码,大大提升了开发效率。
uni-list官方文档地址:uni-app官网
在Uni-App项目中使用uni-list,首先确保在页面模板中引入uni-list组件。uni-list组件属于uni-app扩展组件uni-ui中的一个组件。要想使用它需要先引入uni-ui,引入的方法这里就不说了。
以下是一个简单的示例:
- <template>
- <view>
- <uni-list>
- <uni-list-item v-for="(item, index) in listData" :key="index" title="{{item.title}}" note="{{item.note}}" />
- </uni-list>
- </view>
- </template>
-
- <script>
- export default {
- data() {
- return {
- listData: [
- { title: '列表项1', note: '详情描述1' },
- { title: '列表项2', note: '详情描述2' },
- // 更多数据...
- ]
- };
- }
- };
- </script>
在上述例子中,通过v-for指令遍历listData数组,为每个数组元素创建一个uni-list-item,展示标题(title)和备注(note)信息。
uni-list组件的强大之处在于其高度的可定制性。
除了基本的文本展示,它还支持图片、图标、开关、滑动操作等多种元素的嵌入,以及不同的布局模式(如左图右文、上下结构等)。
图片展示:通过<uni-list-item>的thumb属性,可以为列表项添加左侧或顶部的缩略图。
图标与按钮:利用extra插槽,可以在列表项末尾添加图标或操作按钮,如删除、编辑等。
滑动操作:结合swipe-action组件,可以为列表项添加滑动时触发的操作菜单,提升交互体验。
示例:
左侧显示略缩图、图标
thumb
属性 ,可以在列表左侧显示略缩图show-extra-icon
属性,并指定 extra-icon
可以在左侧显示图标- <uni-list>
- <uni-list-item title="列表左侧带略缩图" note="列表描述信息" thumb="https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/unicloudlogo.png"
- thumb-size="lg" rightText="右侧文字"></uni-list-item>
- <uni-list-item :show-extra-icon="true" :extra-icon="extraIcon1" title="列表左侧带扩展图标" ></uni-list-item>
- </uni-list>
开启点击反馈和右侧箭头
clickable
为 true
,则表示这是一个可点击的列表,会默认给一个点击效果,并可以监听 click
事件,click
事件也在此绑定link
属性,会自动开启点击反馈,并给列表右侧添加一个箭头to
属性,可以跳转页面,link
的值表示跳转方式,如果不指定,默认为 navigateTo
- <uni-list>
- <uni-list-item title="开启点击反馈" clickable @click="onClick" ></uni-list-item>
- <uni-list-item title="默认 navigateTo 方式跳转页面" link to="/pages/vue/index/index" @click="onClick($event,1)" ></uni-list-item>
- <uni-list-item title="reLaunch 方式跳转页面" link="reLaunch" to="/pages/vue/index/index" @click="onClick($event,1)" ></uni-list-item>
- </uni-list>
-
通过插槽扩展
名称 | 说明 |
---|---|
header | 左/上内容插槽,可完全自定义默认显示 |
body | 中间内容插槽,可完全自定义中间内容 |
footer | 右/下内容插槽,可完全自定义右侧内容 |
通过插槽扩展 需要注意的是当使用插槽时,内置样式将会失效,只保留排版样式,此时的样式需要开发者自己实现 如果
uni-list-item
组件内置属性样式无法满足需求,可以使用插槽来自定义uni-list-item里的内容。 uni-list-item提供了3个可扩展的插槽:header
、body
、footer
- 当
direction
属性为row
时表示水平排列,此时header
表示列表的左边部分,body
表示列表的中间部分,footer
表示列表的右边部分- 当
direction
属性为column
时表示垂直排列,此时header
表示列表的上边部分,body
表示列表的中间部分,footer
表示列表的下边部分 开发者可以只用1个插槽,也可以3个一起使用。在插槽中可自主编写view标签,实现自己所需的效果。
示例:
- <uni-list>
- <uni-list-item title="自定义右侧插槽" note="列表描述信息" link>
- <template v-slot:header>
- <image class="slot-image" src="/static/logo.png" mode="widthFix"></image>
- </template>
- </uni-list-item>
- <uni-list-item>
- <!-- 自定义 header -->
- <template v-slot:header>
- <view class="slot-box"><image class="slot-image" src="/static/logo.png" mode="widthFix"></image></view>
- </template>
- <!-- 自定义 body -->
- <template v-slot:body>
- <text class="slot-box slot-text">自定义插槽</text>
- </template>
- <!-- 自定义 footer-->
- <template v-slot:footer>
- <image class="slot-image" src="/static/logo.png" mode="widthFix"></image>
- </template>
- </uni-list-item>
- </uni-list>
- ### 当前日报列表
- get https://news-at.zhihu.com/api/4/news/latest
-
- ###历史日报
- get https://news-at.zhihu.com/api/4/news/before/20240617
-
- ### 热门日报
- get http://news-at.zhihu.com/api/4/news/hot
-
- ### 主题日报
- get http://news-at.zhihu.com/api/4/news/theme/2024
- ### 2016年
- get http://news-at.zhihu.com/api/4/news/before/20160101
-
- ### 日报详情
- get http://news-at.zhihu.com/api/4/news/9773253
curl https://news-at.zhihu.com/api/4/news/latest |python3 -m json.tool
博主没有直接调用知乎的后台api接口,而是自己使用golang的go-zero框架,从新包装实现了一下。 如果不用golang实现后台接口,以下内容可忽略。可以直接调用知乎的接口来测试。
1.go-api文件定义
- syntax = "v1"
-
- info (
- title: "doc title"
- desc: "zhihu background service api"
- version: "1.0"
- )
-
- // 0.轮播图
- type (
- SwiperData {
- id int `json:"id"`
- imageUrl string `json:"imageUrl"`
- title string `json:"title"`
- desc string `json:"description"`
- }
- SwiperResp {
- code int `json:"code"`
- message string `json:"message"`
- data []SwiperData `json:"data"`
- }
- )
- // ......
- // 11. 知乎日报 日报列表请求
- type (
- //请求
- ZhihuNewsReq {
- date string `path:"date"`
- }
- //应答
- ZhiItem {
- id string `json:"id"`
- image string `json:"image"`
- title string `json:"title"`
- url string `json:"url"`
- hint string `json:"hint"`
- date string `json:"date"`
- }
- ZhihuNewsResp {
- code int `json:"code"`
- message string `json:"message"`
- stories []ZhiItem `json:"stories"`
- date string `json:"date"`
- }
- )
-
- // 12. 知乎日报 日报详情
- type (
- //请求
- ZhiDetailReq {
- id string `path:"id"`
- }
- //应答
- CtItem {
- types string `json:"types"`
- value string `json:"value"`
- }
- ZhiDetailResp {
- code int `json:"code"`
- message string `json:"message"`
- content []CtItem `json:"content"`
- title string `json:"title"`
- author string `json:"author"`
- bio string `json:"bio"`
- avatar string `json:"avatar"`
- image string `json:"image"`
- more string `json:"more"`
- }
- )
-
- service zhihu-api {
- @doc (
- summary: "zhihu api"
- )
-
- @handler SwiperHandler
- get /api/v1/swiperdata returns (SwiperResp)
-
-
- // 11.知乎日报 news
- @handler ZhihuNewsHandler
- get /api/v1/zhihunews/:date (ZhihuNewsReq) returns (ZhihuNewsResp)
-
- // 12.知乎日报 详情
- @handler ZhiDetailHandler
- get /api/v1/zhihudetail/:id (ZhiDetailReq) returns (ZhiDetailResp)
- }
2.使用goctl工具自动生成后台项目代码
goctl api go -api go-zhihu/zhihu.api -dir go-zhihu/
3.实现后台接口逻辑
- func (l *ZhihuNewsLogic) ZhihuNews(req *types.ZhihuNewsReq) (resp *types.ZhihuNewsResp, err error) {
-
- url := "https://news-at.zhihu.com/api/4/news/latest"
- parsedDate, err := time.Parse("20060102", req.Date)
- if err != nil {
- l.Errorf("Error parsing date:", err)
- }
- url = "https://news-at.zhihu.com/api/4/news/before/" + parsedDate.AddDate(0, 0, 1).Format("20060102")
- res, err_ := httpc.Do(l.ctx, http.MethodGet, url, nil)
- if err_ != nil {
- l.Error(err_)
- return nil, err_
- }
- defer res.Body.Close()
- body, err := io.ReadAll(res.Body)
- if err != nil {
- l.Errorf("Failed to read response body:", err)
- return nil, err
- }
- var zhi types.ZhiItem
- var responseData []types.ZhiItem
- list_ := gjson.GetBytes(body, "stories").Array()
- for _, item := range list_ {
- zhi.Id = strconv.FormatInt(item.Get("id").Int(), 10)
- zhi.Title = item.Get("title").String()
- zhi.Image = item.Get("images.0").String()
- zhi.Url = item.Get("url").String()
- zhi.Hint = item.Get("hint").String()
- zhi.Date = gjson.GetBytes(body, "date").String()
- responseData = append(responseData, zhi)
- }
-
- if len(list_) != 0 {
- resp = &types.ZhihuNewsResp{
- Code: 0,
- Message: res.Status,
- Stories: responseData,
- Date: gjson.GetBytes(body, "date").String(),
- }
- } else {
- resp = &types.ZhihuNewsResp{
- Code: 0,
- Message: res.Status,
- Stories: responseData,
- Date: "",
- }
- }
- return resp, nil
- }
- <template>
- <view class="content">
- <swiper class="swiper" circular :indicator-dots="indicatorDots" :autoplay="autoplay" :interval="interval"
- :duration="duration" lazy-render>
-
- <swiper-item v-for="item in swiperList" :key="item.id">
- <image :src="item.image" :alt="item.title" mode="widthFix" class="swiper-image"></image>
- <view class="swiper-desc" v-if="item.title">{{ item.title }}</view>
- </swiper-item>
- </swiper>
- </view>
- </template>
-
- <script>
- import { getZhihuNewsList } from '@/api/zhihu.js';
- export default {
- data() {
- return {
- indicatorDots: true,
- autoplay: true,
- interval: 2000,
- duration: 500,
- // 轮播图的数据列表,默认为空数组
- swiperList:[],
- // 日报数据列表,默认为空数组
- stories:[],
- currentDate: '', // 初始化为今天的日期
- previousDate: '', // 上一个的日期
- }
- }
- }
- </script>
- // 知乎日报 列表页
- /**
- * date 日期 格式:yyyymmdd
- */
- export const getZhihuNewsList = async (date) => {
- try {
- console.log('getZhihuNewsList request');
- let date_ = date.replace(/-/g, '')
- const response = await uni.$http.get('/zhihunews/'+date_);
- console.log(response);
- if (response.statusCode !== 200) {
- uni.showToast({
- title: '数据请求失败! ',
- duration: 1500,
- icon: 'none',
- });
- return [];
- }
- return response.data;
- } catch (error) {
- console.error('Network request failed:', error);
- uni.showToast({
- title: '网络请求失败! ',
- duration: 1500,
- icon: 'none',
- });
- return [];
- }
- };
- <uni-list>
- <uni-list-item direction="row" v-for="item in stories" :key="item.id" :title="item.title" >
- <template v-slot:body>
- <view class="uni-list-box uni-content">
- <view class="uni-title uni-ellipsis-2">{{item.title}}</view>
- <view class="uni-note">
- <text>{{item.hint}}</text>
- </view>
- </view>
- </template>
-
- <template v-slot:footer>
- <view class="uni-thumb" style="margin: 0;">
- <image :src="item.image" mode="aspectFill"></image>
- </view>
- </template>
- </uni-list-item>
- </uni-list>
如何插入日期分割线?类似于知乎日报上,当往下滑动时会展示历史日期的日报,需要展示下日期和下滑线。如何在uni-list列表中实现这一效果呢?以下是代码:
- <uni-list>
- <template v-for="(item, index) in stories" :key="item.id">
- <!-- 如果是第一条或者日期有变化,则插入日期分割线 -->
- <uni-list-item direction="row" v-if="isShowDivider(index)" >
- <template v-slot:header>
- <view class="uni-divider__content">
- <text>{{item.date.replace(/(\d{4})(\d{2})(\d{2})/, '$1-$2-$3')}}</text>
- </view>
- <view class="uni-divider__line"></view>
- </template>
- </uni-list-item>
-
- <!-- 正常的列表项 -->
- <uni-list-item direction="row" :title="item.title">
- <template v-slot:body>
- <view class="uni-list-box uni-content">
- <view class="l-title uni-ellipsis-2">{{item.title}}</view>
- <view class="uni-note">
- <text>{{item.hint}}</text>
- </view>
- </view>
- </template>
- <template v-slot:footer>
- <view class="uni-thumb" style="margin: 0;">
- <image :src="item.image" mode="aspectFill"></image>
- </view>
- </template>
- </uni-list-item>
- </template>
- </uni-list>
当向页面下滑动时,需要展示历史日期的日报,通过onReachBottom()这一回调可以实现效果。
- /**
- * 上拉加载回调函数
- */
- onReachBottom() {
- console.log('onReachBottom')
- this.getmorenews()
- }
-
- methods: {
- formatDate(date) {
- const year = date.getFullYear();
- const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从0开始,所以需要+1
- const day = String(date.getDate()).padStart(2, '0');
- return `${year}-${month}-${day}`;
- },
-
- isShowDivider(index) {
- if (this.stories[index].date !== this.previousDate) {
- this.previousDate = this.stories[index].date;
- console.log(this.previousDate)
- if(index!==0){
- return true;
- }
- }
- return false;
- },
-
- // 触底之后触发函数,
- getmorenews() {
- //this.loadStatu = true
- //this.listStatus = 'loading'
- //每次滑动都递减一天
- const date_ = new Date(this.currentDate);
- console.log(date_);
- date_.setDate(date_.getDate() - 1); // 日期减一
- //console.log(date_);
- let currentDate_ = this.formatDate(date_);
- console.log('currentDate_:'+currentDate_);
- getZhihuNewsList(currentDate_).then(result => {
- console.log("getZhihuNewsList,result:");
- console.log(result);
- this.currentDate = this.formatDate(date_);
- this.stories = this.stories.concat(result.stories);
- });
- }
- },
- <template>
- <view class="content">
- <swiper class="swiper" circular :indicator-dots="indicatorDots" :autoplay="autoplay" :interval="interval"
- :duration="duration" lazy-render>
-
- <swiper-item v-for="item in swiperList" :key="item.id">
- <image :src="item.image" :alt="item.title" mode="widthFix" class="swiper-image"></image>
- <view class="swiper-desc" v-if="item.title">{{ item.title }}</view>
- </swiper-item>
- </swiper>
-
- <!-- 通过 loadMore 组件实现上拉加载效果,如需自定义显示内容,可参考:https://ext.dcloud.net.cn/plugin?id=29 -->
- <uni-list>
- <template v-for="(item, index) in stories" :key="item.id">
- <!-- 如果是第一条或者日期有变化,则插入日期分割线 -->
- <uni-list-item direction="row" v-if="isShowDivider(index)" >
- <template v-slot:header>
- <view class="uni-divider__content">
- <text>{{item.date.replace(/(\d{4})(\d{2})(\d{2})/, '$1-$2-$3')}}</text>
- </view>
- <view class="uni-divider__line"></view>
- </template>
- </uni-list-item>
-
- <!-- 正常的列表项 -->
- <uni-list-item direction="row" :title="item.title">
- <template v-slot:body>
- <view class="uni-list-box uni-content">
- <view class="l-title uni-ellipsis-2">{{item.title}}</view>
- <view class="uni-note">
- <text>{{item.hint}}</text>
- </view>
- </view>
- </template>
- <template v-slot:footer>
- <view class="uni-thumb" style="margin: 0;">
- <image :src="item.image" mode="aspectFill"></image>
- </view>
- </template>
- </uni-list-item>
- </template>
- </uni-list>
- </view>
- </template>
-
- <script>
- import { getZhihuNewsList } from '@/api/zhihu.js';
- export default {
- data() {
- return {
- indicatorDots: true,
- autoplay: true,
- interval: 2000,
- duration: 500,
- // 轮播图的数据列表,默认为空数组
- swiperList:[],
- // 日报数据列表,默认为空数组
- stories:[],
- currentDate: '', // 初始化为今天的日期
- previousDate: '', // 上一个的日期
- }
- },
- onLoad() {
- this.currentDate = this.formatDate(new Date())
- this.previousDate = this.currentDate
- },
- methods: {
- formatDate(date) {
- const year = date.getFullYear();
- const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从0开始,所以需要+1
- const day = String(date.getDate()).padStart(2, '0');
- return `${year}-${month}-${day}`;
- },
-
- isShowDivider(index) {
- if (this.stories[index].date !== this.previousDate) {
- this.previousDate = this.stories[index].date;
- console.log(this.previousDate)
- if(index!==0){
- return true;
- }
- }
- return false;
- },
-
- // 触底之后触发函数,
- getmorenews() {
- //this.loadStatu = true
- //this.listStatus = 'loading'
- //每次滑动都递减一天
- const date_ = new Date(this.currentDate);
- console.log(date_);
- date_.setDate(date_.getDate() - 1); // 日期减一
- //console.log(date_);
- let currentDate_ = this.formatDate(date_);
- console.log('currentDate_:'+currentDate_);
- getZhihuNewsList(currentDate_).then(result => {
- console.log("getZhihuNewsList,result:");
- console.log(result);
- this.currentDate = this.formatDate(date_);
- this.stories = this.stories.concat(result.stories);
- });
- }
- },
- mounted() {
- console.log("mounted")
- console.log('currentDate:'+this.currentDate);
- getZhihuNewsList(this.currentDate).then(result => {
- console.log("getZhihuNewsList,result:");
- console.log(result);
- this.stories = result.stories;
- this.swiperList = result.stories;
- });
- },/**
- * 下拉刷新回调函数
- */
- onPullDownRefresh() {
- console.log('onPullDownRefresh')
- },
- /**
- * 上拉加载回调函数
- */
- onReachBottom() {
- console.log('onReachBottom')
- this.getmorenews()
- }
- }
- </script>
-
- <style lang="scss" scoped>
- @import '@/common/uni-ui.scss';
-
- page {
- display: flex;
- flex-direction: column;
- box-sizing: border-box;
- background-color: #efeff4;
- min-height: 100%;
- height: auto;
- }
-
- .content {
- width: 100%;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- }
-
- .uni-list-box {
- margin-top: 0;
- }
-
- .l-title {
- font-weight: bold;
- font-size: 30rpx;
- color: #3b4144;
- }
-
- .uni-content {
- padding-right: 10rpx;
- }
-
- .uni-note {
- display: flex;
- margin: 0;
- justify-content: space-between;
- }
-
- .thumb-image {
- width: 100%;
- height: 100%;
- }
-
- /*布局和溢出隐藏规则*/
- .ellipsis {
- display: flex;
- overflow: hidden;
- }
-
- .uni-ellipsis-1 {
- overflow: hidden;
- white-space: nowrap; /*nowrap;:强制文本在一行内显示,不允许换行*/
- text-overflow: ellipsis;
- }
-
- /*多行文本的省略效果*/
- .uni-ellipsis-2 {
- overflow: hidden;
- /*表示当文本内容超出所在容器的宽度时,用省略号来代替超出的部分*/
- text-overflow: ellipsis;
- display: -webkit-box;
- -webkit-line-clamp: 2;
- -webkit-box-orient: vertical;
- }
-
- .swiper {
- width: 100%;
- height: 300rpx;
- }
- .swiper-image{
- width: 100%;
- height: auto;
- }
-
- .swiper-desc {
- position: absolute;
- bottom: 20px;
- left: 0;
- right: 0;
- color: #fff;
- background-color: rgba(0, 0, 0, 0.5);
- padding: 10px;
- text-align: center;
- }
-
- .swiper-item {
- display: block;
- height: 300rpx;
- line-height: 300rpx;
- text-align: center;
- }
-
- .date-divider {
- color: #8f8f94;
- font-size: 12rpx;
- font-weight: bold;
- }
- .line-divider {
- height: 1px;
- width: 75%;
- margin-left: 10rpx;
- margin-top: 15rpx;
- background-color: #D8D8D8; /* 分割线颜色 */
- }
- </style>
最后,附上测试的工程完整源码。
资源下载地址:https://download.csdn.net/download/qq8864/89377440
人到了一定年纪,你再去回首过往,曾经那些重大的时刻,我们也一步步咬紧牙关挺过去,一步步熬过许多最黑暗的日子,走到如今。关关难过,关关通过,一路上,我们也练就了一身的本领,也拥有一些处事不惊的能力和适应生活的心态。
杨绛先生说:“生活并非都是繁花锦簇,所有的好,不过是来自内心的知足,眼里的热爱,以及对万千世界删繁就简的态度。与独处相安,与万事言和。这烟火人间,事事值得,事事也遗憾。”
生活不可能都是鲜花和阳光,也充满无数的荆棘和坎坷,走过的每一段岁月,曾经都有美好照亮前行,也有一些遗憾留在心中。
生活总是喜忧参半,没有十全十美,万事只求半称心,所有的美好不过都是来自于懂得知足常乐。
生活都是在于选择之中,选择了一条路,注定也会失去另一条路的风景,遗憾是人生常态而已。不如充实自己,什么让你快乐,你就去做什么,不要非要去求什么意义。对我来说,虽然天色以晚,别人喜欢刷抖音,而我喜欢敲代码和写文字,简称码字。这使我快乐,我走在充实自己的路上,足以。
如果钓鱼的意义是为了吃鱼肉,那生活将是多么无趣。
https://news-at.zhihu.com/api/4/news/latest
-Api/豆瓣电影.md at master · shichunlei/-Api · GitHub
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。