Uni-app 详情页 播放视频功能

Posted YoloAva

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Uni-app 详情页 播放视频功能相关的知识,希望对你有一定的参考价值。

逻辑:

1.课程详情页加载后,用token判断用户是否登录,登录状态则调用checkAuth的接口(只传入courseId),后端会返回hasAuth为true/false

2.点击某一章节时,登录状态则调用checkAuth的接口(传入courseId & chapterId),后端会返回hasAuth为true/false和videoId,如果这俩都有,则跳页面到视频播放页

3.跳转到视频播放页,加载完毕:请求课程详情接口、getPlay接口(传入courseId & chapterId)——后端返回formt,videoURL,duration等

功能:

4.自动跳转至上次播放时间:

        加载完视频播放页,调checkHistory得到上次的记录——接着使用视频控制进度的组件uni.createVideoContext的seek方法,将checkHistory返回的lastTime传入

5.记录播放历史:

        video标签上绑定@timeupdate方法,这个方法在播放进度变化时触发,也就是只要在播放就在不停的触发,所以每次进入方法都this.timer++,当它等于25时也就是每隔6s,调用recordHistory记录播放进度的接口,并使this.timer变回为1

6.倍速播放:

        下载f-drop-menu插件,绑定videoList,以及changeSpeed事件,使用视频控制进度的组件uni.createVideoContext的playbackRate方法

7.下一节/重学一次

        在data中,分别用new Map来new空的实例对象 ,Map字典数据结构是为了方便以[键,值]的形式存储数据,给每个小节做标记。

        在初次进入视频页,调课程详情接口时,返回的数据是章嵌套节的结构。所以先循环章,再循环节,将这个实例对象使用set方法,将小节信息设置成键值对的数组,目的是为了给每个小节做标记。

        给video绑定了ended事件——在播放结束时用这个实例对象的get方法查找读取key对应的键值,找到下一个章节对应的信息。

        判断——如果下个章节有内容,就提示下一节/重学的选项。

8.视频防盗

        在video标签中加上视频来源,否则后端会判断为为非法入侵。

<template>
  <view class="course-play">
    <u-navbar title="视频" class="header"></u-navbar>
    <video id="myVideo" :src="videoUrl" controls :header="'Referer':'http://testapp.cn'" :poster="cover"
      @timeupdate="timeupdate" @ended="playEnded" class="video-play"></video>
    <view class="video-control">
      <view class="" @tap="dropSpeed">倍速:speed</view>
      <f-drop-menu :list="videoList" v-model="show" @click="changeSpeed"></f-drop-menu>
    </view>
    <view class="tabs">
      <u-tabs-swiper ref="uTabs" :list="list" :current="current" @change="tabsChange" :is-scroll="false"
        swiperWidth="750"></u-tabs-swiper>
    </view>
    <swiper class="swiper" :current="swiperCurrent">
      <swiper-item class="swiper-item">
        <scroll-view scroll-y style="height: 800rpx;width: 100%;">
          <u-collapse accordion class="ui-collapse" :border="false" event-type="close">
            <u-collapse-item :title="item.chapterName" :open="index === 0" v-for="(item,index) in catalogueList"
              :key="item.id">
              <view class="child-item" v-for="child in item.children" :key="child.id"
                :class="child.id === current ? 'collapse-active':''" @tap="goPlay(child)">
                <view class="video-box">视频</view>
                <view class="content-box">child.chapterName</view>
              </view>
            </u-collapse-item>
          </u-collapse>
        </scroll-view>
      </swiper-item>
      <swiper-item class="swiper-item">
        <scroll-view scroll-y style="height: 800rpx;width: 100%;">
          <Download :downloadList="downloadList"></Download>
        </scroll-view>
      </swiper-item>
    </swiper>
    <u-toast ref="uToast" />
  </view>
</template>

