├── pages ├── index │ ├── index.json │ ├── index.wxss │ ├── index.wxml │ └── index.js └── preview-media-desc │ ├── swiper-limited-load │ ├── index.wxss │ ├── index.json │ ├── index.wxml │ └── index.js │ ├── item │ ├── item-index.json │ ├── item-index.wxss │ ├── item-index.wxml │ └── item-index.js │ ├── index.json │ ├── index.wxss │ ├── index.wxml │ └── index.js ├── img └── test.gif ├── sitemap.json ├── .gitignore ├── app.wxss ├── app.json ├── app.js ├── README.md └── project.config.json /pages/index/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": {} 3 | } -------------------------------------------------------------------------------- /img/test.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pengboboer/preview-media-desc/HEAD/img/test.gif -------------------------------------------------------------------------------- /pages/preview-media-desc/swiper-limited-load/index.wxss: -------------------------------------------------------------------------------- 1 | /* components/swiper-limited-load/index.wxss */ -------------------------------------------------------------------------------- /pages/preview-media-desc/item/item-index.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /pages/preview-media-desc/swiper-limited-load/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "componentGenerics": { 4 | "item-view": true 5 | }, 6 | "usingComponents": {} 7 | } -------------------------------------------------------------------------------- /sitemap.json: -------------------------------------------------------------------------------- 1 | { 2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html", 3 | "rules": [{ 4 | "action": "allow", 5 | "page": "*" 6 | }] 7 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows 2 | [Dd]esktop.ini 3 | Thumbs.db 4 | $RECYCLE.BIN/ 5 | 6 | # macOS 7 | .DS_Store 8 | .fseventsd 9 | .Spotlight-V100 10 | .TemporaryItems 11 | .Trashes 12 | 13 | # Node.js 14 | node_modules/ 15 | -------------------------------------------------------------------------------- /pages/index/index.wxss: -------------------------------------------------------------------------------- 1 | /* pages/index/index.wxss */ 2 | .main{ 3 | height: 100%; 4 | width: 100%; 5 | display: flex; 6 | flex-direction: column; 7 | align-items: center; 8 | } 9 | 10 | .btn{ 11 | margin-top: 100rpx; 12 | } -------------------------------------------------------------------------------- /app.wxss: -------------------------------------------------------------------------------- 1 | /**app.wxss**/ 2 | .container { 3 | height: 100%; 4 | display: flex; 5 | flex-direction: column; 6 | align-items: center; 7 | justify-content: space-between; 8 | padding: 200rpx 0; 9 | box-sizing: border-box; 10 | } 11 | -------------------------------------------------------------------------------- /pages/index/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /pages/preview-media-desc/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": { 3 | "swiper-limited-load": "./swiper-limited-load/index", 4 | "item-view": "./item/item-index" 5 | }, 6 | "navigationStyle": "custom", 7 | "navigationBarTextStyle": "white" 8 | } -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages": [ 3 | "pages/index/index", 4 | "pages/preview-media-desc/index" 5 | ], 6 | "window": { 7 | "backgroundTextStyle": "light", 8 | "navigationBarBackgroundColor": "#fff", 9 | "navigationBarTitleText": "Weixin", 10 | "navigationBarTextStyle": "black" 11 | }, 12 | "style": "v2", 13 | "sitemapLocation": "sitemap.json" 14 | } -------------------------------------------------------------------------------- /pages/preview-media-desc/index.wxss: -------------------------------------------------------------------------------- 1 | /* pages/preview-image-video/index.wxss */ 2 | 3 | .index-title{ 4 | width: 100%; 5 | display: flex; 6 | flex-direction: row; 7 | justify-content: center; 8 | align-items: center; 9 | margin-top: 100rpx; 10 | color: #ffffff; 11 | font-size: 30rpx; 12 | position: fixed; 13 | top: 0; 14 | z-index: 10; 15 | } 16 | 17 | .swiper{ 18 | background-color: #000000; 19 | } -------------------------------------------------------------------------------- /pages/preview-media-desc/swiper-limited-load/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 11 | 12 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | //app.js 2 | App({ 3 | onLaunch: function () { 4 | // 展示本地存储能力 5 | var logs = wx.getStorageSync('logs') || [] 6 | logs.unshift(Date.now()) 7 | wx.setStorageSync('logs', logs) 8 | 9 | // 登录 10 | wx.login({ 11 | success: res => { 12 | // 发送 res.code 到后台换取 openId, sessionKey, unionId 13 | } 14 | }) 15 | // 获取用户信息 16 | wx.getSetting({ 17 | success: res => { 18 | if (res.authSetting['scope.userInfo']) { 19 | // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框 20 | wx.getUserInfo({ 21 | success: res => { 22 | // 可以将 res 发送给后台解码出 unionId 23 | this.globalData.userInfo = res.userInfo 24 | 25 | // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回 26 | // 所以此处加入 callback 以防止这种情况 27 | if (this.userInfoReadyCallback) { 28 | this.userInfoReadyCallback(res) 29 | } 30 | } 31 | }) 32 | } 33 | } 34 | }) 35 | }, 36 | globalData: { 37 | userInfo: null 38 | } 39 | }) -------------------------------------------------------------------------------- /pages/preview-media-desc/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | module.exports = { 4 | getIndex: function (currentIndex, list) { 5 | if (currentIndex == -1) { 6 | return 1 7 | } 8 | 9 | if (currentIndex == -2) { 10 | return list.length 11 | } 12 | 13 | return currentIndex + 1 14 | } 15 | } 16 | 17 | 18 | {{func.getIndex(currentIndex, list)}}/{{list.length}} 19 | 20 | 39 | 40 | -------------------------------------------------------------------------------- /pages/preview-media-desc/item/item-index.wxss: -------------------------------------------------------------------------------- 1 | /* pages/preview-image-video/item/item-index.wxss */ 2 | 3 | .box{ 4 | width: 100%; 5 | height: 100%; 6 | display: flex; 7 | flex-direction: row; 8 | justify-content: center; 9 | align-items: center; 10 | background-color: #000000; 11 | overflow: scroll; 12 | } 13 | 14 | .img-box{ 15 | display: flex; 16 | flex-direction: row; 17 | align-items: center; 18 | } 19 | 20 | .img{ 21 | width: 100%; 22 | } 23 | 24 | .desc{ 25 | width: 100%; 26 | font-size: 30rpx; 27 | color: #ffffff; 28 | position: fixed; 29 | bottom: 0; 30 | padding: 30rpx; 31 | box-sizing: border-box; 32 | background-color: rgba(0,0,0,0.5); 33 | display: -webkit-box; 34 | overflow: hidden; 35 | text-overflow: ellipsis; 36 | word-break: break-all; 37 | white-space: pre-line; 38 | -webkit-box-orient: vertical; 39 | -webkit-line-clamp: 6; 40 | } 41 | 42 | movable-view { 43 | display: flex; 44 | align-items: center; 45 | justify-content: center; 46 | height: 100%; 47 | width: 100%; 48 | color: #fff; 49 | } 50 | 51 | movable-area { 52 | height: 100%; 53 | width: 750rpx; 54 | overflow: hidden; 55 | } 56 | 57 | .video{ 58 | width: 100%; 59 | height: 0rpx; 60 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # preview-image-video 2 | ## 微信小程序preview-media带有图片描述 3 | 4 | ### 示例动图 5 |

