当前位置: 首页 > news >正文

Vue3学习(六)Vue3 + ts几种写法

前言

官网提到组合式api和选项式api

选项式api其实就是vue2的写法,组合式api是vue3的新写法(组合式api可以在script中使用setup()也可以使用<script setup>,<script setup>是setup()的语法糖,语法糖的写法在vue3.2后才支持)

参考

Vue3官网的一些文章

Vue3语法官网教程

官网迁移教程 (Vue2和Vue3差异点)

组合式api setup()用法

单文件组件 <sctipt setup>用法

Vue3使用setup()函数核心API写法

vue3中使用TypeScript

Vue3结合TS项目开发实践总结

Vue3写法总结

Vue3种使用<script setup>语法糖核心API写法

上手后才知道 ,Vue3 的 script setup 语法糖是真的爽

Vue3 中setup()和<script setup></script>

Vue3 <script setup>语法糖+ts+Hook实践探索

Vue3一些API用法

vue3 ref函数用法

Vue3中ref和reactive的区别

Vue3第一篇之ref和reactive详解扩展

实战

Vue3使用setup()函数

复制代码

<script lang="ts">
import { defineComponent, onMounted, ref, watch, nextTick, computed, onBeforeUnmount } from '@vue/composition-api';
import { useVisibility } from '@live/hooks/src/useVisibility';
import { toWorkVideoPage, getCookie, parseQuery, toLiveRoomByUserId, openProfile, osName, query } from '@live/actions';
import { throttle, isInLiveRoom, isLowDeviceBiz } from '../../utils/init';
import { BOOKSTATUS, ENROLLSTATUS, EVENTSTATUS } from '../../schemas';
import loadingsvg from './img/loading.svg';
import type { PropType } from '@vue/composition-api';
import type { TTabPhotoList, TEventList, TTabs } from '../../schemas';
// import LoadingIcon from '@/components/LoadingIcon/index.vue';
import { showToast } from '@/utils/init';
import { sendShow, sendClick } from '@/logs/index';
import TabSwiper from '@/components/TabSwiper/index.vue';
// import LottieIcon from '@/components/LottieIcon/index.vue';export default defineComponent({components: {Swiper,Sticky,// LottieIcon,TabSwiper,// LoadingIcon,LottieIcon: () => import(/* webpackChunkName:"lottie-icon" */ '@/components/LottieIcon/index.vue'),},props: {tabPhotoList: {type: Array as PropType<TTabPhotoList[]>,default: () => [],},currentTabIndex: {type: Number,default: 0,},bookStatusLoading: {type: Boolean,default: false,},},emits: ['updateCurrentTabIndex', 'handleEnroll', 'handleBook',],setup(props, { emit }) {const swiperPanelRef = ref();const currentSwiperPanelIndex = ref(0);const setTimeoutId = ref();// 当前页面是否可见,settimeout中需要判断是否播放视频const isVisibility = ref(true);// 当前video是否可见,只有video可见 && 页面可见才播放视频const isVisibilityVideo = ref(true);const swiperPannelItemRef = ref();const laterRender = ref(false);setTimeout(() => {laterRender.value = true;});watch([() => props.currentTabIndex],() => {if (currentSwiperPanelIndex.value === 0) {sendShow(getPanelShowLog(0));}},{immediate: false,},);// 自动播放第一个视频onMounted(() => {sendShow(getPanelShowLog(0));handleVideoPlay();// 离开可视区不播放视频const io = new IntersectionObserver(res => {if (res[0].intersectionRatio > 0) {isVisibilityVideo.value = true;handleVideoPlay();} else {isVisibilityVideo.value = false;isVisibility.value = true;videoStop();}});io.observe(document.querySelector('.swiper-panel-main')!);});onBeforeUnmount(() => {videoStop();});useVisibility({visibleHandler: () => {console.log('----visibleHandler-00-0---');isVisibility.value = true;// 此处安卓端未生效,代码执行到,但是视频没有重新播放// if (osName !== 'android') { // fix 安卓偶先播放状态下漏出封面图// pc,ios,androidhandleVideoPlay(1000, false);// }},hiddenHandler: () => {isVisibility.value = false;console.log('----hiddenHandler-00-0---');// 此处安卓端未生效,代码执行到,但是视频没有因此暂停// if (osName !== 'android') {videoStop(false);// }},});// const videoVisibilityCallBack =const eventListByIndex = computed<TEventList[]>(() => {return (props.tabPhotoList[props.currentTabIndex] as TTabPhotoList).eventList || [];});const tabsByTabPhotoList = computed<TTabs[]>(() => {return props?.tabPhotoList?.map((item: TTabPhotoList) => {return {tabTitle: item?.tabTitle,tabCode: item?.tabCode,selectedTitle: item?.selectedTitle,};});});const onSwiperTabsChange = (index: number) => {// currentSwiperTabsIndex.value = index;emit('updateCurrentTabIndex', index);currentSwiperPanelIndex.value = 0;swiperPanelRef?.value?.to(0);handleVideoPlay();};const getPanelShowLog = (index: number) => {const event: any = (props as any).tabPhotoList[props.currentTabIndex].eventList[index];return {action: 'BLIND_DATE_VENUE_VIDEO_CARD',params: {author_id: event.authorInfo.userInfo.user_id,id: event.eventId,status: event.eventStatus,tab_name: props.tabPhotoList[props.currentTabIndex].tabTitle,video_id: event.photo.photoId,},};};const onSwiperPanelChange = (index, lastIndex) => {sendShow(getPanelShowLog(index));currentSwiperPanelIndex.value = index;handleVideoPlay();};const videoStop = (isInitPoster = true) => {try {if (isInLiveRoom()) {return;}// 暂停隐藏封面if (isInitPoster) {initPoster();}const dom = document.querySelectorAll('.swiper-panel-item video');dom.forEach((item: HTMLVideoElement) => {item?.pause();// item?.load();console.log('stop', item.className);});} catch (e) {console.log('error', 'videostop', e);}};/*** 播放视频处理:ref不太满足播放控制,采用document.querySelectorAll直接获取dom* 1.涉及到过渡动画,影响getBoundingClientRect计算,所以await nextTick();* 2.因为支持轮播,可能存在两个activitydom都处于选中状态,因此需要用for循环找到一个距离屏幕中心最近的item* inShowPoster: 安卓端点击视频跳转再次回到h5时候,封面会闪一下(不会暂停1s后播放),次case不隐藏封面*/const handleVideoPlay = (timeOut = 1000, isInitPoster = true) => {if (isInLiveRoom()) {return;}// fix 快速切换导致业务卡顿clearTimeout(setTimeoutId.value);videoStop(isInitPoster);setTimeoutId.value = setTimeout(() => {try {videoStop(isInitPoster);// console.error(' settimeout transform------', document.querySelector('.spu-swiper-inner').style.transform);if (isVisibility.value && isVisibilityVideo.value ) {const targetDom = getCurrentVideo();// play调用失败或者多次调用触发异常(The operation was aborted)targetDom?.play()?.catch(e => {console.log(e);});}} catch (e) {console.log('error', e);}}, timeOut);};const getCurrentVideo = () => {const activeDom = document.querySelectorAll('.swiper-panel-item.is-active video');const target = window.innerWidth / 2;let targetDom = activeDom?.[0] as HTMLVideoElement;let distance = Number.MAX_VALUE;for (const item of activeDom) {const left = item.getBoundingClientRect().left;if (Math.abs(left - target) < distance) {distance = Math.abs(left - target);targetDom = item as HTMLVideoElement;}}return targetDom;};const initPoster = () => {//const domPoster = document.querySelectorAll<HTMLElement>('.item-video-living.videoPoster');domPoster.forEach(item => {item && (item.style.opacity = '1');});};const toWorkVideoPageFn = (eventId: number, photoId: string, userId: string, eventStatus: number) => {if (isInLiveRoom()) {return;}sendClick({action: 'BLIND_DATE_VENUE_VIDEO_CARD',params: {author_id: userId,id: eventId,status: eventStatus,tab_name: props.tabPhotoList[props.currentTabIndex].tabTitle,video_id: photoId,},});// videoStop();toWorkVideoPage(photoId, '');};const handleBook = throttle((isCancel:boolean, eventId: number, userId: number, photoId: string) => {console.log('handleBook', isCancel, eventId, userId, photoId);if (!props.bookStatusLoading) { // 网络请求阶段bookStatusLoading为trueemit('handleBook', isCancel, eventId, userId, photoId);}}, 1000);const handleEnroll = throttle((isCancel:boolean, eventId: number, userId: number, photoId: string) => {console.log('handleEnroll', isCancel, eventId, userId, photoId);emit('handleEnroll', isCancel, eventId, userId, photoId);}, 1000);const handleOnline = (userId: number) => {// videoStop();const { authorId } = query;if ( String(authorId) === String(userId)) {showToast('已经在当前直播间');return;}if (userId) {toLiveRoomByUserId(String(userId), {liveSource: 'BLIND_DATE_CNY_PAGE_BUTTON',sourceType: 269,});}};const openProfileFn = (userId: number) => {// videoStop();openProfile(String(userId));};const onVideoWaiting = (id: string) => {// loadingconst domLoading = document.querySelectorAll<HTMLElement>(`.${id}`);domLoading.forEach(item => {item && (item.style.opacity = '1');});console.log('onVideoWaiting', id);};// 性能考虑,不采用display,用opacityconst onVideoPlaying = (id: string) => {try {// 关闭loadingconst domLoading = document.querySelectorAll<HTMLElement>(`.${id}`);domLoading.forEach(item => {item && (item.style.opacity = '0');});// 关闭posterconst domPoster = document.querySelectorAll<HTMLElement>(`.${id}_poster`);domPoster.forEach(item => {item && (item.style.opacity = '0');});const video = getCurrentVideo();video && (video.muted = false);} catch (e) {console.log('onVideoPlaying', e);}};const onVideoOtherEvent = throttle((name: string, id: string) => {if (name === 'timeupdate') {const dom = getCurrentVideo();if (dom?.readyState < 4 ) {onVideoWaiting(id);} else {onVideoPlaying(id);}}}, 1000);// 不是低端机 && 不在直播间const isShowVideo = () => {return !isLowDeviceBiz() && !isInLiveRoom();};const oneventvideo = (name, id) => {// const dom = getCurrentVideo();// console.log('name', name, id, dom.readyState);if (name === 'canplaythrough') {try {// 关闭loadingconst domLoading = document.querySelectorAll<HTMLElement>(`.${id}`);domLoading.forEach(item => {item && (item.style.opacity = '0');});} catch (e) {console.log('onVideoPlaying', e);}}};// 当前dom节点改变:loop模式下,边界场景下视觉上未切换,实际已切换,此时会出现有声音,无画面情况,此case需要重新播放视频const onDomChangePanel = (index, lastIndex) => {handleVideoPlay();};const getTextInfo = (title: string) => {return title.indexOf('「') === 0;};return {swiperPanelRef,currentSwiperPanelIndex,onSwiperTabsChange,onSwiperPanelChange,toWorkVideoPageFn,eventListByIndex,tabsByTabPhotoList,handleBook,handleEnroll,handleOnline,openProfileFn,isInLiveRoom,BOOKSTATUS,ENROLLSTATUS,EVENTSTATUS,onVideoWaiting,onVideoPlaying,loadingsvg,isShowVideo,swiperPannelItemRef,oneventvideo,onVideoOtherEvent,onDomChangePanel,getTextInfo,laterRender,};},
});
</script>

