免费观影神器之爱影家app开发手记

最近看到360周董分享的几句话,觉得有道理,这里分享下:“想干什么就去干,干得烂总比不干强!”一个粗糙的开始就是一个最好的开始,因为你最快的开始行动了。

忘记一些得失,很多时候我们就是在计较得失,各种各样的得失物质上的、精神上的、面子上的。

不要想着事情一定要做了就一定要做完美。我们一开始可以先去试一段时间,你就可能发现你进步神速。而且能力也越来越强了。只要你敢迈出第一步,以后就会越来越熟练,也就会有成绩有起色。无从下手的时候就随便糊弄了一下,假装自己游刃有余就好。这就是有慢到快,质变产生量变的过程。

干的烂总比不干要好,先完成再完美。

互联网有句话:“不是大鱼吃小鱼,而是快鱼吃慢鱼。”

很多事情等你想清楚了,黄花菜就凉了。想的越多,越不敢去干。先开枪后瞄准,边开枪边瞄准。

想想也确实是这样子的。好多人啊,其实不是他们没有想法,而是想法太多都无法落地。不如挑一个想法把它付诸行动,做起来再说。

干得烂总比不干强,你又害怕什么呢?害怕走弯路?殊不知即便是弯路也好过原地踏步。等待,永远没有机会!做事情不要想那么多了,尤其是别太去计较什么意义和得失,开心就好。把这句话送给自己,也送给你们。

开发背景:从想法到行动

一切都始于一句话:“想干什么就去干,干得烂总比不干强!”受此启发,我决定将自己心中的想法付诸行动——,手机上的观影总是受各种广告的烦扰,自己要开发一款既无广告又免费的观影App。

项目开源地址uniapp晓程序版:https://gitee.com/yyz116/imovie/ 

 HarmonyOS版gitee:hmmovie: 爱影家,开源鸿蒙影视app

 HarmonyOS版github :https://github.com/yangyongzhen/hmmovie

HarmonyOS版本atomgit:hmmovie · AtomGit_开放原子开源基金会代码托管平台 

uniapp的video组件的使用

在移动应用开发中,视频播放是一个常见的需求。uni-app 提供了强大的 video 组件,使得在跨平台应用中集成视频播放功能变得简单高效。本文将详细介绍如何在 uni-app 项目中使用 video 组件。

基本用法

首先,确保你已经在项目中引入了 video 组件。在 pages/index/index.vue 文件中,你可以这样使用:

<template>
  <view class="container">
    <video
      id="myVideo"
      src="https://example.com/path/to/video.mp4"
      controls
      autoplay
      loop
      muted
      initial-time="0"
      duration="100"
      danmu-list="{{danmuList}}"
      enable-danmu
      danmu-btn
      show-progress
      show-fullscreen-btn
      show-play-btn
      show-center-play-btn
      enable-progress-gesture
      object-fit="contain"
      poster="https://example.com/path/to/poster.jpg"
      @play="onPlay"
      @pause="onPause"
      @ended="onEnded"
      @timeupdate="onTimeUpdate"
      @error="onError"
    ></video>
  </view>
</template>

<script>
export default {
  data() {
    return {
      danmuList: [
        { text: '第一条弹幕', color: '#ff0000', time: 1 },
        { text: '第二条弹幕', color: '#00ff00', time: 2 }
      ]
    };
  },
  methods: {
    onPlay() {
      console.log('视频开始播放');
    },
    onPause() {
      console.log('视频暂停');
    },
    onEnded() {
      console.log('视频播放结束');
    },
    onTimeUpdate(e) {
      console.log('视频播放时间更新', e.detail.currentTime);
    },
    onError(e) {
      console.error('视频播放错误', e.detail);
    }
  }
};
</script>