<script>
  import 
    mapState
   from 'vuex'
  import Download from '@/common/course-detail/download/index.vue'
  import courseApi from '@/service/coursedetail.js'
  import playApi from '@/service/play.js'
  export default 
    data() 
      return 
        speed: 'X1.0',
        show: false, //默认不显示
        videoList: [
          name: '0.5',
          style: 

          
        , 
          name: '1.0',
          style: 

          
        , 
          name: '1.25',
          style: 

          
        , 
          name: '1.5',
          style: 

          
        ],
        courseId: null,
        chapterId: null,
        swiperCurrent: 0,
        current: 0,
        list: [
          name: '目录'
        , 
          name: '下载笔记代码'
        ],
        downloadList: [],
        catalogueList: [],
        clientHeight: 0,
        cover: null, // 封面图
        videoUrl: null, // 视频
        totalTime: null, // 总时长
        timer: 1, // 控制
        indexMap: new Map(), //保存
        maps: new Map(),
        videoContext: null, // 视频控制组件
      
    ,
    computed: 
      ...mapState(
        userInfo: state => state.user.userInfo
      ),
      curId() 
        // curId 
        if (this.chapterId !== 0) 
          return this.chapterId
         else 
          // 第一个章节里面第一个小节
          return this.catalogueList[0].children[0].id
        
      ,
    ,
    components: 
      Download
    ,
    onReady() 
      //视频进度控制组件
      this.videoContext = uni.createVideoContext('myVideo')
      // 动态获取头部高
      const query = uni.createSelectorQuery().in(this);
      query.select('.header').boundingClientRect(data => 
        uni.getSystemInfo(
          success: (res) => 
            this.clientHeight = res.screenHeight - data.height
          
        );
      ).exec();
      // video
      query.select('.video-play').boundingClientRect(data => 
        this.clientHeight = this.clientHeight - data.height
      ).exec();
      // video-control
      query.select('.video-control').boundingClientRect(data => 
        this.clientHeight = this.clientHeight - data.height
      ).exec();
      // 切换
      query.select('.tabs').boundingClientRect(data => 
        this.clientHeight = this.clientHeight - data.height
      ).exec();
    ,
    onLoad(params) 
      this.courseId = params.courseId
      this.chapterId = params.chapterId
      // 如果是点击了重学跳过来的 就有restudy
      let restudy = params.restudy
      this.__init()
      if (!restudy) 
        this.checkHistory()
      
    ,
    methods: 
      //点击倍速
      dropSpeed() 
        this.show = !this.show
      ,
      //切换倍速
      changeSpeed(item) 
        this.speed = 'X' + item.name
        this.videoContext.playbackRate(Number(item.name))
        this.show = false
      ,
      __init() 
        // 获取课程 详情
        //获取课程详情
        courseApi.getClassDetail(
          classId: this.courseId
        ).then(res => 
          if (res.meta.code === '200') 
            //当前课程的目录
            this.catalogueList = res.data.data.bizCourseChapters
            //笔记代码
            this.downloadList = res.data.data.bizCourseAttachments
            let idx = 0;
            //先循环章
            res.data.data.bizCourseChapters.map((item, index) => 
              //再循环节 
              item.children.map((ele) => 
                //本课程所有小节 组成一个不重复的数组 给每个小节做标记
                this.indexMap.set(ele.id, idx) // 节 ['节ID',0,'节ID',1]
                this.maps.set('chapter_' + idx, ele) //['chapter_0',节信息,'chapter_1',节信息]
                idx++
              )
            )
           else  //非200

          
        ).catch(err => 
          console.log(err)
        )
        // 视频播放
        playApi.getPlay(
          courseId: this.courseId,
          chapterId: this.chapterId
        ).then(res => 
          if (res.meta.code === '200') 
            let playInfoList = res.data.playInfo.playInfoList
            let chapterInfo = res.data.chapterInfo //封面图
            let arr = playInfoList.filter(item => 
              if (item.format === 'mp4') 
                return item
              
            )
            console.log(arr) //[]
            let obj = arr[0] //含videoUrl,format,duration的对象
            this.videoUrl = obj.playURL
            this.totalTime = obj.duration
            this.cover = chapterInfo.chapterLitpic
          
        ).catch(err => 
          console.log(err)
        )

      ,
      //查询上一次播放的进度
      checkHistory() 
        playApi.checkHistory(
          memberId: this.userInfo.id,
          courseId: this.courseId,
          chapterId: this.chapterId
        ).then(res => 
          if (res.meta.code === '200')  //查询到进度 并且用控件调整进度
            this.videoContext.seek(Number(res.data.data.lastTime))
          
        ).catch(err => 
          console.log(err)
        )
      ,
      //历史记录
      recordHistory(lastTime) 
        playApi.recordHistory(
          chapterId: this.chapterId,
          courseId: this.courseId,
          memberId: this.userInfo.id,
          lastTime: lastTime //上次观看时间
        ).then(res => 
          if (res.meta.code === '200')  //记录成功
            this.timer = 1
           else 
            //记录失败
          
        ).catch(err => 
          console.log(err)
        )
      ,
      //播放进度变化时触发 历史记录 存储播放进度
      timeupdate(e) 
        let curTime = e.detail.currentTime
        console.log(curTime)
        if (this.timer === 25) 
          //调一次记录历史记录的接口
          this.recordHistory(curTime)
          console.log('记录')
        
        this.timer++ //每次变化+1
      ,
      //播放结束
      playEnded(e) 
        this.recordHistory(this.totalTime)
        // this.indexMap.set(ele.id,idx)// 节 ['节ID',0,'节ID',1]
        // this.maps.set('chapter_'+idx,ele)//['chapter_0',节信息,'chapter_1',节信息]
        //查找对应项
        let index = this.indexMap.get(this.chapterId); //idx
        let nextChapter = this.maps.get('chapter_' + (index + 1)) //后面一章的节信息
        if (nextChapter)  //如果后面还有
          //下一个小节 视频
          uni.showModal(
            title: '提示',
            content: '继续下一小节',
            confirmText: '下一小节',
            cancelText: '重学',
            success: res => 
              if (res.confirm) 
                //继续学 下一小节
                uni.redirectTo(
                  url: '/pages/course-play/course-play?courseId=' + this.courseId + '&chapterId=' +
                    nextChapter.id
                )
               else if (res.cancel) 
                //重学
                uni.redirectTo(
                  url: '/pages/course-play/course-play?courseId=' + this.courseId + '&chapterId=' + this
                    .chapterId + '&restudy=' + 'true'
                )
              
            
          );
         else 
          this.$refs.uToast.show(
            title: '恭喜你学完本课程',
            type: 'success',
            icon: false
          )
        
      ,
      //播放另一个章节
      goPlay() 
        this.chapterId = child.id
        //关闭当前页 重定向
        uni.redirectTo(
          url: '/pages/course-play/course-play?courseId=' + this.courseId + '&chapterId=' + child.id
        )
      ,
      tabsChange()
        
      
    
  