相关文章:

Vue3学习(六)Vue3 + ts几种写法

前言 官网提到组合式api和选项式api 选项式api其实就是vue2的写法&#xff0c;组合式api是vue3的新写法&#xff08;组合式api可以在script中使用setup&#xff08;&#xff09;也可以使用<script setup>&#xff0c;<script setup>是setup&#xff08;&#xff…...

【前端】ES6:Proxy代理和Reflect对象

文章目录 1 Proxy代理1.1 get方法1.2 set方法1.3 has方法1.4 this问题 2 Reflect对象2.1 代替Object的某些方法2.2 修改某些Object方法返回结果2.3 命令式变为函数行为2.4 配合Proxy 1 Proxy代理 Proxy如其名&#xff0c;它的作用是在对象和和对象的属性值之间设置一个代理&am…...

基于微信开发助手企鹅音乐微信小程序的设计与实现(源码+文档+讲解)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…...

学习Spring Boot,应该从哪里开始学起

文章目录 前言1. Java基础2. Spring框架基础3. Spring Boot入门4. 搭建Spring Boot项目5. 编写RESTful API6. 数据库操作7. 安全性和测试8. 部署和运维9. 实践和项目总结前言 学习Spring Boot,应该从哪里开始学起 学习Spring Boot,你可以从以下几个步骤开始学起: 1. Java基…...

