refactor: solve the mute problem

This commit is contained in:
zyronon 2024-04-27 02:31:27 +08:00
parent 1b6001f6f6
commit 7c5bdc9883
30 changed files with 1016 additions and 629 deletions

3
env.d.ts vendored
View File

@ -1,10 +1,13 @@
/// <reference types="vite/client" /> /// <reference types="vite/client" />
/// <reference types="unplugin-vue-macros/macros-global" />
declare const LATEST_COMMIT_HASH: string declare const LATEST_COMMIT_HASH: string
declare global { declare global {
interface Window { interface Window {
isMoved: boolean isMoved: boolean
isMuted: boolean
showMutedNotice: boolean
} }
interface Navigator { interface Navigator {

View File

@ -58,7 +58,7 @@
"prettier": "^3.2.5", "prettier": "^3.2.5",
"rollup-plugin-visualizer": "^5.9.2", "rollup-plugin-visualizer": "^5.9.2",
"typescript": "5.3.3", "typescript": "5.3.3",
"unplugin-vue-define-options": "^1.4.1", "unplugin-vue-macros": "^2.9.1",
"vite": "^5.1.7", "vite": "^5.1.7",
"vite-plugin-cdn-import": "0.3.5", "vite-plugin-cdn-import": "0.3.5",
"vite-plugin-commonjs": "^0.10.1", "vite-plugin-commonjs": "^0.10.1",

View File

@ -109,9 +109,9 @@ devDependencies:
typescript: typescript:
specifier: 5.3.3 specifier: 5.3.3
version: 5.3.3 version: 5.3.3
unplugin-vue-define-options: unplugin-vue-macros:
specifier: ^1.4.1 specifier: ^2.9.1
version: 1.4.2(rollup@2.79.1)(vue@3.4.21) version: 2.9.1(rollup@2.79.1)(typescript@5.3.3)(vite@5.1.7)(vue@3.4.21)
vite: vite:
specifier: ^5.1.7 specifier: ^5.1.7
version: 5.1.7(@types/node@20.12.4)(less@4.1.3) version: 5.1.7(@types/node@20.12.4)(less@4.1.3)
@ -140,6 +140,10 @@ packages:
'@jridgewell/trace-mapping': 0.3.20 '@jridgewell/trace-mapping': 0.3.20
dev: true dev: true
/@antfu/utils@0.7.7:
resolution: {integrity: sha512-gFPqTG7otEJ8uP6wrhDv6mqwGWYZKNvAcCq6u9hOj0c+IKCEsY4L1oC9trPq2SaWIzAfHvqfBDxF591JkMf+kg==}
dev: true
/@babel/code-frame@7.22.13: /@babel/code-frame@7.22.13:
resolution: {integrity: sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==} resolution: {integrity: sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
@ -401,6 +405,14 @@ packages:
'@babel/types': 7.24.0 '@babel/types': 7.24.0
dev: true dev: true
/@babel/parser@7.24.4:
resolution: {integrity: sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==}
engines: {node: '>=6.0.0'}
hasBin: true
dependencies:
'@babel/types': 7.24.0
dev: true
/@babel/plugin-syntax-jsx@7.22.5(@babel/core@7.24.3): /@babel/plugin-syntax-jsx@7.22.5(@babel/core@7.24.3):
resolution: {integrity: sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==} resolution: {integrity: sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
@ -1034,6 +1046,10 @@ packages:
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
dev: true dev: true
/@polka/url@1.0.0-next.25:
resolution: {integrity: sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==}
dev: true
/@rollup/plugin-commonjs@25.0.7(rollup@2.79.1): /@rollup/plugin-commonjs@25.0.7(rollup@2.79.1):
resolution: {integrity: sha512-nEvcR+LRjEjsaSsc4x3XZfCCvZIaSMenZu/OiwOKGN2UhQpAYI7ru7czFvyWbErlpoGjnSX3D5Ch5FcMA3kRWQ==} resolution: {integrity: sha512-nEvcR+LRjEjsaSsc4x3XZfCCvZIaSMenZu/OiwOKGN2UhQpAYI7ru7czFvyWbErlpoGjnSX3D5Ch5FcMA3kRWQ==}
engines: {node: '>=14.0.0'} engines: {node: '>=14.0.0'}
@ -1426,8 +1442,54 @@ packages:
path-browserify: r2.cnpmjs.org/path-browserify@1.0.1 path-browserify: r2.cnpmjs.org/path-browserify@1.0.1
dev: true dev: true
/@vue-macros/common@1.10.1(rollup@2.79.1)(vue@3.4.21): /@vue-macros/api@0.9.5(rollup@2.79.1)(vue@3.4.21):
resolution: {integrity: sha512-uftSpfwdwitcQT2lM8aVxcfe5rKQBzC9jMrtJM5sG4hEuFyfIvnJihpPpnaWxY+X4p64k+YYXtBFv+1O5Bq3dg==} resolution: {integrity: sha512-ybaOuoB3HIMJsH2Cj3903cf6YM65UOl7U1Vbq4ZH4drDLymlgIqEri5ufhq76XXn6mi6xx4cZ3JUqo5VwteHkQ==}
engines: {node: '>=16.14.0'}
dependencies:
'@babel/types': 7.24.0
'@vue-macros/common': 1.10.2(rollup@2.79.1)(vue@3.4.21)
resolve.exports: 2.0.2
transitivePeerDependencies:
- rollup
- vue
dev: true
/@vue-macros/better-define@1.7.5(rollup@2.79.1)(vue@3.4.21):
resolution: {integrity: sha512-XKByxQ+867gujPUKfRWnC5ajBfFChX2bgqVGK5fSVr+EAbkxZmMAa6KhxkGTWSn0R0T7TJIULXGlRj0TV4j6EQ==}
engines: {node: '>=16.14.0'}
dependencies:
'@vue-macros/api': 0.9.5(rollup@2.79.1)(vue@3.4.21)
'@vue-macros/common': 1.10.2(rollup@2.79.1)(vue@3.4.21)
unplugin: 1.10.1
transitivePeerDependencies:
- rollup
- vue
dev: true
/@vue-macros/boolean-prop@0.3.3(rollup@2.79.1)(vue@3.4.21):
resolution: {integrity: sha512-FAHBAXtI0qcoLIfq5AAfHokz191nC/ciYcqbBUygvI4DEPINOnrb/QN0M56LkszJUl7girx/JxUOixUDHozUyA==}
engines: {node: '>=16.14.0'}
dependencies:
'@vue-macros/common': 1.10.2(rollup@2.79.1)(vue@3.4.21)
'@vue/compiler-core': 3.4.21
transitivePeerDependencies:
- rollup
- vue
dev: true
/@vue-macros/chain-call@0.2.3(rollup@2.79.1)(vue@3.4.21):
resolution: {integrity: sha512-THXfqdpqcdcz0ugCW3AfTcAqa6vXeHHCgKsDc9wvdITjsxIwiXmGIiA22rNZxdXGnXVSY+v18VdzChv/dbZ0RA==}
engines: {node: '>=16.14.0'}
dependencies:
'@vue-macros/common': 1.10.2(rollup@2.79.1)(vue@3.4.21)
unplugin: 1.10.1
transitivePeerDependencies:
- rollup
- vue
dev: true
/@vue-macros/common@1.10.2(rollup@2.79.1)(vue@3.4.21):
resolution: {integrity: sha512-WC66NPVh2mJWqm4L0l/u/cOqm4pNOIwVdMGnDYAH2rHcOWy5x68GkhpkYTBu1+xwCSeHWOQn1TCGGbD+98fFpA==}
engines: {node: '>=16.14.0'} engines: {node: '>=16.14.0'}
peerDependencies: peerDependencies:
vue: ^2.7.0 || ^3.2.25 vue: ^2.7.0 || ^3.2.25
@ -1438,7 +1500,7 @@ packages:
'@babel/types': 7.24.0 '@babel/types': 7.24.0
'@rollup/pluginutils': 5.1.0(rollup@2.79.1) '@rollup/pluginutils': 5.1.0(rollup@2.79.1)
'@vue/compiler-sfc': 3.4.21 '@vue/compiler-sfc': 3.4.21
ast-kit: 0.11.3(rollup@2.79.1) ast-kit: 0.12.1
local-pkg: 0.5.0 local-pkg: 0.5.0
magic-string-ast: 0.3.0 magic-string-ast: 0.3.0
vue: 3.4.21(typescript@5.3.3) vue: 3.4.21(typescript@5.3.3)
@ -1446,6 +1508,280 @@ packages:
- rollup - rollup
dev: true dev: true
/@vue-macros/define-emit@0.2.5(rollup@2.79.1)(vue@3.4.21):
resolution: {integrity: sha512-QsmzVLkxYdPaJr5hi/S3K9hr9hQ8Q55SIMmDiUsYABJpmSzczGv6HcJKkvP3k1J5UHxGx9rkytTv5KKxEaAYyw==}
engines: {node: '>=16.14.0'}
peerDependencies:
vue: ^2.7.0 || ^3.2.25
dependencies:
'@vue-macros/api': 0.9.5(rollup@2.79.1)(vue@3.4.21)
'@vue-macros/common': 1.10.2(rollup@2.79.1)(vue@3.4.21)
unplugin: 1.10.1
vue: 3.4.21(typescript@5.3.3)
transitivePeerDependencies:
- rollup
dev: true
/@vue-macros/define-models@1.2.3(rollup@2.79.1)(vue@3.4.21):
resolution: {integrity: sha512-yeAcE3W9wZG1tePzY6+Ldpzj+zZJs7YZcQGLYxoXiEOii5Koh5VLaLm+qEQaXToMwjV/904YaJHKPH7Gsi0Tfg==}
engines: {node: '>=16.14.0'}
peerDependencies:
'@vueuse/core': '>=9.0.0'
peerDependenciesMeta:
'@vueuse/core':
optional: true
dependencies:
'@vue-macros/common': 1.10.2(rollup@2.79.1)(vue@3.4.21)
ast-walker-scope: 0.6.1
unplugin: 1.10.1
transitivePeerDependencies:
- rollup
- vue
dev: true
/@vue-macros/define-prop@0.3.5(rollup@2.79.1)(vue@3.4.21):
resolution: {integrity: sha512-1eTmUQh5Oz2UldFPlsK6CuNw8N+zIUGIQB8SxgN8m0V0xKvyJpjJrSWs0WfFBivCl+gxYJUZ7ZjiwTuCc9Z7kA==}
engines: {node: '>=16.14.0'}
peerDependencies:
vue: ^2.7.0 || ^3.2.25
dependencies:
'@vue-macros/api': 0.9.5(rollup@2.79.1)(vue@3.4.21)
'@vue-macros/common': 1.10.2(rollup@2.79.1)(vue@3.4.21)
unplugin: 1.10.1
vue: 3.4.21(typescript@5.3.3)
transitivePeerDependencies:
- rollup
dev: true
/@vue-macros/define-props-refs@1.2.3(rollup@2.79.1)(vue@3.4.21):
resolution: {integrity: sha512-7nZKCZhr5CsQ93wBHauvwO3/NxYe6+IP2mvKYBxAlq9oADGptZbrK6jarUpBE2V0tTyq0AynfAOG6GueGxvJEg==}
engines: {node: '>=16.14.0'}
peerDependencies:
vue: ^2.7.0 || ^3.2.25
dependencies:
'@vue-macros/common': 1.10.2(rollup@2.79.1)(vue@3.4.21)
unplugin: 1.10.1
vue: 3.4.21(typescript@5.3.3)
transitivePeerDependencies:
- rollup
dev: true
/@vue-macros/define-props@2.0.4(@vue-macros/reactivity-transform@0.4.4)(rollup@2.79.1)(vue@3.4.21):
resolution: {integrity: sha512-opifxLT9yF+A/bEfEpuFxNcAMPEmnPv/ewlCDmOH8VX+CBnlWbDqY0n0LcimPGRTYkRDAkNBHRRQulxNfRXNpw==}
engines: {node: '>=16.14.0'}
peerDependencies:
'@vue-macros/reactivity-transform': ^0.4.4
vue: ^2.7.0 || ^3.2.25
dependencies:
'@vue-macros/common': 1.10.2(rollup@2.79.1)(vue@3.4.21)
'@vue-macros/reactivity-transform': 0.4.4(rollup@2.79.1)(vue@3.4.21)
unplugin: 1.10.1
vue: 3.4.21(typescript@5.3.3)
transitivePeerDependencies:
- rollup
dev: true
/@vue-macros/define-render@1.5.3(rollup@2.79.1)(vue@3.4.21):
resolution: {integrity: sha512-phdDLTHvZi0AxK2kEJ1Gt6TDMH9vHQib+eU5k+GXV/WPz43n+Cp4a9tq5Mpkc1rojc796w/+O1bE6jE0fyGxjw==}
engines: {node: '>=16.14.0'}
peerDependencies:
vue: ^2.7.0 || ^3.0.0
dependencies:
'@vue-macros/common': 1.10.2(rollup@2.79.1)(vue@3.4.21)
unplugin: 1.10.1
vue: 3.4.21(typescript@5.3.3)
transitivePeerDependencies:
- rollup
dev: true
/@vue-macros/define-slots@1.1.3(rollup@2.79.1)(vue@3.4.21):
resolution: {integrity: sha512-b8lhEOMS8kl3x2ihOIrfz9xjCCUdBKliLzs5mqdQlaLRVRSxHxXVnBq1Ek7dCIxrc2Mp9VyvBn7E4Q4i0StpmQ==}
engines: {node: '>=16.14.0'}
peerDependencies:
vue: ^2.7.0 || ^3.0.0
dependencies:
'@vue-macros/common': 1.10.2(rollup@2.79.1)(vue@3.4.21)
unplugin: 1.10.1
vue: 3.4.21(typescript@5.3.3)
transitivePeerDependencies:
- rollup
dev: true
/@vue-macros/devtools@0.2.0(typescript@5.3.3)(vite@5.1.7):
resolution: {integrity: sha512-jHjvY1bFgQLe/2+5pBOG4fgmL5MPhsqQDj7Barhj8YN+Oe7U2hBImvfAyOGpqd2uucLOWQTP1cWrp3q9b1svsg==}
engines: {node: '>=16.14.0'}
peerDependencies:
vite: ^4.0.0 || ^5.0.0-0
peerDependenciesMeta:
vite:
optional: true
dependencies:
sirv: 2.0.4
vite: 5.1.7(@types/node@20.12.4)(less@4.1.3)
vue: 3.4.21(typescript@5.3.3)
transitivePeerDependencies:
- typescript
dev: true
/@vue-macros/export-expose@0.1.3(rollup@2.79.1)(vue@3.4.21):
resolution: {integrity: sha512-K2cFoVXqzLjVe0kpOKS+QlLdI3P9+zjDDj8LQQreaWTBuAYQIyEIIjEt5aw5MImLrmmoSqbWNFf/iiZNJrDl1w==}
engines: {node: '>=16.14.0'}
peerDependencies:
vue: ^2.7.0 || ^3.2.25
dependencies:
'@vue-macros/common': 1.10.2(rollup@2.79.1)(vue@3.4.21)
'@vue/compiler-sfc': 3.4.21
unplugin: 1.10.1
vue: 3.4.21(typescript@5.3.3)
transitivePeerDependencies:
- rollup
dev: true
/@vue-macros/export-props@0.4.3(rollup@2.79.1)(vue@3.4.21):
resolution: {integrity: sha512-UhIZFb9lwuZfuOdPTUIRs4D74YGdZjBKpUZNjDQG1P2VbIsqXZ5nwKo1nPH4XYoAzXmJcpGqP+gwemCITpTewA==}
engines: {node: '>=16.14.0'}
peerDependencies:
vue: ^2.7.0 || ^3.2.25
dependencies:
'@vue-macros/common': 1.10.2(rollup@2.79.1)(vue@3.4.21)
unplugin: 1.10.1
vue: 3.4.21(typescript@5.3.3)
transitivePeerDependencies:
- rollup
dev: true
/@vue-macros/export-render@0.2.3(rollup@2.79.1)(vue@3.4.21):
resolution: {integrity: sha512-0iQnVNxMuTjfmF1N6mWR+21dClHwJRd/WJXwGhjABOBX8g90JM7kj0pXvhdpQZ4CBiDTHrNMl0s4C0c3tjwjnw==}
engines: {node: '>=16.14.0'}
peerDependencies:
vue: ^2.7.0 || ^3.2.25
dependencies:
'@vue-macros/common': 1.10.2(rollup@2.79.1)(vue@3.4.21)
'@vue/compiler-sfc': 3.4.21
unplugin: 1.10.1
vue: 3.4.21(typescript@5.3.3)
transitivePeerDependencies:
- rollup
dev: true
/@vue-macros/hoist-static@1.5.3(rollup@2.79.1)(vue@3.4.21):
resolution: {integrity: sha512-17IcyI2EnMRgC7YtDr1PpjI4inca7jqSeRJZVHemU9oYZxYes1lIh5A/x18vVh1+ZP2xFFHjJr69AEhPzedk1g==}
engines: {node: '>=16.14.0'}
dependencies:
'@vue-macros/common': 1.10.2(rollup@2.79.1)(vue@3.4.21)
unplugin: 1.10.1
transitivePeerDependencies:
- rollup
- vue
dev: true
/@vue-macros/jsx-directive@0.8.12(rollup@2.79.1)(vue@3.4.21):
resolution: {integrity: sha512-+50MSQfcG5d+Sv2AVi3DAOSxcVmEuxdpghZzismg1dYWPikbFu7f4RH6wvexFnCjKoYKDw/E02DBup5wLEGJSA==}
engines: {node: '>=16.14.0'}
dependencies:
'@vue-macros/common': 1.10.2(rollup@2.79.1)(vue@3.4.21)
unplugin: 1.10.1
transitivePeerDependencies:
- rollup
- vue
dev: true
/@vue-macros/named-template@0.4.3(rollup@2.79.1)(vue@3.4.21):
resolution: {integrity: sha512-d3PcaVE/aSF7sHOJrbQlNZaODQYpTidbSk4DK6i/ucgYBD5eOx3dwr/37gtmjLu4vXM1l8igouaSLhWVf3bPsg==}
engines: {node: '>=16.14.0'}
dependencies:
'@vue-macros/common': 1.10.2(rollup@2.79.1)(vue@3.4.21)
'@vue/compiler-dom': 3.4.21
unplugin: 1.10.1
transitivePeerDependencies:
- rollup
- vue
dev: true
/@vue-macros/reactivity-transform@0.4.4(rollup@2.79.1)(vue@3.4.21):
resolution: {integrity: sha512-Yn22Ls+KAJzjwdjrjwaDkjx+lxSXlk4ev+s0hD9biTpjaf1Sv7AKYq5381TGZIeDadklkhHzYwQWueROqvpG6w==}
engines: {node: '>=16.14.0'}
peerDependencies:
vue: ^2.7.0 || ^3.2.25
dependencies:
'@babel/parser': 7.24.4
'@vue-macros/common': 1.10.2(rollup@2.79.1)(vue@3.4.21)
'@vue/compiler-core': 3.4.21
'@vue/shared': 3.4.21
magic-string: 0.30.10
unplugin: 1.10.1
vue: 3.4.21(typescript@5.3.3)
transitivePeerDependencies:
- rollup
dev: true
/@vue-macros/setup-block@0.3.3(rollup@2.79.1)(vue@3.4.21):
resolution: {integrity: sha512-06UnxX8wDKJcJHvSgnxi7aJo2jdGvbeAur+aSLcmYgTfNUwRtuC2KmJKQohjos24USpQEYyGqMKPYuxkdoQ+Wg==}
engines: {node: '>=16.14.0'}
dependencies:
'@vue-macros/common': 1.10.2(rollup@2.79.1)(vue@3.4.21)
'@vue/compiler-dom': 3.4.21
unplugin: 1.10.1
transitivePeerDependencies:
- rollup
- vue
dev: true
/@vue-macros/setup-component@0.17.3(rollup@2.79.1)(vue@3.4.21):
resolution: {integrity: sha512-zBZCPBhVh5gZMKQKE/K+SJYiXjIoK+Hc/FxhHkijZd4njx2a3CtpW5BX3bDr0498E78+f7vlqcPHaE9IRNUGsQ==}
engines: {node: '>=16.14.0'}
dependencies:
'@vue-macros/common': 1.10.2(rollup@2.79.1)(vue@3.4.21)
unplugin: 1.10.1
transitivePeerDependencies:
- rollup
- vue
dev: true
/@vue-macros/setup-sfc@0.17.3(rollup@2.79.1)(vue@3.4.21):
resolution: {integrity: sha512-6D6UMLi1qdgpBhgwRo2VevVpNlo9QtnzsOIag4seAl3zEI1jB5KfOoUWl8yHZ5MUGfs5jSPzOhlQfEzefrgO4g==}
engines: {node: '>=16.14.0'}
dependencies:
'@vue-macros/common': 1.10.2(rollup@2.79.1)(vue@3.4.21)
unplugin: 1.10.1
transitivePeerDependencies:
- rollup
- vue
dev: true
/@vue-macros/short-bind@0.2.3(rollup@2.79.1)(vue@3.4.21):
resolution: {integrity: sha512-3QwHQQDVNpsWh36/q4sB5QmGGedwIZUmL2rvQ8YQD6EA455samG0r2zB9Q6Z7DA8+qk6TjpmkvltubDY9TWtEQ==}
engines: {node: '>=16.14.0'}
dependencies:
'@vue-macros/common': 1.10.2(rollup@2.79.1)(vue@3.4.21)
'@vue/compiler-core': 3.4.21
transitivePeerDependencies:
- rollup
- vue
dev: true
/@vue-macros/short-emits@1.5.3(rollup@2.79.1)(vue@3.4.21):
resolution: {integrity: sha512-DTzJ1Bj2cwJK9kCRWw9VUeNjuAnmyXoTC05J76lGBa7Ftr/04UZM31h8/NyTKqG/oXHBnNa4X8kGy9A7kRwG9g==}
engines: {node: '>=16.14.0'}
dependencies:
'@vue-macros/common': 1.10.2(rollup@2.79.1)(vue@3.4.21)
unplugin: 1.10.1
transitivePeerDependencies:
- rollup
- vue
dev: true
/@vue-macros/short-vmodel@1.4.3(rollup@2.79.1)(vue@3.4.21):
resolution: {integrity: sha512-ZQph4GuKl4kEXtzGDddqSgfykAZ9cT7tu14G4K3ZGJ8wsLmhuLGWfFL596UVg5zfVyMWuC/SbTmR8UEp/eMPJA==}
engines: {node: '>=16.14.0'}
dependencies:
'@vue-macros/common': 1.10.2(rollup@2.79.1)(vue@3.4.21)
'@vue/compiler-core': 3.4.21
transitivePeerDependencies:
- rollup
- vue
dev: true
/@vue/babel-helper-vue-transform-on@1.1.5: /@vue/babel-helper-vue-transform-on@1.1.5:
resolution: {integrity: sha512-SgUymFpMoAyWeYWLAY+MkCK3QEROsiUnfaw5zxOVD/M64KQs8D/4oK6Q5omVA2hnvEOE0SCkH2TZxs/jnnUj7w==} resolution: {integrity: sha512-SgUymFpMoAyWeYWLAY+MkCK3QEROsiUnfaw5zxOVD/M64KQs8D/4oK6Q5omVA2hnvEOE0SCkH2TZxs/jnnUj7w==}
dev: true dev: true
@ -1679,36 +2015,20 @@ packages:
engines: {node: '>=8'} engines: {node: '>=8'}
dev: true dev: true
/ast-kit@0.11.3(rollup@2.79.1): /ast-kit@0.12.1:
resolution: {integrity: sha512-qdwwKEhckRk0XE22/xDdmU3v/60E8Edu4qFhgTLIhGGDs/PAJwLw9pQn8Rj99PitlbBZbYpx0k/lbir4kg0SuA==} resolution: {integrity: sha512-O+33g7x6irsESUcd47KdfWUrS2F6aGp9KeVJFGj0YjIznfXpBxVGjA0w+y/1OKqX4mFOfmZ9Xpf1ixPT4n9xxw==}
engines: {node: '>=16.14.0'} engines: {node: '>=16.14.0'}
dependencies: dependencies:
'@babel/parser': 7.24.0 '@babel/parser': 7.24.4
'@rollup/pluginutils': 5.1.0(rollup@2.79.1)
pathe: 1.1.2 pathe: 1.1.2
transitivePeerDependencies:
- rollup
dev: true dev: true
/ast-kit@0.9.5(rollup@2.79.1): /ast-walker-scope@0.6.1:
resolution: {integrity: sha512-kbL7ERlqjXubdDd+szuwdlQ1xUxEz9mCz1+m07ftNVStgwRb2RWw+U6oKo08PAvOishMxiqz1mlJyLl8yQx2Qg==} resolution: {integrity: sha512-0ZdQEsSfH3mX4BFbRCc3xOBjx5bDbm73+aAdQOHerPQNf8K0XFMAv79ucd2BpnSc4UMyvBDixiroT8yjm2Y6bw==}
engines: {node: '>=16.14.0'} engines: {node: '>=16.14.0'}
dependencies: dependencies:
'@babel/parser': 7.24.0 '@babel/parser': 7.24.4
'@rollup/pluginutils': 5.1.0(rollup@2.79.1) ast-kit: 0.12.1
pathe: 1.1.2
transitivePeerDependencies:
- rollup
dev: true
/ast-walker-scope@0.5.0(rollup@2.79.1):
resolution: {integrity: sha512-NsyHMxBh4dmdEHjBo1/TBZvCKxffmZxRYhmclfu0PP6Aftre47jOHYaYaNqJcV0bxihxFXhDkzLHUwHc0ocd0Q==}
engines: {node: '>=16.14.0'}
dependencies:
'@babel/parser': 7.24.0
ast-kit: 0.9.5(rollup@2.79.1)
transitivePeerDependencies:
- rollup
dev: true dev: true
/axios-mock-adapter@1.22.0(axios@1.6.8): /axios-mock-adapter@1.22.0(axios@1.6.8):
@ -2888,6 +3208,12 @@ packages:
sourcemap-codec: 1.4.8 sourcemap-codec: 1.4.8
dev: true dev: true
/magic-string@0.30.10:
resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==}
dependencies:
'@jridgewell/sourcemap-codec': 1.4.15
dev: true
/magic-string@0.30.7: /magic-string@0.30.7:
resolution: {integrity: sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==} resolution: {integrity: sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==}
engines: {node: '>=12'} engines: {node: '>=12'}
@ -3000,6 +3326,11 @@ packages:
commander: 1.1.1 commander: 1.1.1
dev: false dev: false
/mrmime@2.0.0:
resolution: {integrity: sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==}
engines: {node: '>=10'}
dev: true
/ms@2.1.2: /ms@2.1.2:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
dev: true dev: true
@ -3257,6 +3588,11 @@ packages:
engines: {node: '>=4'} engines: {node: '>=4'}
dev: true dev: true
/resolve.exports@2.0.2:
resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==}
engines: {node: '>=10'}
dev: true
/restore-cursor@4.0.0: /restore-cursor@4.0.0:
resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@ -3409,6 +3745,15 @@ packages:
engines: {node: '>=14'} engines: {node: '>=14'}
dev: true dev: true
/sirv@2.0.4:
resolution: {integrity: sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==}
engines: {node: '>= 10'}
dependencies:
'@polka/url': 1.0.0-next.25
mrmime: 2.0.0
totalist: 3.0.1
dev: true
/slash@3.0.0: /slash@3.0.0:
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -3546,6 +3891,11 @@ packages:
is-number: 7.0.0 is-number: 7.0.0
dev: true dev: true
/totalist@3.0.1:
resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
engines: {node: '>=6'}
dev: true
/ts-api-utils@1.3.0(typescript@5.3.3): /ts-api-utils@1.3.0(typescript@5.3.3):
resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==}
engines: {node: '>=16'} engines: {node: '>=16'}
@ -3594,20 +3944,89 @@ packages:
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
dev: true dev: true
/unplugin-vue-define-options@1.4.2(rollup@2.79.1)(vue@3.4.21): /unplugin-combine@0.9.0(rollup@2.79.1)(vite@5.1.7):
resolution: {integrity: sha512-jQ3nJ1olC107QUA67UEB1CWJXnbVA7SF4UibKQF+jvME7UZ/XomctISHtAkJSJ9YHn0eqnqqzyNkng/KnLUZBw==} resolution: {integrity: sha512-1bXgHXIhw/bNEFCwNnYRlOOcamsBNQObSWBuy3FcDcnMoFLIi4ZaMsi/L0cNxltfYBTS+QvGSZ1F+LgQ0vbcLg==}
engines: {node: '>=16.14.0'}
peerDependencies:
esbuild: '>=0.13'
rollup: ^3.2.0 || ^4.0.0
vite: ^2.3.0 || ^3.0.0 || ^4.0.0 || ^5.0.0
webpack: 4 || 5
peerDependenciesMeta:
esbuild:
optional: true
rollup:
optional: true
vite:
optional: true
webpack:
optional: true
dependencies:
'@antfu/utils': 0.7.7
rollup: 2.79.1
unplugin: 1.10.1
vite: 5.1.7(@types/node@20.12.4)(less@4.1.3)
dev: true
/unplugin-vue-define-options@1.4.3(rollup@2.79.1)(vue@3.4.21):
resolution: {integrity: sha512-CN5xF8l8bySD6okw6PCt1zWFHf5vX+q4Cg2ssn9usANHtxmeyCgMccC7ywZyzI32dQS+pq6hvuSz/GewtYnbEQ==}
engines: {node: '>=16.14.0'} engines: {node: '>=16.14.0'}
dependencies: dependencies:
'@vue-macros/common': 1.10.1(rollup@2.79.1)(vue@3.4.21) '@vue-macros/common': 1.10.2(rollup@2.79.1)(vue@3.4.21)
ast-walker-scope: 0.5.0(rollup@2.79.1) ast-walker-scope: 0.6.1
unplugin: 1.7.1 unplugin: 1.10.1
transitivePeerDependencies: transitivePeerDependencies:
- rollup - rollup
- vue - vue
dev: true dev: true
/unplugin@1.7.1: /unplugin-vue-macros@2.9.1(rollup@2.79.1)(typescript@5.3.3)(vite@5.1.7)(vue@3.4.21):
resolution: {integrity: sha512-JqzORDAPxxs8ErLV4x+LL7bk5pk3YlcWqpSNsIkAZj972KzFZLClc/ekppahKkOczGkwIG6ElFgdOgOlK4tXZw==} resolution: {integrity: sha512-r9y6e5GhUgRGzHr+Od9X6S2irdzwSAdU2BvSz0dXN00tDHNm/Y/iCn/Iypdzbe4ai9b09lMfB5MFUpT3jfOlQA==}
engines: {node: '>=16.14.0'}
peerDependencies:
vue: ^2.7.0 || ^3.2.25
dependencies:
'@vue-macros/better-define': 1.7.5(rollup@2.79.1)(vue@3.4.21)
'@vue-macros/boolean-prop': 0.3.3(rollup@2.79.1)(vue@3.4.21)
'@vue-macros/chain-call': 0.2.3(rollup@2.79.1)(vue@3.4.21)
'@vue-macros/common': 1.10.2(rollup@2.79.1)(vue@3.4.21)
'@vue-macros/define-emit': 0.2.5(rollup@2.79.1)(vue@3.4.21)
'@vue-macros/define-models': 1.2.3(rollup@2.79.1)(vue@3.4.21)
'@vue-macros/define-prop': 0.3.5(rollup@2.79.1)(vue@3.4.21)
'@vue-macros/define-props': 2.0.4(@vue-macros/reactivity-transform@0.4.4)(rollup@2.79.1)(vue@3.4.21)
'@vue-macros/define-props-refs': 1.2.3(rollup@2.79.1)(vue@3.4.21)
'@vue-macros/define-render': 1.5.3(rollup@2.79.1)(vue@3.4.21)
'@vue-macros/define-slots': 1.1.3(rollup@2.79.1)(vue@3.4.21)
'@vue-macros/devtools': 0.2.0(typescript@5.3.3)(vite@5.1.7)
'@vue-macros/export-expose': 0.1.3(rollup@2.79.1)(vue@3.4.21)
'@vue-macros/export-props': 0.4.3(rollup@2.79.1)(vue@3.4.21)
'@vue-macros/export-render': 0.2.3(rollup@2.79.1)(vue@3.4.21)
'@vue-macros/hoist-static': 1.5.3(rollup@2.79.1)(vue@3.4.21)
'@vue-macros/jsx-directive': 0.8.12(rollup@2.79.1)(vue@3.4.21)
'@vue-macros/named-template': 0.4.3(rollup@2.79.1)(vue@3.4.21)
'@vue-macros/reactivity-transform': 0.4.4(rollup@2.79.1)(vue@3.4.21)
'@vue-macros/setup-block': 0.3.3(rollup@2.79.1)(vue@3.4.21)
'@vue-macros/setup-component': 0.17.3(rollup@2.79.1)(vue@3.4.21)
'@vue-macros/setup-sfc': 0.17.3(rollup@2.79.1)(vue@3.4.21)
'@vue-macros/short-bind': 0.2.3(rollup@2.79.1)(vue@3.4.21)
'@vue-macros/short-emits': 1.5.3(rollup@2.79.1)(vue@3.4.21)
'@vue-macros/short-vmodel': 1.4.3(rollup@2.79.1)(vue@3.4.21)
unplugin: 1.10.1
unplugin-combine: 0.9.0(rollup@2.79.1)(vite@5.1.7)
unplugin-vue-define-options: 1.4.3(rollup@2.79.1)(vue@3.4.21)
vue: 3.4.21(typescript@5.3.3)
transitivePeerDependencies:
- '@vueuse/core'
- esbuild
- rollup
- typescript
- vite
- webpack
dev: true
/unplugin@1.10.1:
resolution: {integrity: sha512-d6Mhq8RJeGA8UfKCu54Um4lFA0eSaRa3XxdAJg8tIdxbu1ubW0hBCZUL7yI2uGyYCRndvbK8FLHzqy2XKfeMsg==}
engines: {node: '>=14.0.0'}
dependencies: dependencies:
acorn: 8.11.3 acorn: 8.11.3
chokidar: 3.6.0 chokidar: 3.6.0

View File

@ -1,47 +1,45 @@
<template> <template>
<img class="close" ref="img" :src="src" /> <img class="close" ref="imgEl" :src="src" />
</template> </template>
<script> <script setup lang="ts">
import { _css } from '@/utils/dom' import { _css } from '@/utils/dom'
import { onMounted } from 'vue'
export default { defineOptions({
name: 'Back', name: 'Back'
props: { })
mode: { const props = defineProps({
type: String, mode: {
default: 'gray' type: String,
}, default: 'gray'
img: {
type: String,
default: 'back'
},
direction: {
type: String,
default: 'left'
},
scale: {
type: [Number, String],
default: 1
}
}, },
data() { img: {
return {} type: String,
default: 'back'
}, },
computed: { direction: {
src() { type: String,
return new URL(`../assets/img/icon/components/${this.mode}-${this.img}.png`, import.meta.url) default: 'left'
.href
}
}, },
mounted() { scale: {
_css( type: [Number, String],
this.$refs.img, default: 1
'transform', }
`rotate(${this.direction === 'left' ? '0' : '180'}deg) scale(${this.scale})` })
)
}, const imgEl = $ref()
methods: {} const src = $computed(() => {
} return new URL(`../assets/img/icon/components/${props.mode}-${props.img}.png`, import.meta.url)
.href
})
onMounted(() => {
_css(
imgEl,
'transform',
`rotate(${props.direction === 'left' ? '0' : '180'}deg) scale(${props.scale})`
)
})
</script> </script>
<style scoped lang="less"> <style scoped lang="less">

View File

@ -1,36 +1,50 @@
<template> <template>
<div class="music-wrapper"> <div class="music-wrapper">
<div
class="mute-icon"
:class="showMutedNotice && 'notice'"
v-click="() => bus.emit(EVENT_KEY.REMOVE_MUTED)"
v-if="isMuted"
>
<div class="wrap">
<Icon icon="flowbite:volume-mute-solid" />
<span :style="{ opacity: showMutedNotice ? 1 : 0 }">取消静音</span>
</div>
</div>
<img <img
class="music" class="music"
:src="props.item.music?.cover_thumb.url_list[0]" :src="item.music?.cover_thumb.url_list[0]"
:style="style" :style="style"
@click.stop=" v-click="
bus.emit(EVENT_KEY.NAV, { () =>
path: '/home/music', bus.emit(EVENT_KEY.NAV, {
query: { id: props.item.id } path: '/home/music',
}) query: { id: item.aweme_id }
})
" "
/> />
</div> </div>
</template> </template>
<script setup> <script setup lang="ts">
import { computed, inject } from 'vue' import { inject, onMounted } from 'vue'
import bus, { EVENT_KEY } from '@/utils/bus' import bus, { EVENT_KEY } from '@/utils/bus'
import { Icon } from '@iconify/vue'
import { useClick } from '@/utils/hooks/useClick'
const props = defineProps({ const isPlaying = inject<boolean>('isPlaying')
item: { const isMuted = inject('isMuted')
type: Object, const item = inject<any>('item')
default: () => { const vClick = useClick()
return {} let showMutedNotice = $ref(window.showMutedNotice)
}
}
})
const isPlaying = inject('isPlaying') const style = $computed(() => {
const style = computed(() => {
return { webkitAnimationPlayState: isPlaying.value ? 'running' : 'paused' } return { webkitAnimationPlayState: isPlaying.value ? 'running' : 'paused' }
}) })
onMounted(() => {
bus.on(EVENT_KEY.HIDE_MUTED_NOTICE, () => {
showMutedNotice = false
})
})
</script> </script>
<style lang="less"> <style lang="less">
@ -38,11 +52,14 @@ const style = computed(() => {
display: flex; display: flex;
justify-content: center; justify-content: center;
@w: 45rem; @w: 45rem;
width: @w;
height: @w;
position: relative;
.music { .music {
border-radius: 50%; border-radius: 50%;
width: @w; width: 100%;
height: @w; height: 100%;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
@ -59,5 +76,43 @@ const style = computed(() => {
transform: rotate(360deg); transform: rotate(360deg);
} }
} }
.mute-icon {
.music;
cursor: pointer;
position: absolute;
z-index: 1;
right: 0;
background: white;
animation: unset;
color: black;
transition: all 0.5s;
overflow: hidden;
.wrap {
width: 100rem;
position: absolute;
left: 0;
display: flex;
align-items: center;
justify-content: center;
}
&.notice {
border-radius: 50rem;
width: 100rem;
}
svg {
font-size: 22rem;
}
span {
margin-left: 5rem;
font-size: 13rem;
word-break: keep-all;
transition: all 0.5s;
}
}
} }
</style> </style>

View File

@ -35,7 +35,7 @@
src="../assets/img/icon/components/check/check-red-share.png" src="../assets/img/icon/components/check/check-red-share.png"
/> />
</div> </div>
<div class="option" @click.stop="closeShare($nav('/message/share-to-friend'))"> <div class="option" @click.stop="closeShare($router.push('/message/share-to-friend'))">
<dy-back class="more" mode="light" direction="right"></dy-back> <dy-back class="more" mode="light" direction="right"></dy-back>
<span>更多朋友</span> <span>更多朋友</span>
</div> </div>
@ -62,7 +62,7 @@
<img class="small" src="../assets/img/icon/components/video/dou.webp" alt="" /> <img class="small" src="../assets/img/icon/components/video/dou.webp" alt="" />
<span>帮上热门</span> <span>帮上热门</span>
</div> </div>
<div class="option" @click.stop="$nav('/home/report', { mode: this.mode })"> <div class="option" @click.stop="$router.push('/home/report', { mode: this.mode })">
<img class="small" src="../assets/img/icon/components/video/warring.png" alt="" /> <img class="small" src="../assets/img/icon/components/video/warring.png" alt="" />
<span>举报</span> <span>举报</span>
</div> </div>
@ -105,7 +105,7 @@
<img class="small" src="../assets/img/icon/components/video/tofriend.webp" alt="" /> <img class="small" src="../assets/img/icon/components/video/tofriend.webp" alt="" />
<span>私信朋友</span> <span>私信朋友</span>
</div> </div>
<div class="option" @click.stop="$nav('/home/report', { mode: this.mode })"> <div class="option" @click.stop="$router.push('/home/report', { mode: this.mode })">
<img class="small" src="../assets/img/icon/components/video/warring.png" alt="" /> <img class="small" src="../assets/img/icon/components/video/warring.png" alt="" />
<span>举报音乐</span> <span>举报音乐</span>
</div> </div>

View File

@ -1,13 +1,13 @@
<template> <template>
<div class="video-wrapper" ref="videoWrapper" :class="positionName"> <div class="video-wrapper" ref="videoWrapper" :class="positionName">
<Loading v-if="loading" style="position: absolute" /> <Loading v-if="state.loading" style="position: absolute" />
<!-- <video :src="item.video + '?v=123'"--> <!-- <video :src="item.video + '?v=123'"-->
<video <video
:src="item.video.play_addr.url_list[0]" :src="item.video.play_addr.url_list[0]"
:poster="poster" :poster="poster"
ref="video" ref="videoEl"
muted :muted="state.isMuted"
preload preload="true"
loop loop
x5-video-player-type="h5-page" x5-video-player-type="h5-page"
:x5-video-player-fullscreen="false" :x5-video-player-fullscreen="false"
@ -23,13 +23,13 @@
<div class="float"> <div class="float">
<template v-if="isLive"> <template v-if="isLive">
<div class="living">点击进入直播间</div> <div class="living">点击进入直播间</div>
<ItemDesc :is-live="true" v-model:item="localItem" :position="position" /> <ItemDesc :is-live="true" v-model:item="state.localItem" :position="position" />
</template> </template>
<template v-else> <template v-else>
<div :style="{ opacity: isMove ? 0 : 1 }" class="normal"> <div :style="{ opacity: state.isMove ? 0 : 1 }" class="normal">
<template v-if="!commentVisible"> <template v-if="!state.commentVisible">
<ItemToolbar v-model:item="localItem" :position="position" v-bind="$attrs" /> <ItemToolbar v-model:item="state.localItem" />
<ItemDesc v-model:item="localItem" :position="position" /> <ItemDesc v-model:item="state.localItem" />
</template> </template>
<div v-if="isMy" class="comment-status"> <div v-if="isMy" class="comment-status">
<div class="comment"> <div class="comment">
@ -44,7 +44,7 @@
</div> </div>
</div> </div>
<transition-group name="comment-status" tag="div" class="loveds"> <transition-group name="comment-status" tag="div" class="loveds">
<div class="type-loved" :key="i" v-for="i in test"> <div class="type-loved" :key="i" v-for="i in state.test">
<img src="../../assets/img/icon/head-image.jpeg" alt="" class="avatar" /> <img src="../../assets/img/icon/head-image.jpeg" alt="" class="avatar" />
<img src="../../assets/img/icon/love.svg" alt="" class="loved" /> <img src="../../assets/img/icon/love.svg" alt="" class="loved" />
</div> </div>
@ -55,17 +55,17 @@
<div <div
class="progress" class="progress"
:class="progressClass" :class="progressClass"
ref="progress" ref="progressEl"
@click="null" @click="null"
@touchstart="touchstart" @touchstart="touchstart"
@touchmove="touchmove" @touchmove="touchmove"
@touchend="touchend" @touchend="touchend"
> >
<div class="time" v-if="isMove"> <div class="time" v-if="state.isMove">
<span class="currentTime">{{ _duration(currentTime) }}</span> <span class="currentTime">{{ _duration(state.currentTime) }}</span>
<span class="duration"> / {{ _duration(duration) }}</span> <span class="duration"> / {{ _duration(state.duration) }}</span>
</div> </div>
<template v-if="duration > 15 || isMove || !isPlaying"> <template v-if="state.duration > 15 || state.isMove || !isPlaying">
<div class="bg"></div> <div class="bg"></div>
<div class="progress-line" :style="durationStyle"></div> <div class="progress-line" :style="durationStyle"></div>
<div class="point"></div> <div class="point"></div>
@ -76,310 +76,325 @@
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import { _checkImgUrl, _duration, _stopPropagation } from '@/utils' import { _checkImgUrl, _duration, _stopPropagation } from '@/utils'
import Loading from '../Loading' import Loading from '../Loading.vue'
import ItemToolbar from './ItemToolbar' import ItemToolbar from './ItemToolbar.vue'
import ItemDesc from './ItemDesc' import ItemDesc from './ItemDesc.vue'
import bus, { EVENT_KEY } from '../../utils/bus' import bus, { EVENT_KEY } from '../../utils/bus'
import { SlideItemPlayStatus } from '@/utils/const_var' import { SlideItemPlayStatus } from '@/utils/const_var'
import { computed } from 'vue' import { computed, onMounted, onUnmounted, provide, reactive } from 'vue'
import { Icon } from '@iconify/vue' import { Icon } from '@iconify/vue'
import { _css } from '@/utils/dom' import { _css } from '@/utils/dom'
export default { defineOptions({
name: 'BaseVideo', name: 'BaseVideo'
components: { })
Loading,
ItemToolbar,
ItemDesc,
Icon
},
provide() {
return {
// isPlaying: computed(() => this.status)
isPlaying: computed(() => this.isPlaying)
}
},
props: {
item: {
type: Object,
default: () => {
return {}
}
},
position: {
type: Object,
default: () => {
return {}
}
},
//
isPlay: {
type: Boolean,
default: () => {
return true
}
},
isMy: {
type: Boolean,
default: () => {
return false
}
},
isLive: {
type: Boolean,
default: () => {
return false
}
}
},
computed: {
poster() {
return _checkImgUrl(this.item.video.poster ?? this.item.video.cover.url_list[0])
},
durationStyle() {
return { width: this.playX + 'px' }
},
progressClass() {
if (this.isMove) {
return 'move'
} else {
return this.isPlaying ? '' : 'stop'
}
},
positionName() {
return 'item-' + Object.values(this.position).join('-')
},
isPlaying() {
return this.status === SlideItemPlayStatus.Play
}
},
data() {
return {
loading: false,
paused: false,
status: this.isPlay ? SlideItemPlayStatus.Play : SlideItemPlayStatus.Pause,
duration: 0,
step: 0,
currentTime: -1,
playX: 0,
start: { x: 0 },
last: { x: 0, time: 0 },
height: 0,
width: 0,
isMove: false,
ignoreWaiting: false, //waitingwaiting
test: [1, 2],
localItem: this.item,
progressBarRect: {},
videoScreenHeight: 0,
commentVisible: false
}
},
mounted() {
// console.log('video', this.localItem.aweme_id)
// console.log(this.commentVisible)
this.height = document.body.clientHeight
this.width = document.body.clientWidth
let video = this.$refs.video
video.currentTime = 0
let fun = (e) => {
this.currentTime = Math.ceil(e.target.currentTime)
this.playX = (this.currentTime - 1) * this.step
}
video.addEventListener('loadedmetadata', () => {
this.videoScreenHeight = video.videoHeight / (video.videoWidth / this.width)
this.duration = video.duration
this.progressBarRect = this.$refs.progress.getBoundingClientRect()
this.step = this.progressBarRect.width / Math.floor(this.duration)
video.addEventListener('timeupdate', fun)
})
let eventTester = (e) => { const props = defineProps({
video.addEventListener( item: {
e, type: Object,
() => { default: () => {
// console.log('eventTester', e, this.item.aweme_id) return {}
if (e === 'playing') this.loading = false
if (e === 'waiting') {
if (!this.paused && !this.ignoreWaiting) {
this.loading = true
}
}
// console.log(e, t)
},
false
)
} }
// eventTester("loadstart", ''); //
// eventTester("abort", ''); //
// eventTester("loadstart", ''); //
// eventTester("progress", ''); //
// // eventTester("suspend", ''); //
// eventTester("abort", ''); //
// eventTester("error", ''); //
// eventTester("stalled", ''); //
// eventTester("play", 'play()autoplay'); //play()autoplay
// eventTester("pause", 'pause()'); //pause()
// eventTester("loadedmetadata", ''); //
// eventTester("loadeddata"); //
eventTester('waiting', '等待数据,并非错误') //
eventTester('playing', '开始回放') //
// eventTester("canplay", '/'); //
// eventTester("canplaythrough", ''); //
// eventTester("seeking", ''); //
// eventTester("seeked", ''); //
// // eventTester("timeupdate",''); //
// eventTester("ended", ''); //
// eventTester("ratechange", ''); //
// eventTester("durationchange", ''); //
// eventTester("volumechange", ''); //
// console.log('mounted')
// bus.off('singleClickBroadcast')
bus.on(EVENT_KEY.SINGLE_CLICK_BROADCAST, this.click)
bus.on(EVENT_KEY.DIALOG_MOVE, this.onDialogMove)
bus.on(EVENT_KEY.DIALOG_END, this.onDialogEnd)
bus.on(EVENT_KEY.OPEN_COMMENTS, this.onOpenComments)
bus.on(EVENT_KEY.CLOSE_COMMENTS, this.onCloseComments)
bus.on(EVENT_KEY.OPEN_SUB_TYPE, this.onOpenSubType)
bus.on(EVENT_KEY.CLOSE_SUB_TYPE, this.onCloseSubType)
}, },
unmounted() { position: {
// console.log('unmounted') type: Object,
bus.off(EVENT_KEY.SINGLE_CLICK_BROADCAST, this.click) default: () => {
bus.off(EVENT_KEY.DIALOG_MOVE, this.onDialogMove) return {}
bus.off(EVENT_KEY.DIALOG_END, this.onDialogEnd) }
bus.off(EVENT_KEY.OPEN_COMMENTS, this.onOpenComments)
bus.off(EVENT_KEY.CLOSE_COMMENTS, this.onCloseComments)
bus.off(EVENT_KEY.OPEN_SUB_TYPE, this.onOpenSubType)
bus.off(EVENT_KEY.CLOSE_SUB_TYPE, this.onCloseSubType)
}, },
methods: { //
_duration, isPlay: {
_checkImgUrl, type: Boolean,
onOpenSubType() { default: () => {
this.commentVisible = true return true
}, }
onCloseSubType() { },
this.commentVisible = false isMy: {
}, type: Boolean,
onDialogMove({ tag, e }) { default: () => {
if (this.commentVisible && tag === 'comment') { return false
_css(this.$refs.video, 'transition-duration', `0ms`) }
_css(this.$refs.video, 'height', `calc(var(--vh, 1vh) * 30 + ${e}px)`) },
} isLive: {
}, type: Boolean,
onDialogEnd({ tag, isClose }) { default: () => {
if (this.commentVisible && tag === 'comment') { return false
console.log('isClose', isClose)
_css(this.$refs.video, 'transition-duration', `300ms`)
if (isClose) {
this.commentVisible = false
_css(this.$refs.video, 'height', '100%')
} else {
_css(this.$refs.video, 'height', 'calc(var(--vh, 1vh) * 30)')
}
}
},
onOpenComments(id) {
if (id === this.item.aweme_id) {
_css(this.$refs.video, 'transition-duration', `300ms`)
_css(this.$refs.video, 'height', 'calc(var(--vh, 1vh) * 30)')
this.commentVisible = true
}
},
onCloseComments() {
if (this.commentVisible) {
_css(this.$refs.video, 'transition-duration', `300ms`)
_css(this.$refs.video, 'height', '100%')
this.commentVisible = false
}
},
click({ uniqueId, index, type }) {
if (this.position.uniqueId === uniqueId && this.position.index === index) {
if (type === EVENT_KEY.ITEM_TOGGLE) {
if (this.isLive) {
if (type === EVENT_KEY.ITEM_TOGGLE) {
this.pause()
bus.emit(EVENT_KEY.NAV, {
path: '/home/live',
query: { id: this.item.aweme_id }
})
}
} else {
if (this.status === SlideItemPlayStatus.Play) {
this.pause()
} else {
this.play()
}
}
}
if (type === EVENT_KEY.ITEM_STOP) {
this.$refs.video.currentTime = 0
this.ignoreWaiting = true
this.pause()
setTimeout(() => (this.ignoreWaiting = false), 300)
}
if (type === EVENT_KEY.ITEM_PLAY) {
this.$refs.video.currentTime = 0
this.ignoreWaiting = true
this.play()
setTimeout(() => (this.ignoreWaiting = false), 300)
}
}
},
play() {
this.status = SlideItemPlayStatus.Play
this.$refs.video.volume = 1
this.$refs.video.play()
},
pause() {
this.status = SlideItemPlayStatus.Pause
this.$refs.video.pause()
},
touchstart(e) {
_stopPropagation(e)
this.start.x = e.touches[0].pageX
this.last.x = this.playX
this.last.time = this.currentTime
},
touchmove(e) {
// console.log('move',e)
_stopPropagation(e)
this.isMove = true
this.pause()
let dx = e.touches[0].pageX - this.start.x
this.playX = this.last.x + dx
this.currentTime = this.last.time + Math.ceil(Math.ceil(dx) / this.step)
if (this.currentTime <= 0) this.currentTime = 0
if (this.currentTime >= this.duration) this.currentTime = this.duration
},
touchend(e) {
// console.log('end', e)
_stopPropagation(e)
if (this.isPlaying) return
setTimeout(() => (this.isMove = false), 1000)
this.$refs.video.currentTime = this.currentTime
this.play()
} }
} }
})
provide(
'isPlaying',
computed(() => isPlaying)
)
provide(
'isMuted',
computed(() => state.isMuted)
)
provide(
'position',
computed(() => props.position)
)
provide(
'item',
computed(() => props.item)
)
const videoEl = $ref<HTMLVideoElement>()
const progressEl = $ref<HTMLDivElement>()
let state = reactive({
loading: false,
paused: false,
isMuted: window.isMuted,
status: props.isPlay ? SlideItemPlayStatus.Play : SlideItemPlayStatus.Pause,
duration: 0,
step: 0,
currentTime: -1,
playX: 0,
start: { x: 0 },
last: { x: 0, time: 0 },
height: 0,
width: 0,
isMove: false,
ignoreWaiting: false, //waitingwaiting
test: [1, 2],
localItem: props.item,
progressBarRect: {
height: 0,
width: 0
},
videoScreenHeight: 0,
commentVisible: false
})
const poster = $computed(() => {
return _checkImgUrl(props.item.video.poster ?? props.item.video.cover.url_list[0])
})
const durationStyle = $computed(() => {
return { width: state.playX + 'px' }
})
const isPlaying = $computed(() => {
return state.status === SlideItemPlayStatus.Play
})
const positionName = $computed(() => {
return 'item-' + Object.values(props.position).join('-')
})
const progressClass = $computed(() => {
if (state.isMove) {
return 'move'
} else {
return isPlaying ? '' : 'stop'
}
})
onMounted(() => {
// console.log('video', this.localItem.aweme_id)
// console.log(this.commentVisible)
state.height = document.body.clientHeight
state.width = document.body.clientWidth
videoEl.currentTime = 0
let fun = (e) => {
state.currentTime = Math.ceil(e.target.currentTime)
state.playX = (state.currentTime - 1) * state.step
}
videoEl.addEventListener('loadedmetadata', () => {
state.videoScreenHeight = videoEl.videoHeight / (videoEl.videoWidth / state.width)
state.duration = videoEl.duration
state.progressBarRect = progressEl.getBoundingClientRect()
state.step = state.progressBarRect.width / Math.floor(state.duration)
videoEl.addEventListener('timeupdate', fun)
})
let eventTester = (e, t: string) => {
videoEl.addEventListener(
e,
() => {
// console.log('eventTester', e, state.item.aweme_id)
if (e === 'playing') state.loading = false
if (e === 'waiting') {
if (!state.paused && !state.ignoreWaiting) {
state.loading = true
}
}
console.log(e, t)
},
false
)
}
// eventTester("loadstart", ''); //
// eventTester("abort", ''); //
// eventTester("loadstart", ''); //
// eventTester("progress", ''); //
// // eventTester("suspend", ''); //
// eventTester("abort", ''); //
// eventTester("error", ''); //
// eventTester("stalled", ''); //
// eventTester("play", 'play()autoplay'); //play()autoplay
// eventTester("pause", 'pause()'); //pause()
// eventTester("loadedmetadata", ''); //
// eventTester("loadeddata"); //
eventTester('waiting', '等待数据,并非错误') //
eventTester('playing', '开始回放') //
// eventTester("canplay", '/'); //
// eventTester("canplaythrough", ''); //
// eventTester("seeking", ''); //
// eventTester("seeked", ''); //
// // eventTester("timeupdate",''); //
// eventTester("ended", ''); //
// eventTester("ratechange", ''); //
// eventTester("durationchange", ''); //
// eventTester("volumechange", ''); //
// console.log('mounted')
// bus.off('singleClickBroadcast')
bus.on(EVENT_KEY.SINGLE_CLICK_BROADCAST, click)
bus.on(EVENT_KEY.DIALOG_MOVE, onDialogMove)
bus.on(EVENT_KEY.DIALOG_END, onDialogEnd)
bus.on(EVENT_KEY.OPEN_COMMENTS, onOpenComments)
bus.on(EVENT_KEY.CLOSE_COMMENTS, onCloseComments)
bus.on(EVENT_KEY.OPEN_SUB_TYPE, onOpenSubType)
bus.on(EVENT_KEY.CLOSE_SUB_TYPE, onCloseSubType)
bus.on(EVENT_KEY.REMOVE_MUTED, removeMuted)
})
onUnmounted(() => {
// console.log('unmounted')
bus.off(EVENT_KEY.SINGLE_CLICK_BROADCAST, click)
bus.off(EVENT_KEY.DIALOG_MOVE, onDialogMove)
bus.off(EVENT_KEY.DIALOG_END, onDialogEnd)
bus.off(EVENT_KEY.OPEN_COMMENTS, onOpenComments)
bus.off(EVENT_KEY.CLOSE_COMMENTS, onCloseComments)
bus.off(EVENT_KEY.OPEN_SUB_TYPE, onOpenSubType)
bus.off(EVENT_KEY.CLOSE_SUB_TYPE, onCloseSubType)
bus.off(EVENT_KEY.REMOVE_MUTED, removeMuted)
})
function removeMuted() {
state.isMuted = false
}
function onOpenSubType() {
state.commentVisible = true
}
function onCloseSubType() {
state.commentVisible = false
}
function onDialogMove({ tag, e }) {
if (state.commentVisible && tag === 'comment') {
_css(videoEl, 'transition-duration', `0ms`)
_css(videoEl, 'height', `calc(var(--vh, 1vh) * 30 + ${e}px)`)
}
}
function onDialogEnd({ tag, isClose }) {
if (state.commentVisible && tag === 'comment') {
console.log('isClose', isClose)
_css(videoEl, 'transition-duration', `300ms`)
if (isClose) {
state.commentVisible = false
_css(videoEl, 'height', '100%')
} else {
_css(videoEl, 'height', 'calc(var(--vh, 1vh) * 30)')
}
}
}
function onOpenComments(id) {
if (id === props.item.aweme_id) {
_css(videoEl, 'transition-duration', `300ms`)
_css(videoEl, 'height', 'calc(var(--vh, 1vh) * 30)')
state.commentVisible = true
}
}
function onCloseComments() {
if (state.commentVisible) {
_css(videoEl, 'transition-duration', `300ms`)
_css(videoEl, 'height', '100%')
state.commentVisible = false
}
}
function click({ uniqueId, index, type }) {
if (props.position.uniqueId === uniqueId && props.position.index === index) {
if (type === EVENT_KEY.ITEM_TOGGLE) {
if (props.isLive) {
if (type === EVENT_KEY.ITEM_TOGGLE) {
pause()
bus.emit(EVENT_KEY.NAV, {
path: '/home/live',
query: { id: props.item.aweme_id }
})
}
} else {
if (state.status === SlideItemPlayStatus.Play) {
pause()
} else {
play()
}
}
}
if (type === EVENT_KEY.ITEM_STOP) {
videoEl.currentTime = 0
state.ignoreWaiting = true
pause()
setTimeout(() => (state.ignoreWaiting = false), 300)
}
if (type === EVENT_KEY.ITEM_PLAY) {
videoEl.currentTime = 0
state.ignoreWaiting = true
play()
setTimeout(() => (state.ignoreWaiting = false), 300)
}
}
}
function play() {
state.status = SlideItemPlayStatus.Play
videoEl.volume = 1
videoEl.play()
}
function pause() {
state.status = SlideItemPlayStatus.Pause
videoEl.pause()
}
function touchstart(e) {
_stopPropagation(e)
state.start.x = e.touches[0].pageX
state.last.x = state.playX
state.last.time = state.currentTime
}
function touchmove(e) {
// console.log('move',e)
_stopPropagation(e)
state.isMove = true
pause()
let dx = e.touches[0].pageX - state.start.x
state.playX = state.last.x + dx
state.currentTime = state.last.time + Math.ceil(Math.ceil(dx) / state.step)
if (state.currentTime <= 0) state.currentTime = 0
if (state.currentTime >= state.duration) state.currentTime = state.duration
}
function touchend(e) {
// console.log('end', e)
_stopPropagation(e)
if (isPlaying) return
setTimeout(() => (state.isMove = false), 1000)
videoEl.currentTime = state.currentTime
play()
} }
</script> </script>
<style scoped lang="less"> <style scoped lang="less">
.fade-enter-active,
.fade-leave-active {
transition: transform 0.5s linear;
}
.fade-enter-from,
.fade-leave-to {
transform: scale(0);
}
.video-wrapper { .video-wrapper {
position: relative; position: relative;
font-size: 14rem; font-size: 14rem;
@ -410,140 +425,6 @@ export default {
width: 100%; width: 100%;
transition: all 0.3s; transition: all 0.3s;
.toolbar {
//width: 40px;
position: absolute;
bottom: 0;
right: 5px;
color: #fff;
.avatar-ctn {
position: relative;
.avatar {
width: 55px;
height: 55px;
border-radius: 50%;
}
.options {
position: absolute;
border-radius: 50%;
margin: auto;
left: 0;
right: 0;
bottom: -5px;
background: red;
//background: black;
width: 18px;
height: 18px;
display: flex;
justify-content: center;
align-items: center;
transition: all 1s;
img {
position: absolute;
width: 12px;
height: 12px;
transition: all 1s;
}
.yes {
opacity: 0;
transform: rotate(-180deg);
}
&.attention {
background: white;
.no {
opacity: 0;
transform: rotate(180deg);
}
.yes {
opacity: 1;
transform: rotate(0deg);
}
}
}
}
.love,
.message,
.share {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
@width: 35rem;
img {
width: @width;
height: @width;
}
span {
font-size: 12rem;
}
}
.loved {
background: red;
}
}
.content {
color: #fff;
position: absolute;
bottom: 0;
width: 75%;
//display: flex;
//flex-direction: column;
.location-wrapper {
display: flex;
.location {
margin-bottom: 10rem;
display: flex;
align-items: center;
font-size: 12rem;
padding: 4rem;
border-radius: 3rem;
background: var(--second-btn-color-tran);
.gang {
height: 8rem;
width: 1.5px;
margin: 0 5rem;
background: gray;
}
img {
margin-right: 7rem;
width: 18rem;
}
}
}
.music {
position: relative;
width: 60%;
display: flex;
align-items: center;
.music-image {
width: 20px;
height: 20px;
margin-top: 3px;
}
}
}
.comment-status { .comment-status {
display: flex; display: flex;
align-items: center; align-items: center;

View File

@ -1,19 +1,7 @@
<script setup> <script setup lang="ts">
import { reactive } from 'vue' import { inject, reactive } from 'vue'
const props = defineProps({ const props = defineProps({
item: {
type: Object,
default: () => {
return {}
}
},
position: {
type: Object,
default: () => {
return {}
}
},
isMy: { isMy: {
type: Boolean, type: Boolean,
default: () => { default: () => {
@ -28,6 +16,8 @@ const props = defineProps({
} }
}) })
const item = inject<any>('item')
const state = reactive({ const state = reactive({
isAttention: false, isAttention: false,
test: [1, 2] test: [1, 2]
@ -36,26 +26,26 @@ const state = reactive({
<template> <template>
<div class="item-desc ml1r mb1r"> <div class="item-desc ml1r mb1r">
<div class="content" v-if="!props.isMy"> <div class="content" v-if="!props.isMy">
<div class="location-wrapper" v-if="props.item.city || item.address"> <div class="location-wrapper" v-if="item.city || item.address">
<div class="location"> <div class="location">
<img src="../../assets/img/icon/location.webp" alt="" /> <img src="../../assets/img/icon/location.webp" alt="" />
<span>{{ props.item.city }}</span> <span>{{ item.city }}</span>
<template v-if="props.item.address"> <template v-if="item.address">
<div class="gang"></div> <div class="gang"></div>
</template> </template>
<span>{{ props.item.address }}</span> <span>{{ item.address }}</span>
</div> </div>
</div> </div>
<div class="live" v-if="props.isLive">直播中</div> <div class="live" v-if="props.isLive">直播中</div>
<div class="name mb1r f18 fb" @click.stop="$emit('goUserInfo')"> <div class="name mb1r f18 fb" @click.stop="$emit('goUserInfo')">
@{{ props.item.author.nickname }} @{{ item.author.nickname }}
</div> </div>
<div class="description"> <div class="description">
{{ props.item.desc }} {{ item.desc }}
</div> </div>
<!-- <div class="music" @click.stop="bus.emit('nav','/home/music')">--> <!-- <div class="music" @click.stop="bus.emit('nav','/home/music')">-->
<!-- <img src="../../assets/img/icon/music.svg" alt="" class="music-image">--> <!-- <img src="../../assets/img/icon/music.svg" alt="" class="music-image">-->
<!-- <span>{{ props.item.music.title }}</span>--> <!-- <span>{{ item.music.title }}</span>-->
<!-- </div>--> <!-- </div>-->
</div> </div>
<div v-else class="comment-status"> <div v-else class="comment-status">
@ -88,7 +78,7 @@ const state = reactive({
.content { .content {
color: #fff; color: #fff;
width: 75vw; width: 70vw;
text-align: left; text-align: left;
.location-wrapper { .location-wrapper {

View File

@ -1,23 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import BaseMusic from '../BaseMusic.vue' import BaseMusic from '../BaseMusic.vue'
import { _dateFormat, _formatNumber, _stopPropagation, _updateItem } from '@/utils' import { _formatNumber, _updateItem } from '@/utils'
import bus, { EVENT_KEY } from '@/utils/bus' import bus, { EVENT_KEY } from '@/utils/bus'
import { Icon } from '@iconify/vue' import { Icon } from '@iconify/vue'
import { useClick } from '@/utils/hooks/useClick' import { useClick } from '@/utils/hooks/useClick'
import { inject } from 'vue'
const props = defineProps({ const props = defineProps({
item: {
type: Object,
default: () => {
return {}
}
},
position: {
type: Object,
default: () => {
return {}
}
},
isMy: { isMy: {
type: Boolean, type: Boolean,
default: () => { default: () => {
@ -25,10 +14,13 @@ const props = defineProps({
} }
} }
}) })
const item = inject<any>('item')
const emit = defineEmits(['update:item', 'goUserInfo', 'showComments', 'showShare', 'goMusic']) const emit = defineEmits(['update:item', 'goUserInfo', 'showComments', 'showShare', 'goMusic'])
function loved() { function loved() {
_updateItem(props, 'isLoved', !props.item.isLoved, emit) _updateItem(props, 'isLoved', !item.isLoved, emit)
} }
function attention(e) { function attention(e) {
@ -39,7 +31,7 @@ function attention(e) {
} }
function showComments() { function showComments() {
bus.emit(EVENT_KEY.OPEN_COMMENTS, props.item.aweme_id) bus.emit(EVENT_KEY.OPEN_COMMENTS, item.aweme_id)
} }
const vClick = useClick() const vClick = useClick()
@ -50,12 +42,12 @@ const vClick = useClick()
<div class="avatar-ctn mb2r"> <div class="avatar-ctn mb2r">
<img <img
class="avatar" class="avatar"
:src="props.item.author.avatar_168x168.url_list[0]" :src="item.author.avatar_168x168.url_list[0]"
alt="" alt=""
v-click="() => bus.emit(EVENT_KEY.GO_USERINFO)" v-click="() => bus.emit(EVENT_KEY.GO_USERINFO)"
/> />
<transition name="fade"> <transition name="fade">
<div v-if="!props.item.isAttention" v-click="attention" class="options"> <div v-if="!item.isAttention" v-click="attention" class="options">
<img class="no" src="../../assets/img/icon/add-light.png" alt="" /> <img class="no" src="../../assets/img/icon/add-light.png" alt="" />
<img class="yes" src="../../assets/img/icon/ok-red.png" alt="" /> <img class="yes" src="../../assets/img/icon/ok-red.png" alt="" />
</div> </div>
@ -63,36 +55,36 @@ const vClick = useClick()
</div> </div>
<div class="love mb2r" v-click="loved"> <div class="love mb2r" v-click="loved">
<div> <div>
<img src="../../assets/img/icon/love.svg" class="love-image" v-if="!props.item.isLoved" /> <img src="../../assets/img/icon/love.svg" class="love-image" v-if="!item.isLoved" />
<img src="../../assets/img/icon/loved.svg" class="love-image" v-if="props.item.isLoved" /> <img src="../../assets/img/icon/loved.svg" class="love-image" v-if="item.isLoved" />
</div> </div>
<span>{{ _formatNumber(props.item.statistics.digg_count) }}</span> <span>{{ _formatNumber(item.statistics.digg_count) }}</span>
</div> </div>
<div class="message mb2r" v-click="showComments"> <div class="message mb2r" v-click="showComments">
<Icon icon="mage:message-dots-round-fill" class="icon" style="color: white" /> <Icon icon="mage:message-dots-round-fill" class="icon" style="color: white" />
<span>{{ _formatNumber(props.item.statistics.comment_count) }}</span> <span>{{ _formatNumber(item.statistics.comment_count) }}</span>
</div> </div>
<!--TODO --> <!--TODO -->
<div <div
class="message mb2r" class="message mb2r"
v-click="() => _updateItem(props, 'isCollect', !props.item.isCollect, emit)" v-click="() => _updateItem(props, 'isCollect', !item.isCollect, emit)"
> >
<Icon v-if="props.item.isCollect" icon="ic:round-star" class="icon" style="color: yellow" /> <Icon v-if="item.isCollect" icon="ic:round-star" class="icon" style="color: yellow" />
<Icon v-else icon="ic:round-star" class="icon" style="color: white" /> <Icon v-else icon="ic:round-star" class="icon" style="color: white" />
<span>{{ _formatNumber(props.item.statistics.comment_count) }}</span> <span>{{ _formatNumber(item.statistics.comment_count) }}</span>
</div> </div>
<div v-if="!props.isMy" class="share mb2r" v-click="() => bus.emit(EVENT_KEY.SHOW_SHARE)"> <div v-if="!props.isMy" class="share mb2r" v-click="() => bus.emit(EVENT_KEY.SHOW_SHARE)">
<img src="../../assets/img/icon/share-white-full.png" alt="" class="share-image" /> <img src="../../assets/img/icon/share-white-full.png" alt="" class="share-image" />
<span>{{ _formatNumber(props.item.statistics.share_count) }}</span> <span>{{ _formatNumber(item.statistics.share_count) }}</span>
</div> </div>
<div v-else class="share mb2r" v-click="() => bus.emit(EVENT_KEY.SHOW_SHARE)"> <div v-else class="share mb2r" v-click="() => bus.emit(EVENT_KEY.SHOW_SHARE)">
<img src="../../assets/img/icon/menu-white.png" alt="" class="share-image" /> <img src="../../assets/img/icon/menu-white.png" alt="" class="share-image" />
</div> </div>
<!-- <BaseMusic--> <!-- <BaseMusic-->
<!-- :cover="props.item.music.cover"--> <!-- :cover="item.music.cover"-->
<!-- v-click="$nav('/home/music')"--> <!-- v-click="$router.push('/home/music')"-->
<!-- /> --> <!-- /> -->
<BaseMusic :item="props.item" /> <BaseMusic />
</div> </div>
</template> </template>
@ -101,8 +93,11 @@ const vClick = useClick()
//width: 40px; //width: 40px;
position: absolute; position: absolute;
bottom: 0; bottom: 0;
right: 5px; right: 10rem;
color: #fff; color: #fff;
display: flex;
flex-direction: column;
align-items: center;
.avatar-ctn { .avatar-ctn {
position: relative; position: relative;

View File

@ -8,8 +8,11 @@ import mixin from './utils/mixin'
import VueLazyload from '@jambonn/vue-lazyload' import VueLazyload from '@jambonn/vue-lazyload'
import { createPinia } from 'pinia' import { createPinia } from 'pinia'
import { useClick } from '@/utils/hooks/useClick' import { useClick } from '@/utils/hooks/useClick'
import bus, { EVENT_KEY } from '@/utils/bus'
window.isMoved = false window.isMoved = false
window.isMuted = true
window.showMutedNotice = true
HTMLElement.prototype.addEventListener = new Proxy(HTMLElement.prototype.addEventListener, { HTMLElement.prototype.addEventListener = new Proxy(HTMLElement.prototype.addEventListener, {
apply(target, ctx, args) { apply(target, ctx, args) {
const eventName = args[0] const eventName = args[0]
@ -52,3 +55,10 @@ app.directive('click', vClick)
//放到最后才可以使用pinia //放到最后才可以使用pinia
startMock() startMock()
setTimeout(() => {
bus.emit(EVENT_KEY.HIDE_MUTED_NOTICE)
window.showMutedNotice = false
}, 2000)
bus.on(EVENT_KEY.REMOVE_MUTED, () => {
window.isMuted = false
})

View File

@ -22,11 +22,11 @@
<img src="../../../assets/img/icon/components/follow/share.png" alt="" /> <img src="../../../assets/img/icon/components/follow/share.png" alt="" />
<span>分享主页</span> <span>分享主页</span>
</div> </div>
<div class="option" @click="cancel((e) => $nav('/message/chat'))"> <div class="option" @click="cancel((e) => $router.push('/message/chat'))">
<img src="../../../assets/img/icon/components/follow/private-chat.png" alt="" /> <img src="../../../assets/img/icon/components/follow/private-chat.png" alt="" />
<span>发私信</span> <span>发私信</span>
</div> </div>
<div class="option" @click="cancel((e) => $nav('/home/report', { mode: 'chat' }))"> <div class="option" @click="cancel((e) => $router.push('/home/report', { mode: 'chat' }))">
<img src="../../../assets/img/icon/components/follow/report.png" alt="" /> <img src="../../../assets/img/icon/components/follow/report.png" alt="" />
<span>举报</span> <span>举报</span>
</div> </div>

View File

@ -37,7 +37,12 @@
</div> </div>
<div class="indicator" ref="indicator"></div> <div class="indicator" ref="indicator"></div>
</div> </div>
<Icon v-hide="loading" icon="ion:search" class="search" @click="$nav('/home/search')" /> <Icon
v-hide="loading"
icon="ion:search"
class="search"
@click="$router.push('/home/search')"
/>
</div> </div>
<div class="toggle-type" :class="{ open }"> <div class="toggle-type" :class="{ open }">
<div class="l-button" :class="{ active: type === 0 }" @click="toggleType(0)"> <div class="l-button" :class="{ active: type === 0 }" @click="toggleType(0)">
@ -276,6 +281,7 @@ export default {
color: rgba(white, 0.7); color: rgba(white, 0.7);
position: relative; position: relative;
font-size: 17rem; font-size: 17rem;
cursor: pointer;
.tab1-img { .tab1-img {
position: absolute; position: absolute;

View File

@ -109,7 +109,7 @@
<div class="share-btn shared" v-else>已私信</div> <div class="share-btn shared" v-else>已私信</div>
</div> </div>
</div> </div>
<div class="more" @click="cancel($nav('/message/share-to-friend'))"> <div class="more" @click="cancel($router.push('/message/share-to-friend'))">
<img src="../../../assets/img/icon/components/video/more-dark.png" /> <img src="../../../assets/img/icon/components/video/more-dark.png" />
<div class="right"> <div class="right">
<span>更多好友</span> <span>更多好友</span>

View File

@ -38,7 +38,7 @@
:can-download="canDownload" :can-download="canDownload"
@click="closeShare()" @click="closeShare()"
/> />
<to-share item-type="report" @click="$nav('/home/report', { mode: this.mode })" /> <to-share item-type="report" @click="$router.push('/home/report', { mode: this.mode })" />
<to-share item-type="copyPassword" @click="copyLink" /> <to-share item-type="copyPassword" @click="copyLink" />
<to-share :item-type="isCollect ? 'collectYellow' : 'collect'" @click="toggleCollect" /> <to-share :item-type="isCollect ? 'collectYellow' : 'collect'" @click="toggleCollect" />
<to-share item-type="comeon" @click="_no" /> <to-share item-type="comeon" @click="_no" />
@ -67,7 +67,7 @@
</dy-button> </dy-button>
</div> </div>
</div> </div>
<div class="more" @click="closeShare($nav('/message/share-to-friend'))"> <div class="more" @click="closeShare($router.push('/message/share-to-friend'))">
<img class="left" src="../../../assets/img/icon/components/video/more-dark.png" /> <img class="left" src="../../../assets/img/icon/components/video/more-dark.png" />
<span>更多朋友</span> <span>更多朋友</span>
</div> </div>

View File

@ -320,10 +320,12 @@ onUnmounted(() => {
onActivated(() => { onActivated(() => {
state.active = true state.active = true
bus.emit(EVENT_KEY.TOGGLE_VIDEO)
}) })
onDeactivated(() => { onDeactivated(() => {
state.active = false state.active = false
bus.emit(EVENT_KEY.TOGGLE_VIDEO)
}) })
function closeComments() { function closeComments() {

View File

@ -47,7 +47,7 @@
</div> </div>
<SlideList <SlideList
:active="props.active" :active="props.active"
uniqueId="uniqueId3" uniqueId="hot"
:style="{ :style="{
background: 'black', background: 'black',
marginTop: state.subTypeVisible ? state.subTypeHeight : 0 marginTop: state.subTypeVisible ? state.subTypeHeight : 0

View File

@ -18,7 +18,7 @@
<SlideList <SlideList
:cbs="{ isLive: true }" :cbs="{ isLive: true }"
:active="props.active" :active="props.active"
uniqueId="uniqueId2" uniqueId="live"
:style="{ :style="{
background: 'black', background: 'black',
marginTop: state.subTypeVisible ? state.subTypeHeight : 0 marginTop: state.subTypeVisible ? state.subTypeHeight : 0

View File

@ -1,6 +1,11 @@
<template> <template>
<SlideItem> <SlideItem>
<SlideList style="background: #000" :active="props.active" :api="recommendedVideo" /> <SlideList
uniqueId="home"
style="background: #000"
:active="props.active"
:api="recommendedVideo"
/>
</SlideItem> </SlideItem>
</template> </template>

View File

@ -123,12 +123,23 @@ function updateItem({ position, item }) {
} }
} }
function togglePlay() {
if (!props.active) return
bus.emit(EVENT_KEY.SINGLE_CLICK_BROADCAST, {
uniqueId: props.uniqueId,
index: state.index,
type: EVENT_KEY.ITEM_TOGGLE
})
}
onMounted(() => { onMounted(() => {
bus.on(EVENT_KEY.SINGLE_CLICK, click) bus.on(EVENT_KEY.SINGLE_CLICK, click)
bus.on(EVENT_KEY.UPDATE_ITEM, updateItem) bus.on(EVENT_KEY.UPDATE_ITEM, updateItem)
bus.on(EVENT_KEY.TOGGLE_VIDEO, togglePlay)
}) })
onUnmounted(() => { onUnmounted(() => {
bus.off(EVENT_KEY.SINGLE_CLICK, click) bus.off(EVENT_KEY.SINGLE_CLICK, click)
bus.on(EVENT_KEY.UPDATE_ITEM, updateItem) bus.off(EVENT_KEY.UPDATE_ITEM, updateItem)
bus.off(EVENT_KEY.TOGGLE_VIDEO, togglePlay)
}) })
</script> </script>

View File

@ -2,7 +2,7 @@
<div class="other-login" id="other-login"> <div class="other-login" id="other-login">
<BaseHeader mode="light" backMode="dark" backImg="back"> <BaseHeader mode="light" backMode="dark" backImg="back">
<template v-slot:right> <template v-slot:right>
<span class="f14" @click="$nav('/login/help')">帮助与设置</span> <span class="f14" @click="$router.push('/login/help')">帮助与设置</span>
</template> </template>
</BaseHeader> </BaseHeader>
<div class="content"> <div class="content">
@ -24,11 +24,13 @@
</div> </div>
<div class="right"> <div class="right">
已阅读并同意 已阅读并同意
<span class="link" @click="$nav('/service-protocol', { type: '“抖音”用户服务协议' })" <span
class="link"
@click="$router.push('/service-protocol', { type: '“抖音”用户服务协议' })"
>用户协议</span >用户协议</span
> >
<span class="link" @click="$nav('/service-protocol', { type: '“抖音”隐私政策' })" <span class="link" @click="$router.push('/service-protocol', { type: '“抖音”隐私政策' })"
>隐私政策</span >隐私政策</span
> >
同时登录并使用抖音火山版火山小视频和抖音 同时登录并使用抖音火山版火山小视频和抖音
@ -46,7 +48,7 @@
</dy-button> </dy-button>
<div class="options"> <div class="options">
<span class="link" @click="$nav('/login/password')">密码登录</span> <span class="link" @click="$router.push('/login/password')">密码登录</span>
<span class="link" @click="otherLogin">其他方式登录</span> <span class="link" @click="otherLogin">其他方式登录</span>
</div> </div>

View File

@ -2,7 +2,7 @@
<div class="PasswordLogin"> <div class="PasswordLogin">
<BaseHeader mode="light" backMode="dark" backImg="back"> <BaseHeader mode="light" backMode="dark" backImg="back">
<template v-slot:right> <template v-slot:right>
<span class="f14" @click="$nav('/login/help')">帮助与设置</span> <span class="f14" @click="$router.push('/login/help')">帮助与设置</span>
</template> </template>
</BaseHeader> </BaseHeader>
<div class="content"> <div class="content">
@ -26,11 +26,13 @@
</div> </div>
<div class="right"> <div class="right">
已阅读并同意 已阅读并同意
<span class="link" @click="$nav('/service-protocol', { type: '“抖音”用户服务协议' })" <span
class="link"
@click="$router.push('/service-protocol', { type: '“抖音”用户服务协议' })"
>用户协议</span >用户协议</span
> >
<span class="link" @click="$nav('/service-protocol', { type: '“抖音”隐私政策' })" <span class="link" @click="$router.push('/service-protocol', { type: '“抖音”隐私政策' })"
>隐私政策</span >隐私政策</span
> >
同时登录并使用抖音火山版火山小视频和抖音 同时登录并使用抖音火山版火山小视频和抖音
@ -53,7 +55,9 @@
<div class="options"> <div class="options">
<span> <span>
忘记了<span class="link" @click="$nav('/login/retrieve-password')">找回密码</span> 忘记了<span class="link" @click="$router.push('/login/retrieve-password')"
>找回密码</span
>
</span> </span>
</div> </div>
</div> </div>

View File

@ -32,11 +32,13 @@
</div> </div>
<div class="right"> <div class="right">
已阅读并同意 已阅读并同意
<span class="link" @click="$nav('/service-protocol', { type: '“抖音”用户服务协议' })" <span
class="link"
@click="$router.push('/service-protocol', { type: '“抖音”用户服务协议' })"
>用户协议</span >用户协议</span
> >
<span class="link" @click="$nav('/service-protocol', { type: '“抖音”隐私政策' })" <span class="link" @click="$router.push('/service-protocol', { type: '“抖音”隐私政策' })"
>隐私政策</span >隐私政策</span
> >
同时登录并使用抖音火山版火山小视频和抖音 同时登录并使用抖音火山版火山小视频和抖音

View File

@ -19,7 +19,7 @@
<span class="notice">抖音扫一扫立即关注我</span> <span class="notice">抖音扫一扫立即关注我</span>
</div> </div>
<div class="footer"> <div class="footer">
<!-- <div class="btn" @click="$nav('/scan')">--> <!-- <div class="btn" @click="$router.push('/scan')">-->
<div class="btn" @click="_no"> <div class="btn" @click="_no">
<div class="wrapper"> <div class="wrapper">
<img src="../../assets/img/icon/scan.png" alt="" /> <img src="../../assets/img/icon/scan.png" alt="" />

View File

@ -11,7 +11,7 @@
<span class="belong">{{ store.userinfo.nickname }}的红包</span> <span class="belong">{{ store.userinfo.nickname }}的红包</span>
<div class="password">大吉大利</div> <div class="password">大吉大利</div>
<span class="money">0.01</span> <span class="money">0.01</span>
<!-- <span class="notice" @click="$nav('/me/money')">已存入我的零钱可直接使用></span>--> <!-- <span class="notice" @click="$router.push('/me/money')">已存入我的零钱可直接使用></span>-->
<span class="notice" @click="_no">已存入我的零钱可直接使用></span> <span class="notice" @click="_no">已存入我的零钱可直接使用></span>
</div> </div>
<img src="../../assets/img/icon/message/chat/money-detail-bg.png" alt="" class="bg" /> <img src="../../assets/img/icon/message/chat/money-detail-bg.png" alt="" class="bg" />

View File

@ -62,5 +62,8 @@ export const EVENT_KEY = {
GO_USERINFO: 'GO_USERINFO', GO_USERINFO: 'GO_USERINFO',
SHOW_SHARE: 'SHOW_SHARE', SHOW_SHARE: 'SHOW_SHARE',
UPDATE_ITEM: 'UPDATE_ITEM', UPDATE_ITEM: 'UPDATE_ITEM',
CURRENT_ITEM: 'CURRENT_ITEM' CURRENT_ITEM: 'CURRENT_ITEM',
REMOVE_MUTED: 'REMOVE_MUTED',
HIDE_MUTED_NOTICE: 'HIDE_MUTED_NOTICE',
TOGGLE_VIDEO: 'TOGGLE_VIDEO'
} }

View File

@ -8,10 +8,11 @@ export function useClick() {
el.addEventListener('pointerdown', (e) => _stopPropagation(e)) el.addEventListener('pointerdown', (e) => _stopPropagation(e))
el.addEventListener('pointerup', (e) => { el.addEventListener('pointerup', (e) => {
_stopPropagation(e) _stopPropagation(e)
binding.value?.() binding.value?.(e)
}) })
}, },
unmounted(el: HTMLDivElement) { unmounted(el: HTMLDivElement) {
// eslint-disable-next-line
el = null el = null
} }
} }

View File

@ -10,7 +10,7 @@ import BaseButton from '../components/BaseButton.vue'
import CONST_VAR from './const_var' import CONST_VAR from './const_var'
import Dom from './dom' import Dom from './dom'
import bus, { EVENT_KEY } from './bus' import bus, { EVENT_KEY } from './bus'
import { _stopPropagation, random } from '@/utils' import { random } from '@/utils'
import { Icon } from '@iconify/vue' import { Icon } from '@iconify/vue'
import SlideHorizontal from '@/components/slide/SlideHorizontal.vue' import SlideHorizontal from '@/components/slide/SlideHorizontal.vue'

View File

@ -107,7 +107,7 @@ export function slideTouchMove(
notNextCb = null, notNextCb = null,
slideOtherDirectionCb = null slideOtherDirectionCb = null
) { ) {
console.log('move', state.name) // console.log('move', state.name)
if (!checkEvent(e)) return if (!checkEvent(e)) return
if (!state.isDown) return if (!state.isDown) return

View File

@ -18,6 +18,9 @@
"@/*": [ "@/*": [
"./src/*" "./src/*"
] ]
} },
"types": [
"unplugin-vue-macros/macros-global"
]
} }
} }

View File

@ -1,13 +1,11 @@
import { defineConfig, PluginOption } from 'vite' import { defineConfig, PluginOption } from 'vite'
import Vue from '@vitejs/plugin-vue' import Vue from '@vitejs/plugin-vue'
import VueJsx from '@vitejs/plugin-vue-jsx' import VueJsx from '@vitejs/plugin-vue-jsx'
import { resolve } from 'path'
import { visualizer } from 'rollup-plugin-visualizer' import { visualizer } from 'rollup-plugin-visualizer'
import DefineOptions from 'unplugin-vue-define-options/vite' // 引入插件
import { Plugin as importToCDN } from 'vite-plugin-cdn-import' import { Plugin as importToCDN } from 'vite-plugin-cdn-import'
import commonjs from 'vite-plugin-commonjs'
import { fileURLToPath, URL } from 'node:url' import { fileURLToPath, URL } from 'node:url'
import { getLastCommit } from 'git-last-commit' import { getLastCommit } from 'git-last-commit'
import VueMacros from 'unplugin-vue-macros/vite'
// import viteImagemin from 'vite-plugin-imagemin' // import viteImagemin from 'vite-plugin-imagemin'
// import viteCompression from 'vite-plugin-compression' // import viteCompression from 'vite-plugin-compression'
@ -28,20 +26,19 @@ export default defineConfig(async () => {
base: './', base: './',
envDir: 'env', envDir: 'env',
plugins: [ plugins: [
// VueMacros({ VueMacros({
// plugins: { plugins: {
// vue: Vue(), vue: Vue(),
// vueJsx: VueJsx(), // if needed vueJsx: VueJsx() // if needed
// }, }
// betterDefine: true, // betterDefine: true,
// // reactivityTransform: { // reactivityTransform: {
// // exclude: [/node_modules/, /jQuery\.js/] // exclude: [/node_modules/, /jQuery\.js/]
// // } // }
// }), }),
// Vue(),
// VueJsx(),
lifecycle === 'report' ? (visualizer({ open: false }) as any as PluginOption) : null, lifecycle === 'report' ? (visualizer({ open: false }) as any as PluginOption) : null,
DefineOptions(),
Vue(),
VueJsx(),
importToCDN({ importToCDN({
modules: [ modules: [
{ {