</script>

uni-app 视频播放遇到的问题-video

最近开发一个项目,一个视频列表,点击其中一个视频,全屏播放(像大屏预览似的全屏),图上覆盖截图,全屏和回放图标。

本文涉及到的知识点:

1。视频播放video组件使用;

2。图片下载uni.downloadFile;

3。上拉加载,下拉刷新

4。subNVue;

5。父子组件传值

弹出的全屏窗口:

videoTest.vue

<template>
	<view style="height: 100%;">
		<videoView :srcPath="src" :picPath="picPath"></videoView>
	</view>
</template>

<script>
	import videoView from './video.nvue'
	export default 
		components:
			videoView,
		,
		data() 
			return 
				picPath:'',
				src: 'https://img.cdn.aliyun.dcloud.net.cn/guide/uniapp/%E7%AC%AC1%E8%AE%B2%EF%BC%88uni-app%E4%BA%A7%E5%93%81%E4%BB%8B%E7%BB%8D%EF%BC%89-%20DCloud%E5%AE%98%E6%96%B9%E8%A7%86%E9%A2%91%E6%95%99%E7%A8%8B@20181126-lite.m4v',
			
		,
		onLoad(params) 
			this.src = params.path;
			this.picPath = params.picPath;
		,
		methods:
			goBack() 
				uni.navigateBack();//跳转到上一个页面
			,
		
	
</script>

<style>
	
</style>

video.nvue

<template>
	<view class="video_bg" @click="goBack">
		<video id="myVideo" :src="srcPath" class="video_width"
			@error="videoErrorCallback" controls="true"
			autoplay="true" direction="90" objectFit="fill" 
			@play="beginPlay" @fullscreenchange="changeFull"
			enable-play-gesture="true" :show-center-play-btn="true"
			:poster="picPath" @click="">
			<cover-image src="../../static/images/check/icon_full.png" class="cover_img_common right_20" @click="fullScreen()"></cover-image>
			<cover-image src="../../static/images/check/icon_crop.png" class="cover_img_common right_65"></cover-image>
		</video>
	</view>
</template>