【JavaEE初阶】深入解析死锁的产生和避免以及内存不可见问题

前言&#xff1a; &#x1f308;上期博客&#xff1a;【后端开发】JavaEE初阶—线程安全问题与加锁原理&#xff08;超详解&#xff09;-CSDN博客 &#x1f525;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondlctrl-CSDN博客 ⭐️小编会在后端开发的学习中不断更新~~~ &#…...

企微群管理软件:构建高效社群运营的新引擎

在数字化营销日益盛行的今天&#xff0c;企业微信&#xff08;简称“企微”&#xff09;群作为企业与用户直接互动的重要平台&#xff0c;其管理与运营效率直接关系到企业的品牌形象、用户满意度及市场影响力。企微群管理软件&#xff0c;作为专为企微社群设计的高效管理工具&a…...

CORE 中间件、wwwroot

ASP.NET Core中间件组件是被组装到应用程序管道中以处理HTTP请求和响应的软件组件&#xff08;从技术上来说&#xff0c;组件只是C&#xff03;类&#xff09;。 ASP.NET Core应用程序中的每个中间件组件都执行以下任务。 选择是否将 HTTP 请求传递给管道中的下一个组件。这可…...

SpringBoot 与 Maven 快速上手指南

SpringBoot 与 Maven 快速上手指南 在Java开发领域&#xff0c;Spring Boot和Maven是两个极其重要的工具&#xff0c;它们极大地简化了企业级应用的开发和构建过程。Spring Boot通过自动配置和起步依赖等特性&#xff0c;让开发者能够快速搭建起一个Spring应用&#xff1b;而M…...