<style>
.container {
  padding: 20px;
}
</style>
<template>
    <view>
        <view>
            <view>
                <video id="myVideo" :src="vsrc"
				      controls="true"
				      autoplay="false"
				      loop="false"
				      muted="false"
                      @error="videoErrorCallback" :custom-cache="false"></video>
            </view>
        </view>
		<uni-card :is-shadow="false"  :title="mv.title" extra="豆瓣评分 >" margin="10rpx">
			<view class="movie-rate">
				<uni-rate :readonly="true" :value="mv.rate/2" size=18 active-color="#ffaa00" color="#DADADA">
				</uni-rate>
				<text class="movie-rate-t">{{mv.rate}}</text>
			</view>
		</uni-card>
		 <!-- 判断 tvurls 是否为空 -->
		<view v-if="tvurls.length > 0">
		  <view>
		    <view class="icon-container" @click="showPopup">
		          <text class="icon-text">选集</text>
		          <view class="icon-badge-wrapper">
		            <uni-icons type="list" size="24" color="#000"></uni-icons>
		            <uni-badge :text="tvurls.length" type="error"></uni-badge>
		          </view>
		    </view>
			<view>
				<uni-grid :column="5" :showBorder="false" :square="false">
				  <uni-grid-item v-for="(url, idx) in limitedTvurls" :key="idx" @click="playEpisode(idx)">
				    <view :class="['episode-item', { active: selectedIndex === idx }]">
				      <text>{{ `第${idx + 1}集` }}</text>
				    </view>
				  </uni-grid-item>
				</uni-grid>
			</view>
		     <uni-popup ref="popup" type="bottom" @maskClick="closePopup">
		       <view class="popup-content">
		         <uni-grid :column="4" :showBorder="false" :square="false">
		           <uni-grid-item v-for="(url, index) in tvurls" :key="index" @click="playEpisode(index)">
		             <view :class="['episode-item', { active: selectedIndex === index }]">
		               <text>{{ `第${index + 1}集` }}</text>
		             </view>
		           </uni-grid-item>
		         </uni-grid>
		       </view>
		     </uni-popup>
		   </view>
		</view>
		<view class="sub-title" >
			简介
		</view>
		<view class="description">
		    <view :class="{'folded': isFolded}" v-html="mv.summary">
				
		    </view>
		    <view @click="toggleDescription" class="toggle-button">
		        {{ isFolded ? '展开' : '收起' }}
		    </view>
		</view>
    </view>
</template>


<script>
	import { getMovieSource } from '@/api/detail.js';
export default {
    data() {
        return {
			s_id:'',
			mv:{},
			isFolded: true ,// 初始状态为折叠
            vsrc: '',
			tvurls:[],
			selectedIndex: -1 // 初始化选中索引为 -1,表示没有选中任何项
        }
    },
	computed: {
	    limitedTvurls() {
	      return this.tvurls.slice(0, 5);
	    }
	},
    onReady: function(res) {
        // #ifndef MP-ALIPAY
        this.videoContext = uni.createVideoContext('myVideo')
        // #endif
    },
	onLoad(params) {
		console.log('videoplay onload');
		//console.log(params);
		const mv_ = JSON.parse(decodeURIComponent(params.mv));
		this.s_id = params.id;
		this.mv = mv_;
	},
	mounted() {
		console.log("mounted")
		console.log(this.s_id)
		getMovieSource(this.s_id).then(result => {
			console.log("getMovieSource,result:");
			console.log(result);
			if (Array.isArray(result.urls) && (result.urls[0] != "")) {
				this.vsrc = result.urls[0]
				if (this.videoContext) {
					this.videoContext.play();
				}
			}else if (Array.isArray(result.tvurls) && result.tvurls.length > 0) {
				this.tvurls = result.tvurls;
			}
			else{
				this.vsrc = "https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/2minute-demo.mp4";
				//this.videoContext = uni.createVideoContext('myVideo')
			    if (this.videoContext) {
			    	this.videoContext.play();
			    }
				// uni.showModal({
				//     content: "暂无片源,可留言反馈",
				//     showCancel: false
				// })
			}
			//console.log(this.v_src);
			
		});
	},
    methods: {
        videoErrorCallback: function(e) {
			console.log(e)
            // uni.showModal({
            //     content: "播放失败,"+e.detail.errMsg,
            //     showCancel: false
            // })
        },
		videoReadyCallback: function(e) {
			console.log('Video ready:', e);
			// 确保视频已准备好再播放
			if (this.vsrc && this.videoContext) {
				this.videoContext.play();
			}
		},
		showPopup() {
		    this.$refs.popup.open();
		},
		closePopup() {
		  this.$refs.popup.close();
		},
		playEpisode(index) {
		  this.selectedIndex = index;
		  // 播放选集的逻辑
		  const url = this.tvurls[index];
		  console.log('play:', url);
		  if (this.videoContext) {
		     this.videoContext.stop();
		  }
		  this.vsrc = url;
		  this.$nextTick(() => {
			  if (this.videoContext) {
				this.videoContext.play();
			  }
		  });
		  this.closePopup();
		  // 可以在这里调用播放视频的 API
		},
        getRandomColor: function() {
            const rgb = []
            for (let i = 0; i < 3; ++i) {
                let color = Math.floor(Math.random() * 256).toString(16)
                color = color.length == 1 ? '0' + color : color
                rgb.push(color)
            }
            return '#' + rgb.join('')
        },
		toggleDescription() {
			this.isFolded = !this.isFolded;
		}
    }
}
</script>