<script>
	export default 
		data() 
			return 
				videoContext:null,
			
		,
		mounted() 
			this.videoContext = uni.createVideoContext('myVideo');
		,
		props:srcPath:String,picPath:String,
		methods:
                        //返回上一页前先结束播放,并将屏幕方向还是设为默认
			goBack() 
				this.videoContext.stop();
				uni.navigateBack();
				plus.screen.lockOrientation('default'); 
			,
			videoErrorCallback: function(e) 
			    uni.showModal(
			        content: e.target.errMsg,
			        showCancel: false
			    )
			,
                        //监听播放状态
			beginPlay(params) 
				console.log('playStatus',params);
				this.playStatus = 1;
			,
                        //只有视频开始播放后,全屏按钮可用
			fullScreen(item) 
				if(this.playStatus == 1) 
					this.videoContext.requestFullScreen();
				
			,
			changeFull(params) 
				console.log('changeFull',params);
				if(params.detail.fullScreen) 
                                        //不能动态设置进度条的显示
					// this.videoContext.controls = true;
				 else 
					plus.screen.lockOrientation('portrait-primary'); 
				
				//屏幕方向数值: 0 - 竖屏; 90 - 横屏,HOME键在右; 180 - 反向竖屏; -90 - 反向横屏,HOME'键在左
			  //  let orit = plus.navigator.getOrientation();
			  //  if((orit==0)||(orit==180))
					// //竖屏做的操作
			  //  else
					// //横屏做的操作
			  //  

			
		
		
	
</script>

<style>
	page
		height: 100%;
	
	.video_width 
		width: 100%;
		/* z-index: 100; */
		
	
	.cover_img_common 
		width: 25px; height: 25px;float: right;position: absolute;bottom: 15px;
	
	.right_20 
		right: 20px;
	
	.right_65 
		right: 65px;
	
	.right_110 
		right: 110px;
	
	.video_bg 
		height:100%;display: flex;justify-content: center;align-items: center;
	
</style>

横竖屏方向:

“orientation” : [
        //竖屏正方向
        “portrait-primary”,
        //竖屏反方向
        “portrait-secondary”,
        //横屏正方向
        “landscape-primary”,
        //横屏反方向
        “landscape-secondary”,
        //自然方向
        “default”
]

视频列表页:

列表中做了两种处理:

1。有视频时显示视频,并显示封面,但点击视频时,并不触发播放,是弹出全屏页面,在全屏页面进行全屏,截图等操作;这种处理需要用subNVue特殊处理一下弹出框,要不然弹出框会被视频遮挡。

2。另一种处理是不管有没有视频,都显示图片,有视频的图片给它显示播放按钮和截屏按钮,但点击图片时,仍然会弹出全屏页面。被注释掉的代码就是只显示图片的处理。

<template>
	<view>
		<uni-nav-bar title="远程巡店" backgroundColor="#074498" color="white" fixed="true"
			statusBar='true' @clickRight="searchPerson">
			<view slot="right" class="flex_vcenter">
				<image src="../../static/images/workbeach/icon_search.png" class="imgSize"></image>
			</view>
		</uni-nav-bar>
		<uni-list :border="false">
			<UniListItemCustomer v-for="(item,index) in deviceList" :key="index"  :border="false" direction="column" class="item" clickable @click="gotoDetail(item.deviceId)">
				<template v-slot:header>
					<view>
						<!-- <view v-if="item.realTimeResults" style="display: flex;align-items: center;justify-content: center;">
							<image ref='img' :src="item.realTimeResults[2].picUrl" class="video_width"
							 @error="handleImageError1" @click="fullPlay(item)"></image>
							 <image src="../../static/images/check/icon_play.png" class="play_icon"></image>
							 <image src="../../static/images/check/icon_full.png" class="cover_img_common right_20" @click="fullScreen(item)"></image>
							 <image src="../../static/images/check/icon_crop.png" class="cover_img_common right_65" @click="cropPic(item.deviceId)"></image>
						</view> -->
						<video id="myVideo" :src="item.realTimeResults[2].hls" class="video_width"
							@error="videoErrorCallback" controls="false" v-if="item.realTimeResults"
							autoplay="false" direction="90" objectFit="fill" 
							@play="beginPlay" @fullscreenchange="changeFull"
							enable-play-gesture="true"
							:poster="item.realTimeResults[2].picUrl">
							<cover-image @click="fullPlay(item)"></cover-image>
							<cover-image src="../../static/images/check/icon_full.png" class="cover_img_common right_20" @click="fullScreen(item)"></cover-image>
							<cover-image src="../../static/images/check/icon_crop.png" class="cover_img_common right_65" @click="cropPic(item.deviceId)"></cover-image>
						</video>
						<image src="../../static/images/icon_check_default.png" class="check_img" @error="handleImageError" v-else></image>
					</view>
				</template>
			</UniListItemCustomer>
		</uni-list>
		<uni-load-more :status="more" :contentText="contentText" @clickLoadMore="more=='error'?getPersonelList():''"></uni-load-more>
	</view>