大觅网之自动化部署(Automated Deployment of Da Mi Network)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 本人主要分享计算机核心技…...

【C++】入门基础知识-1

&#x1f36c;个人主页&#xff1a;Yanni.— &#x1f308;数据结构&#xff1a;Data Structure.​​​​​​ &#x1f382;C语言笔记&#xff1a;C Language Notes &#x1f3c0;OJ题分享&#xff1a; Topic Sharing 目录 前言&#xff1a; C关键字 命名空间 命名空间介…...

Redis一些简单通用命令认识常用数据类型和编码方式认识Redis单线程模型

通用命令 get() / set() 这是Redis中两个最为核心的命令。 set插入 这里的key 和 value都是字符串&#xff0c;我们可以加双引号 或者单引号&#xff0c;或者不加。 get查找 如果查询的key值不存在&#xff0c;那么会返回一个 nil &#xff0c;也就是代表空 在Redis中命令…...

使用电子模拟器 Wokwi 运行 ESP32 示例(Arduino IDE、VSCode、ESP32C3)

文章目录 Wokwi 简介安装客户端&#xff08;Mac/Linux&#xff09;创建 Token Arduino IDEVSCode 配置安装 wokwi 插件打开编译后目录 ESP32C3 示例Arduino IDE创建模拟器运行模拟器 Wokwi 简介 Wokwi 是一款在线电子模拟器。您可以使用它来模拟 Arduino、ESP32、STM32 以及许…...

C嘎嘎入门篇:类和对象(1)

前言&#xff1a; 小编在之前讲述了C的部分入门基础&#xff0c;读者朋友一定要掌握好那些&#xff0c;因为C的学习和C有点不同&#xff0c;C的知识都是比较连贯的&#xff0c;所以我们学好了前面才可以学习后面的内容&#xff0c;本篇文章小编将会讲述C真正的入门篇&#xff1…...

tomcat服务搭建部署ujcms网站

tomcat服务搭建部署ujcms网站 关闭selinux和防火墙 setenforce 0 && systemctl stop firewalld安装java环境 #卸载原有java8环境 yum remove java*#上传java软件包&#xff0c;并解压缩 tar -xf openjdk-11.0.1_linux-x64_bin.tar.gz && mv jdk-11.0.1 jdk11…...

unity_Occlusion_Culling遮挡剔除学习

unity_Occlusion_Culling遮挡剔除学习 文档&#xff1a; https://docs.unity.cn/cn/2019.4/Manual/occlusion-culling-getting-started.html没彻底搞明白&#xff0c;但是会用&#xff0c;虽然也不熟练 设置遮挡剔除 打开遮挡剔除面板 设置场景物体。设置为静态 设置场景 烘…...

vue初学随笔