6 | ##### 跟微信小程序的wx.prevImage或者wx.prevVideo的基本类似,大体功能类似,体验上稍微有一点点差距吧,但是好在可以显示图片描述
7 | 这里实现了如下功能和细节:
8 | * 支持左右滑动 9 | * 图片双指缩放 10 | * 单击图片返回 11 | * 双击放大缩小 12 | * 图片视频混排 13 | * 显示图片描述 14 | 15 | # 使用方法
16 | * 将pages中的preview-media-desc复制到您的项目中
17 | * 在app.json中注册该page
18 | * 具体可以参照项目目录index中的用法
19 | 20 | ``` 21 | app.globalData.previewInfo = { 22 | list: [ 23 | { 24 | picUrl: "", 25 | video: "", 26 | desc: "" 27 | } 28 | ], 29 | current: 0 30 | } 31 | 32 | wx.navigateTo({ 33 | url: '../../pages/preview-media-desc/index', 34 | }) 35 | ``` 36 | # 特别说明: 37 | * 如果你需要使用视频,那么将会涉及到一个视频的宽高比例问题,这里我使用wx.getImageInfo()来获取视频封面的宽高比,从而知道video容器的高度。使用wx.getImageInfo()来获取网络图片的宽高必须配置download域名,否则最好你的接口能直接返回video的宽高信息,然后通过屏幕宽度计算出video容器的高度,这样显示的视频就会是按比例铺满整个手机的宽度。 38 | * 在preview-media-desc/item/item-index中可找到对应的代码 39 | 40 | 41 | [csdn原文:微信小程序可添加图片描述的wx.previewMedia](https://blog.csdn.net/pengbo6665631/article/details/108768510)
42 | [小程序交流专区:大图预览下添加图片描述](https://developers.weixin.qq.com/community/develop/article/doc/00080c2ed6006805050bd275155c13)
43 | ### 如果对你有帮助,动动小手给个star,谢谢。 44 | -------------------------------------------------------------------------------- /project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "项目配置文件", 3 | "packOptions": { 4 | "ignore": [] 5 | }, 6 | "setting": { 7 | "urlCheck": true, 8 | "es6": true, 9 | "postcss": true, 10 | "preloadBackgroundData": false, 11 | "minified": true, 12 | "newFeature": true, 13 | "coverView": true, 14 | "autoAudits": false, 15 | "showShadowRootInWxmlPanel": true, 16 | "scopeDataCheck": false, 17 | "checkInvalidKey": true, 18 | "checkSiteMap": true, 19 | "uploadWithSourceMap": true, 20 | "babelSetting": { 21 | "ignore": [], 22 | "disablePlugins": [], 23 | "outputPath": "" 24 | }, 25 | "useCompilerModule": true, 26 | "userConfirmedUseCompilerModuleSwitch": false 27 | }, 28 | "compileType": "miniprogram", 29 | "libVersion": "2.13.0", 30 | "appid": "wxf6bd41fffc7e1fc8", 31 | "projectname": "preview-image-video", 32 | "debugOptions": { 33 | "hidedInDevtools": [] 34 | }, 35 | "isGameTourist": false, 36 | "simulatorType": "wechat", 37 | "simulatorPluginLibVersion": {}, 38 | "condition": { 39 | "search": { 40 | "current": -1, 41 | "list": [] 42 | }, 43 | "conversation": { 44 | "current": -1, 45 | "list": [] 46 | }, 47 | "game": { 48 | "currentL": -1, 49 | "list": [] 50 | }, 51 | "miniprogram": { 52 | "current": -1, 53 | "list": [] 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /pages/preview-media-desc/item/item-index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 38 | 39 | 40 | {{item.desc}} 41 | -------------------------------------------------------------------------------- /pages/preview-media-desc/item/item-index.js: -------------------------------------------------------------------------------- 1 | // pages/preview-image-video/item/item-index.js 2 | Component({ 3 | 4 | observers: { 5 | 'currentIndex': function(index) { 6 | let that = this 7 | // 这块代码的目的是为了获取视频的比例,这里是通过视频封面图片来获取的 8 | // 如果你们后台有直接返回了宽高比例,这里可以直接计算真是的video容器的高度 9 | let item = that.data.item 10 | if (index == item.index) { 11 | if (item.videoUrl != null && item.videoUrl != "") { 12 | // 如果项目配置了download域名,则可直接用此代码 13 | // 否则看你的接口是否会返回视频的宽高,然后来计算video容器的宽高 14 | // wx.getImageInfo({ 15 | // src: item.picUrl, 16 | // success: function(res){ 17 | // console.log(res) 18 | // let scale = res.height / res.width 19 | // let videoHeight = wx.getSystemInfoSync().windowWidth * scale 20 | // that.setData({ 21 | // videoHeight: videoHeight 22 | // }) 23 | // }, 24 | // fail: function(res){ 25 | // console.log(res) 26 | // }, 27 | // }) 28 | 29 | 30 | // 这里暂时给视频比例弄成个4:3吧, 高:宽 1000: 750 31 | // 你们在使用时要根据情况设置宽高比 32 | that.setData({ 33 | videoHeight: 1000 / 750 * wx.getSystemInfoSync().windowWidth 34 | }) 35 | 36 | } 37 | } 38 | } 39 | }, 40 | /** 41 | * 组件的属性列表 42 | */ 43 | properties: { 44 | item: { 45 | type: Object, 46 | value: null 47 | }, 48 | scaleItem: { 49 | type: Number, 50 | value: 1.0 51 | }, 52 | swiperHeight: { 53 | type: Number, 54 | value: 0 55 | }, 56 | currentIndex: { 57 | type: Number, 58 | value: 0 59 | } 60 | }, 61 | 62 | /** 63 | * 组件的初始数据 64 | */ 65 | data: { 66 | 67 | }, 68 | 69 | /** 70 | * 组件的方法列表 71 | */ 72 | methods: { 73 | touchStart (e) { 74 | this.triggerEvent("touchStart") 75 | }, 76 | 77 | touchMove (e) { 78 | this.triggerEvent("touchMove") 79 | }, 80 | 81 | touchEnd (e) { 82 | this.triggerEvent("touchEnd") 83 | }, 84 | 85 | onClickBox (e) { 86 | this.triggerEvent("onClickBox", e.timeStamp) 87 | }, 88 | 89 | movableChange (e) { 90 | this.triggerEvent("movableChange",e.detail.source) 91 | }, 92 | 93 | onScale (e) { 94 | this.triggerEvent("onScale", e.detail.scale) 95 | } 96 | } 97 | }) 98 | -------------------------------------------------------------------------------- /pages/index/index.js: -------------------------------------------------------------------------------- 1 | // pages/index/index.js 2 | const app = getApp() 3 | Page({ 4 | 5 | /** 6 | * 页面的初始数据 7 | */ 8 | data: { 9 | 10 | }, 11 | 12 | onClickBtn (e) { 13 | let index = e.currentTarget.dataset.index 14 | if (index == 0) { 15 | this.prevImage() 16 | } 17 | 18 | if (index == 1) { 19 | this.prevMedia() 20 | } 21 | }, 22 | 23 | prevImage() { 24 | app.globalData.previewInfo = { 25 | list: [ 26 | { 27 | picUrl: "https://pic.008box.com/picture/20200918104001_2348.jpg", 28 | desc: "这是一个微博长图" 29 | }, 30 | { 31 | picUrl: "https://pic.008box.com/test/20200923152850_1409.jpg", 32 | desc: "这里是图片描述哦,这里是图片描述哦,这里是图片描述哦,这里是图片描述哦" 33 | }, 34 | { 35 | picUrl: "https://pic.008box.com/test/20200923152850_5256.jpg", 36 | desc: "这里是图片描述哦,这里是图片描述哦,这里是图片描述哦,这里是图片描述哦" 37 | }, 38 | { 39 | picUrl: "https://pic.008box.com/test/20200923152850_1958.jpg", 40 | desc: "" 41 | } 42 | ], 43 | current: 3 44 | } 45 | 46 | wx.navigateTo({ 47 | url: '../../pages/preview-media-desc/index', 48 | }) 49 | }, 50 | 51 | prevMedia() { 52 | app.globalData.previewInfo = { 53 | list: [ 54 | { 55 | picUrl: " https://pic.008box.com/test/20200923152453_9874.jpeg", 56 | videoUrl: "https://pic.008box.com/test/20200923152451_0443.mp4", 57 | desc: "刘皇叔蹦迪......" 58 | }, 59 | { 60 | picUrl: "https://pic.008box.com/test/20200923164811_2537.jpeg", 61 | videoUrl: "https://pic.008box.com/test/20200923164808_5195.mp4", 62 | desc: "你是我惊鸿一瞥的春光,也是我永恒追逐的星辰大海。" 63 | }, 64 | { 65 | picUrl: "https://pic.008box.com/test/20200923152850_3681.jpg", 66 | desc: "我以为你是那一场春雨,谁知你是大雨之前的电闪雷鸣。" 67 | }, 68 | { 69 | picUrl: "https://pic.008box.com/test/20200923150733_4419.jpeg", 70 | videoUrl:"https://pic.008box.com/test/20200923150731_6834.mp4", 71 | desc: "这是一个蜘蛛侠视频" 72 | } 73 | ], 74 | current: 0 75 | } 76 | 77 | wx.navigateTo({ 78 | url: '../../pages/preview-media-desc/index', 79 | }) 80 | }, 81 | 82 | /** 83 | * 生命周期函数--监听页面加载 84 | */ 85 | onLoad: function (options) { 86 | 87 | }, 88 | 89 | /** 90 | * 生命周期函数--监听页面初次渲染完成 91 | */ 92 | onReady: function () { 93 | 94 | }, 95 | 96 | /** 97 | * 生命周期函数--监听页面显示 98 | */ 99 | onShow: function () { 100 | 101 | }, 102 | 103 | /** 104 | * 生命周期函数--监听页面隐藏 105 | */ 106 | onHide: function () { 107 | 108 | }, 109 | 110 | /** 111 | * 生命周期函数--监听页面卸载 112 | */ 113 | onUnload: function () { 114 | 115 | }, 116 | 117 | /** 118 | * 页面相关事件处理函数--监听用户下拉动作 119 | */ 120 | onPullDownRefresh: function () { 121 | 122 | }, 123 | 124 | /** 125 | * 页面上拉触底事件的处理函数 126 | */ 127 | onReachBottom: function () { 128 | 129 | }, 130 | 131 | /** 132 | * 用户点击右上角分享 133 | */ 134 | onShareAppMessage: function () { 135 | 136 | } 137 | }) -------------------------------------------------------------------------------- /pages/preview-media-desc/index.js: -------------------------------------------------------------------------------- 1 | // pages/preview-image-video/index.js 2 | const app = getApp() 3 | Page({ 4 | 5 | /** 6 | * 页面的初始数据 7 | */ 8 | data: { 9 | list: [], 10 | scaleList: [], 11 | scaleTempList: [], 12 | current: 0, 13 | currentIndex: 0, 14 | swiperDuration: "0", 15 | 16 | lastTapTime: 0, // 最后一次单击事件点击发生时间 17 | singleClickFunc: null, 18 | isFingerMoved: false, 19 | }, 20 | 21 | swiperChange (e) { 22 | let current = e.detail.current 23 | this.setData({ 24 | currentIndex: current 25 | }) 26 | }, 27 | 28 | touchStart (e) { 29 | this.data.isFingerMoved = false 30 | }, 31 | 32 | touchMove (e) { 33 | this.data.isFingerMoved = true 34 | }, 35 | 36 | touchEnd (e) { 37 | let that = this 38 | let currentIndex = that.data.currentIndex 39 | let scaleTemp = that.data.scaleTempList[currentIndex] 40 | let scaleChange = "scaleList[" + currentIndex + "]" 41 | // 仿微信自带prevImage 缩放到最小后恢复原样, 超过3倍后显示3倍 42 | if (scaleTemp < 1 || scaleTemp > 3) { 43 | that.setData({ 44 | [scaleChange]: scaleTemp < 1 ? 1 : 3 45 | }) 46 | } 47 | }, 48 | 49 | onClickBox (e) { 50 | console.log(e) 51 | let that = this 52 | let curTime = e.detail 53 | let lastTime = that.data.lastTapTime 54 | let currentIndex = that.data.currentIndex 55 | let scaleTemp = that.data.scaleTempList[currentIndex] 56 | // 双击 57 | if (curTime - lastTime < 300) { 58 | clearTimeout(that.data.singleClickFunc) 59 | let scaleChange = "scaleList[" + currentIndex + "]" 60 | that.setData({ 61 | [scaleChange]: scaleTemp == 1 ? 3 : 1 62 | }) 63 | } else { 64 | if (scaleTemp < 1.1 && !that.data.isFingerMoved) { 65 | that.data.singleClickFunc = setTimeout(function(){ 66 | wx.navigateBack({ 67 | delta: 1 68 | }) 69 | }, 350) 70 | } 71 | } 72 | that.data.lastTapTime = curTime 73 | }, 74 | 75 | movableChange (e) { 76 | console.log(e) 77 | let that = this 78 | let currentIndex = that.data.currentIndex 79 | // 这个好像是微信的bug,经常触发不了out-of-bounds,也是头疼 80 | if (e.detail == "out-of-bounds") { 81 | if(currentIndex == 0 || currentIndex == that.data.list.length - 1) { 82 | return 83 | } 84 | // 左边界 85 | if (e.detail.x == 0) { 86 | that.setData({ 87 | current: that.data.currentIndex - 1 88 | }) 89 | // 右边界 90 | } else { 91 | that.setData({ 92 | current: that.data.currentIndex + 1 93 | }) 94 | } 95 | } 96 | }, 97 | 98 | onScale (e) { 99 | let scaleTemp = "scaleTempList[" + this.data.currentIndex + "]" 100 | this.setData({ 101 | [scaleTemp]: e.detail 102 | }) 103 | }, 104 | 105 | /** 106 | * 生命周期函数--监听页面加载 107 | */ 108 | onLoad: function (options) { 109 | let that = this 110 | that.setData({ 111 | swiperHeight: wx.getSystemInfoSync().windowHeight, 112 | }) 113 | 114 | let info = app.globalData.previewInfo 115 | app.globalData.previewInfo = null 116 | 117 | let scaleList = [] 118 | let list = info.list.map(function(item, index){ 119 | item.index = index 120 | scaleList.push(1.0) 121 | return item 122 | }) 123 | 124 | that.setData({ 125 | list: list, 126 | scaleList: scaleList, 127 | scaleTempList: scaleList 128 | }) 129 | 130 | that.setData({ 131 | current: info.current 132 | }) 133 | that.setData({ 134 | swiperDuration: '250' 135 | }) 136 | }, 137 | 138 | /** 139 | * 生命周期函数--监听页面初次渲染完成 140 | */ 141 | onReady: function () { 142 | 143 | }, 144 | 145 | /** 146 | * 生命周期函数--监听页面显示 147 | */ 148 | onShow: function () { 149 | 150 | }, 151 | 152 | /** 153 | * 生命周期函数--监听页面隐藏 154 | */ 155 | onHide: function () { 156 | 157 | }, 158 | 159 | /** 160 | * 生命周期函数--监听页面卸载 161 | */ 162 | onUnload: function () { 163 | 164 | }, 165 | 166 | /** 167 | * 页面相关事件处理函数--监听用户下拉动作 168 | */ 169 | onPullDownRefresh: function () { 170 | 171 | }, 172 | 173 | /** 174 | * 页面上拉触底事件的处理函数 175 | */ 176 | onReachBottom: function () { 177 | 178 | }, 179 | 180 | /** 181 | * 用户点击右上角分享 182 | */ 183 | onShareAppMessage: function () { 184 | 185 | } 186 | }) -------------------------------------------------------------------------------- /pages/preview-media-desc/swiper-limited-load/index.js: -------------------------------------------------------------------------------- 1 | // components/swiper-limited-load/index.js 2 | const START = 0 3 | const END = 2 4 | const SWIPER_LENGTH = 3 5 | 6 | Component({ 7 | observers: { 8 | 'current': function(index) { 9 | let that = this 10 | let current = index % SWIPER_LENGTH 11 | let {swiperIndex, swiperList} = that.data 12 | if (swiperList.length == 0) { 13 | return 14 | } 15 | // 如果change后还是之前的那一个item,直接return 16 | if (current == swiperIndex && swiperList[swiperIndex].index == index) { 17 | return 18 | } 19 | that.init(index) 20 | // 如果change之后还是当前的current,比如之前是1、点击后是4 之前是2、点击后是5之类 21 | // 那么不会走swiperChange的change方法,需要我们手动去给它加一个current,然后传出去 22 | if (current == swiperIndex) { 23 | that.triggerEvent("change", {source: "",current: index}) 24 | } 25 | }, 26 | 27 | 'list': function(list) { 28 | this.init(this.data.swiperIndex) 29 | } 30 | }, 31 | /** 32 | * 组件的属性列表 33 | */ 34 | properties: { 35 | swiperHeight: { 36 | type: Number, 37 | value: 0 38 | }, 39 | list: { 40 | type: Array, 41 | value: [] 42 | }, 43 | scaleList: { 44 | type: Array, 45 | value: [] 46 | }, 47 | scaleTempList: { 48 | type: Array, 49 | value: [] 50 | }, 51 | current: { 52 | type: Number, 53 | value: 0 54 | }, 55 | swiperDuration: { 56 | type: String, 57 | value: "250" 58 | }, 59 | currentSelectIndex: { 60 | type: Number, 61 | value: 0 62 | } 63 | }, 64 | 65 | /** 66 | * 组件的初始数据 67 | */ 68 | data: { 69 | // 滑动到的位置 70 | swiperIndex: 0, 71 | // 此值控制swiper的位置 72 | swiperCurrent: 0, 73 | // 值为0禁止切换动画 74 | swiperDuration: "250", 75 | // 当前swiper渲染的items 76 | swiperList: [], 77 | 78 | list: [], 79 | }, 80 | 81 | /** 82 | * 组件的方法列表 83 | */ 84 | methods: { 85 | 86 | touchStart (e) { 87 | this.triggerEvent("touchStart") 88 | }, 89 | 90 | touchMove (e) { 91 | this.triggerEvent("touchMove") 92 | }, 93 | 94 | touchEnd (e) { 95 | this.triggerEvent("touchEnd") 96 | }, 97 | 98 | onClickBox (e) { 99 | this.triggerEvent("onClickBox", e.detail) 100 | }, 101 | 102 | movableChange (e) { 103 | this.triggerEvent("movableChange", e.detail) 104 | }, 105 | 106 | onScale (e) { 107 | this.triggerEvent("onScale", e.detail) 108 | }, 109 | 110 | init (defaulaIndex) { 111 | let that = this 112 | let list = that.data.list 113 | if (list == null || list.length == 0) { 114 | return 115 | } 116 | // 默认显示的index 117 | let current = defaulaIndex % SWIPER_LENGTH 118 | that.setData({ 119 | swiperList: that.getInitSwiperList(list, defaulaIndex), 120 | swiperIndex: current, 121 | swiperCurrent: current, 122 | }) 123 | 124 | }, 125 | 126 | 127 | swiperChange: function (e) { 128 | let that = this 129 | 130 | let current = e.detail.current 131 | let lastIndex = that.data.swiperIndex 132 | let currentItem = that.data.swiperList[current] 133 | console.log("我看", lastIndex) 134 | console.log(that.data.swiperList) 135 | console.log(that.data.list) 136 | 137 | let info = {} 138 | info.source = e.detail.source 139 | // 如果是滑到了左边界,弹回去 140 | if (currentItem.isFirstPlaceholder) { 141 | info.current = -1 142 | that.triggerEvent("change", info) 143 | that.setData({ 144 | swiperCurrent: lastIndex 145 | }) 146 | return 147 | } 148 | // 如果滑到了右边界,弹回去 149 | if (currentItem.isLastPlaceholder) { 150 | info.current = -2 151 | that.triggerEvent("change", info) 152 | that.setData({ 153 | swiperCurrent: lastIndex 154 | }) 155 | console.log("到右边界了", info) 156 | return 157 | } 158 | 159 | // 正向滑动,到下一个的时候 160 | // 是正向衔接 161 | let isLoopPositive = current == START && lastIndex == END 162 | if (current - lastIndex == 1 || isLoopPositive) { 163 | let swiperChangeItem = "swiperList[" + that.getNextSwiperChangeIndex(current) + "]" 164 | that.setData({ 165 | [swiperChangeItem]: that.getNextSwiperNeedItem(currentItem, that.data.list) 166 | }) 167 | } 168 | 169 | // 反向滑动,到上一个的时候 170 | // 是反向衔接 171 | var isLoopNegative = current == END && lastIndex == START 172 | if (lastIndex - current == 1 || isLoopNegative) { 173 | let swiperChangeItem = "swiperList[" + that.getLastSwiperChangeIndex(current) + "]" 174 | that.setData({ 175 | [swiperChangeItem]: that.getLastSwiperNeedItem(currentItem, that.data.list) 176 | }) 177 | } 178 | 179 | info.current = currentItem.index 180 | that.triggerEvent("change", info) 181 | 182 | // 记录滑过来的位置,此值对于下一次滑动的计算很重要 183 | that.data.swiperIndex = current 184 | }, 185 | 186 | 187 | 188 | 189 | /** 190 | * 获取初始化的swiperList 191 | */ 192 | getInitSwiperList : function (list, defaultIndex) { 193 | let that = this 194 | let swiperList = [] 195 | for (let i = 0; i < 3; i++) { 196 | swiperList.push({}) 197 | } 198 | let current = defaultIndex % 3 199 | let currentItem = list[defaultIndex] 200 | swiperList[current] = currentItem 201 | swiperList[that.getLastSwiperChangeIndex(current)] = that.getLastSwiperNeedItem(currentItem, list) 202 | swiperList[that.getNextSwiperChangeIndex(current)] = that.getNextSwiperNeedItem(currentItem, list) 203 | // console.log(swiperList) 204 | return swiperList; 205 | }, 206 | /** 207 | * 获取swiperList中current上一个的index 208 | */ 209 | getLastSwiperChangeIndex : function (current) { 210 | return current > START ? current - 1 : END 211 | }, 212 | /** 213 | * 获取swiperLit中current下一个的index 214 | */ 215 | getNextSwiperChangeIndex : function (current) { 216 | return current < END ? current + 1 : START 217 | }, 218 | /** 219 | * 获取上一个要替换的list中的item 220 | */ 221 | getLastSwiperNeedItem : function (currentItem, list) { 222 | let listNeedIndex = currentItem.index - 1 223 | let item = listNeedIndex == -1 ? { isFirstPlaceholder: true } : list[listNeedIndex] 224 | return item 225 | }, 226 | /** 227 | * 获取下一个要替换的list中的item 228 | */ 229 | getNextSwiperNeedItem : function (currentItem, list) { 230 | let listNeedIndex = currentItem.index + 1 231 | let item = listNeedIndex == list.length ? { isLastPlaceholder: true } : list[listNeedIndex] 232 | return item 233 | } 234 | 235 | } 236 | }) 237 | --------------------------------------------------------------------------------