</template>

<script>
	import ApiService from './service.js'
	import Tips from '../../utils/tips.js'
	import UniListItemCustomer from '../../components/uni-list-item/uni-list-item-customer.vue'
	export default 
		components:
			UniListItemCustomer
		,
		data() 
			return 
				deviceList:[],
				searchCondition:,
				more:'more',
				pageNum:1,
				pageSize:10,
				contentText: 
					contentdown: '上拉加载更多',
					contentrefresh: '正在加载中',
					contentnomore: '没有更多数据了',
					contenterror: '数据异常,请点击此处重新加载'
				,
				reLoad:false,
				videoContext:null,
				playStatus:0,
			
		,
		created() 
			this.getVideoInfoList();
			console.log('created');
		,
		mounted() 
			console.log('mounted');
		,
		onReady() 
			this.videoContext = uni.createVideoContext('myVideo')
		,
		onLoad() 
			uni.$on('receiveData',(options)=>
				console.log('onLoad====receiveData',JSON.stringify(options));
				this.searchCondition = options;
				this.reLoad = true;
				this.pageNum = 1;
				this.getVideoInfoList();
			)
		,
		onReachBottom() 
			console.log('onReachBottom');
			if(this.more != 'noMore') 
				this.more = 'more';
				this.getVideoInfoList();
			
		,
		onPullDownRefresh() 
			console.log('onPullDownRefresh');
			this.reLoad = true;
			this.pageNum = 1;
			this.getVideoInfoList();
		,
		methods:
			goBack() 
				uni.navigateBack();//跳转到上一个页面
			,
			searchPerson() 
				const subNvue = uni.getSubNVueById('netDialog');
				subNvue.show();
			,
			async getVideoInfoList() 
				this.searchCondition['pageSize'] = this.pageSize;
				this.searchCondition['pageNum'] = this.pageNum;
				this.more = 'loading';
				let res = await ApiService.getVideoInfoList(this.searchCondition);
				// console.log('getPersonelList',JSON.stringify(res));
				if(res.success) 
					if(res.data.code == 200) 
						this.deviceList = this.reLoad?res.data.data.rows:this.deviceList.concat(res.data.data.rows);
						
						if(this.deviceList.length != res.data.data.total) 
							this.pageNum += 1;
							this.more = 'more';
						 else 
							this.more = 'noMore';
						
					 else 
						if(this.pageNum == 1) 
							this.deviceList = [];
						
						Tips.toast(res.data.msg);
						this.more = 'error';
					
					
				 else 
					 Tips.toast(res.message);
					 this.more = 'error';
				
				if(this.reLoad) 
					uni.stopPullDownRefresh();
					this.reLoad = false;
				
			,
			gotoDetail(item) 
				console.log(item)
				uni.navigateTo(
					url: 'personnelDetail?item='+JSON.stringify(item)
				)
			,
			videoErrorCallback: function(e) 
			    uni.showModal(
			        content: e.target.errMsg,
			        showCancel: false
			    )
			,
			handleImageError1(props) 
				console.log('handleImageError',props);
				this.$refs.img.src = '../../static/images/icon_check_default.png'
			,
			handleImageError(props) 
				console.log('handleImageError',props);
				this.picPath = '../../static/images/icon_check_default.png'
			,
			beginPlay(params) 
				console.log('playStatus',params);
				this.playStatus = 1;
			,
			async cropPic(deviceId) 
				let res = await ApiService.getSnapshot("deviceId":deviceId);
				console.log('cropPic',res);
				if(res.success) 
					if(res.data.code == 200) 
						let picPath = res.data.data.url;
						console.log('cropPic picPath=',picPath);
						//下载截图
						uni.downloadFile(
							url:picPath,
							success: (res) => 
								console.log('下载成功',res);
								if(res.statusCode === 200) 
									console.log('下载成功');
									Tips.toast('下载成功');
								
							,
							fail: (error) => 
								console.log('下载失败',error);
								Tips.toast('下载失败');
							
						)
					 else 
						Tips.toast(res.data.msg);
					
				 else 
					Tips.toast(res.message);
				
			,
			fullScreen(item) 
				if(this.playStatus == 1) 
					this.videoContext.requestFullScreen();
				
			,
			changeFull(params) 
				console.log('changeFull',params);
				if(params.detail.fullScreen == true) 
					this.videoContext.controls = true;
				
			,
			fullPlay(item) 
				console.log('3333');
				uni.navigateTo(
					url:'./videoTest?path='+item.realTimeResults[2].hls+'&picPath='+item.realTimeResults[2].picUrl
				)
			
		
	