<style lang="scss" scoped>
	
	page {
			display: flex;
			flex-direction: column;
			box-sizing: border-box;
			background-color: #f8f4f5;
			min-height: 100%;
			height: auto;
		}
		
	.content {
	  display: flex;
	  justify-content: center;
	  align-items: center;
	  height: 100vh;
	}

	video {
	  width: 100%;
	  max-width: 800px;
	}
	
	.movie-rate {
		display: flex;
		align-items: center;
		padding: 0rpx;
		margin-bottom: 0rpx;
	}
	
	.movie-rate-t {
		margin-left: 14rpx;
		font-size: 42rpx;
		font-weight: bold;
	}
	.sub-title {
		padding-left: 20rpx;
		font-size: 32rpx;
		font-weight: bold;
	}
	
	.description {
		display: flex; /* 添加flex布局 */
		flex-direction: column; /* 设置为列方向 */
	    line-height: 1.5;
		padding: 20rpx;
		font-size: 28rpx;
	}
	
	.folded {
	    overflow: hidden;
	    text-overflow: ellipsis;
	    display: -webkit-box;
	    -webkit-line-clamp: 4; /* 控制显示行数 */
	    -webkit-box-orient: vertical;
	}
	.toggle-button {
	    cursor: pointer;
	    margin-top: 20rpx;
		align-self: flex-end; /* 使按钮靠右对齐 */
	}
	
	.popup-content {
	  max-height: 500rpx; /* 限定最大高度 */
	  overflow:hidden;
	  overflow-y: auto; /* 添加滚动条 */
	  background-color: #fff;
	  padding: 20px;
	}
	
	.episode-item {
	  display: flex;
	  flex-direction: column;
	  align-items: center;
	  justify-content: center;
	  height: 100%;
	  padding: 10rpx;
	  margin: 5rpx;
	  border: 1px solid #ccc;
	  border-radius: 15rpx;
	  cursor: pointer;
	}
	
	.episode-item.active {
	  background-color: #007aff;
	  color: #fff;
	}
	
	.episode-item text {
	  margin-bottom: 10rpx;
	}
	
	.icon-container {
	  display: flex;
	  align-items: center;
	  justify-content: space-between;
	  cursor: pointer;
	  padding: 10px;
	}
	
	.icon-text {
	  font-size: 32rpx;
	  font-weight: bold;
	  color: #000;
	}
	
	.icon-badge-wrapper {
	  display: flex;
	  align-items: center;
	}

</style>

也算是想干就干吧,总比打游戏强吧。

在数字娱乐时代,对于电影爱好者而言,随时随地享受精彩影片成为一种日常需求。分享一款基于 uni-app 开发的影视类小程序。它不仅提供了丰富的影视资源推荐,还融入了个性化知乎日报等内容,是不错的素材,同时对电影爱好者来说可以关注最新电影动态,免费且无广告,分享给大家体验。

希望能结交更多的朋友,可以加入猫哥技术交流群,加我微信拉你入群,与更多技术爱好者交流思想。

爱影家小程序采用 uni-app 框架构建,兼容多平台,无论是 iOS、Android 还是 H5 页面,都能流畅运行。项目使用了 Vue.js ,使得前端开发更加高效,同时也利用了 uni-app 的丰富插件,实现了诸如电影详情、搜索、分类、评价、收藏等一系列核心功能。

一个人独立开发,完成前端小程序和后台服务,我的后台接口采用golang+MongoDB实现。目前小程序接口使用的我部署好的腾讯云服务器服务,下载项目后即可直接体验和运行。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

特立独行的猫a

您的鼓励是我的创作动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值