Vue基础 Vue基本概念 Vue是什么 Vue是一个渐进式的JavaScript框架&#xff0c;它基于标准 HTML、CSS 和 JavaScript 构建&#xff0c;并提供了一套声明式的、组件化的编程模型&#xff0c;帮助你高效地开发用户界面。 渐进式&#xff1a;各个特性可以根据项目需要逐渐引入和…...

IDEA Dependency Analyzer 分析 maven 项目包的依赖

一、场景分析 javax.validation 是我们 SpringMVC 常用的数据校验框架。但是 javax.validation 是一个规范&#xff08;Java Bean Validation&#xff0c;简称 JSR 380&#xff09;&#xff0c;它并没有具体的实现&#xff0c;它的常用实现&#xff0c;是hibernate-validator。…...

微信小程序 - 最新详细安装使用 Vant weapp UI 框架环境搭建详细教程

前言 自从 2024 年开始,小程序做了很多改变和升级, 导致网上很多搭建教程文章的教程失效了,本文来做最新的教程。 第一步 为了更贴合新手,我这里创建了一个纯净无任何业务代码的小程序项目。...

【C语言】手把手带你拿捏指针(完)(指针笔试、面试题解析)

文章目录 一、sizeof和strlen的对⽐1.sizeof2.strlen3.sizeof与strlen对比 二、数组和指针笔试解析1.一维数组2.字符、字符串数组和字符指针代码1代码2代码3代码4代码5代码6 3.二维数组4.总结 三、指针运算笔试题解析代码1代码2代码3代码4代码5代码6 一、sizeof和strlen的对⽐ …...

Vue中input框自动聚焦

在Vue中input自动聚焦的思路&#xff1a; 给需要聚焦的input设置ref <el-inputv-model"loginForm.username"ref"userNameInput"name"username"type"text"auto-complete"on"placeholder"username"keyup.enter.…...

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…...

HTML 语义化

目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案&#xff1a; 语义化标签&#xff1a; <header>&#xff1a;页头<nav>&#xff1a;导航<main>&#xff1a;主要内容<article>&#x…...

React第五十七节 Router中RouterProvider使用详解及注意事项

前言 在 React Router v6.4 中&#xff0c;RouterProvider 是一个核心组件&#xff0c;用于提供基于数据路由&#xff08;data routers&#xff09;的新型路由方案。 它替代了传统的 <BrowserRouter>&#xff0c;支持更强大的数据加载和操作功能&#xff08;如 loader 和…...

AtCoder 第409​场初级竞赛 A~E题解

A Conflict 【题目链接】 原题链接&#xff1a;A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串&#xff0c;只有在同时为 o 时输出 Yes 并结束程序&#xff0c;否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

Robots.txt 文件

什么是robots.txt&#xff1f; robots.txt 是一个位于网站根目录下的文本文件&#xff08;如&#xff1a;https://example.com/robots.txt&#xff09;&#xff0c;它用于指导网络爬虫&#xff08;如搜索引擎的蜘蛛程序&#xff09;如何抓取该网站的内容。这个文件遵循 Robots…...

企业如何增强终端安全?

在数字化转型加速的今天&#xff0c;企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机&#xff0c;到工厂里的物联网设备、智能传感器&#xff0c;这些终端构成了企业与外部世界连接的 “神经末梢”。然而&#xff0c;随着远程办公的常态化和设备接入的爆炸式…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比

在机器学习的回归分析中&#xff0c;损失函数的选择对模型性能具有决定性影响。均方误差&#xff08;MSE&#xff09;作为经典的损失函数&#xff0c;在处理干净数据时表现优异&#xff0c;但在面对包含异常值的噪声数据时&#xff0c;其对大误差的二次惩罚机制往往导致模型参数…...

什么是VR全景技术

VR全景技术&#xff0c;全称为虚拟现实全景技术&#xff0c;是通过计算机图像模拟生成三维空间中的虚拟世界&#xff0c;使用户能够在该虚拟世界中进行全方位、无死角的观察和交互的技术。VR全景技术模拟人在真实空间中的视觉体验&#xff0c;结合图文、3D、音视频等多媒体元素…...

消防一体化安全管控平台:构建消防“一张图”和APP统一管理

在城市的某个角落&#xff0c;一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延&#xff0c;滚滚浓烟弥漫开来&#xff0c;周围群众的生命财产安全受到严重威胁。就在这千钧一发之际&#xff0c;消防救援队伍迅速行动&#xff0c;而豪越科技消防一体化安全管控平台构建的消防“…...