</script>

<style lang="scss" scoped>
	@import '../../styles/base.scss';
	page 
		background: #f9f9f9;
		overflow-x: hidden;
		padding: 0;
	
	.nav-style 
		font-family: 'PingFangSC-Semibold', 'PingFang SC Semibold', 'PingFang SC';
		height: 45px;
	
	.status_style 
		float: right;position: absolute;right: 35px;
		font-size: 16px;
		font-family: 'PingFangSC-Regular', 'PingFang SC';
	
	.common_color 
		color:#074498
	
	.title_size 
		font-size: 16px;
	
	.status_color_use 
		color: #73B703;
	
	.status_color_forbidden 
		color: #D9001B;
	
	.item_text 
		/* padding-top: 8px; */
		font-family: 'PingFangSC-Regular', 'PingFang SC';
		color: #333333;
		font-size: 14px;
		line-height: 25px;
	
	.arrow_right 
		width: 20px;
		height: 25px;
		float: right;
		right: 20px;
		position: absolute;
	
	.item_content 
		padding: 10px 0px 0px 0px; 
		display: flex;flex-direction: column;
	
	.divider 
		height: 0.5px;width: 100%; background-color: #dbdbdb;margin-top: 10px;
	
	.flex_vcenter 
		display: flex; align-items: center;
	
	.item 
		border-bottom: #f9f9f9 8px solid;
		/* padding: 0px 15px 0px 15px; */
	
	.video_width 
		width: 100%;
		z-index: 100;
		background-image: url(../../static/images/icon_check_default.png);
		background-size: 100% 100%;
		opacity: 0.5;
	
	.cover_img_common 
		width: 25px; height: 25px;float: right;position: absolute;bottom: 15px;
	
	.play_icon 
		position: absolute;width: 60px; height: 60px;
	
	.right_20 
		right: 20px;
	
	.right_65 
		right: 65px;
	
	.right_110 
		right: 110px;
	
	.imgSize 
		width: 25px; height: 25px;
	
	.check_img 
		width: 100%;opacity: 0.5;
	
</style>

video层级过高,导致弹窗显示在底层,解决方法:


			"path": "pages/netcheck/NetCheckList",
			"style": 
				"navigationBarTitleText": "远程巡店",
				"enablePullDownRefresh":true,//下拉刷新配置
				"app-plus": 
					"pullToRefresh": 
						"style":"circle",
						"offset": "88px"
					,
					"subNVues":[  
						"id": "netDialog", // 唯一标识  
						"path": "pages/netcheck/subNVue/DialogNet", // 页面路径  
						"type": "popup",  //原生子窗口内置样式,可取值:'popup',弹出层;"navigationBar",导航栏
						"style":   
							"position":"fixed",
							// "height": "60px",
							// "top":"40px",
							// "top":"40%",
							"background":"transparent"
						  
					]  
				
			
		,

DialogNet.vue

<template>
    <view class="my-confirm-notice" id="netDialog">
        <view class="confirm-content-wrap1" @click="">
            <!-- 标题 -->
            <div class="unipop__ui_tit">
				<text class="unipop__ui_tit_text">查询条件</text>
				<image src="../../../static/images/workbeach/icon_close.png" class="close_image" @click="close()"></image>
			</div>
            <!-- 内容 -->
            <div class="content_margin">
            	<div class="flex_row_center label_text label_margin">
					<text style="font-size: 16px;">实体名称:</text>
            		<input type="text" class="inputStyle" placeholder="实体名称" @input="onKeyInput" :value="userName" >
            	</div>
            </div>
            <div v-if="btns" class="unipop__ui_btns">
                <text v-for="(item,index) in btns" :key="index" class="btn" :style="item.style" @tap="btnTaped(item)">item.text</text>
            </div>
        </view>
    </view>
</template>


<script>
	export default 
		data() 
		    return 
		        btns:[
					
						text: '重置',
						style: 'color: #ffffff',
					,
					
						text: '确定',
						style: 'color: #ffffff',
					
				],
				selectCondition:,
				userName:'',
		    
		,
		mounted() 
			console.log('mounted==================1111111111111111')
		,
		methods: 
			close()
				this.userName = '';
				this.selectCondition = ;
				const subNvue = uni.getSubNVueById('netDialog');
				subNvue.hide();
			,
			btnTaped(item) 
				console.log(item);
				if(item.text == '重置') 
					this.userName = '';
					this.selectCondition = ;
				 else 
					uni.$emit('receiveData',this.selectCondition);
					this.close();
				
			,
			onKeyInput(event) 
				this.userName = event.detail.value;
				this.selectCondition['storeName'] = this.userName;
			,
		
	
</script>

<style lang="scss">
	.my-confirm-notice 
		position: fixed;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		background-color: rgba(0, 0, 0, 0.5);
		// z-index: 19998;
		/* 这里防止当用户长按屏幕,出现的黑色背景色块,以及 iPhone 横平时字体的缩放问题 */
		// -webkit-text-size-adjust: 100%;
		// -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
		display: flex;
		align-items: center;
		justify-content: center;
	
	.confirm-content-wrap1 
		position: relative;
		left: 0;
		right: 0;
		width: 675rpx;
		/* #ifndef APP-PLUS-NVUE */
		height: auto;
		margin: 0 auto;
		user-select: none;
		/* #endif */
		background-color: white;
		border-radius: 10px;
		// z-index: 999;
	
	.unipop__ui_tit 
		background-color: #074498;
		width: 675rpx;
		border-top-left-radius: 10px;
		border-top-right-radius: 10px;
		height: 44px;
		display: flex;
		align-items: center;
		justify-content: center;
	
	.unipop__ui_tit_text 
		color: white;
		text-align: center;
		line-height: 44px;
		width: 675rpx;
		font-size: 16px;
	
	.close_image 
		z-index: 100;
		position: absolute;
		/* #ifndef APP-PLUS-NVUE */
		float: right;
		/* #endif */
		right: 10px;width:30px;height: 30px;
	
	.unipop__ui_btns
		height: 80px;
		justify-content: space-around;
		display: flex;
		flex-direction: row;
		padding-left: 20px;
		padding-right: 20px;
		align-items: center;
	
	.btn 
		width: 80px;
		height: 34px;
		background-color: #074498;
		line-height: 34px;
		text-align: center;
		font-size: 13px;
		border-radius: 6rpx;
	
	.content_margin 
		padding: 15px 0px 5px 0px;
	
	.flex_row_center 
		display: flex; flex-direction: row; justify-content: center; align-items: center;
	
	.label_text 
		font-size: 28rpx;color: #555555;
	
	.label_margin 
		margin-top: 36rpx;
	
	.inputStyle 
		border: #bababa 0.5px solid; width: 169px;height: 40px; 
		/* #ifndef APP-PLUS-NVUE */
		box-sizing: border-box; 
		/* #endif */
		font-size: 14px; color: #aaaaaa; padding: 3px 5px;
	
	.top_level 
		position: fixed;z-index: 100;width: 675rpx;
	
</style>

注意:

(1)subNVue弹窗的显示,只能使用js的show方法,无法携带参数。

(2)参数传递使用uni.$emit和uni.$on

以上是关于Uni-app 详情页 播放视频功能的主要内容,如果未能解决你的问题,请参考以下文章

在uni-app中使用腾讯视频插件播放视频

uni-app1 uniapp介绍 & 使用 + 小程序实时获取视频播放时间

uni-app开发一个小视频应用(二)

使用uni-app组件播放视频

uni-app 视频播放遇到的问题-video

uni-app视频组件设置圆角