Commit c3571edb authored by lipengcheng 's avatar lipengcheng

feat: 新增布局组件

parent c5de000f
module.exports = { module.exports = {
// 不使用prettier格式化的文件填写在项目的.prettierignore文件中
// ignorePath: ".prettierignore",
// 与eslint集成(让prettier使用eslint的代码格式进行校验)
// eslintIntegration: true,
// 换行长度 // 换行长度
printWidth: 150, printWidth: 150,
// tab缩进大小,默认为2 // tab缩进大小,默认为2
......
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head>
<head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0"> <meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico"> <link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title> <title><%= htmlWebpackPlugin.options.title %></title>
</head> </head>
<body>
<body>
<noscript> <noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
Please enable it to continue.</strong>
</noscript> </noscript>
<div id="app"></div> <div id="app"></div>
<!-- built files will be auto injected --> <!-- built files will be auto injected -->
</body> </body>
</html> </html>
<template> <template>
<div id="app"> <div id="app">
<common-header></common-header> <component :is="layout"></component>
<body class="body-container">
<side-nav></side-nav>
<router-view style="flex:1;border: 1px solid #666;"></router-view>
<right-panel></right-panel>
</body>
<modal-layer></modal-layer>
<uploader></uploader>
</div> </div>
</template> </template>
<script> <script>
import CommonHeader from '@/components/header/index.vue'
export default { export default {
components: {
CommonHeader,
SideNav: () => import('@/components/sideNav/index.vue'),
RightPanel: () => import('@/components/rightPanel/index.vue'),
ModalLayer: () => import('@/components/modal/modalLayer.vue'),
Uploader: () => import('@/components/misc/uploader.vue')
},
data() { data() {
return {} return {}
}, },
computed: {
layout() {
return this.$route.meta.layout || 'default-layout'
}
},
async created() { async created() {
console.log(`this.route:`, this.route)
},
methods: {
async request() {
let result = await this.$http.get('/webapi/home/banner?type=1&category=18') let result = await this.$http.get('/webapi/home/banner?type=1&category=18')
console.log('result:', result) console.log('result:', result)
} }
}
} }
</script> </script>
......
<template>
<div></div>
</template>
<script>
export default {
data() {
return {}
},
methods: {}
}
</script>
<style lang="scss" scoped></style>
<template>
<div>
<input id="video-input" ref="videoInput" type="file" accept="video/mp4, video/NMP4" @change="onVideoInputChange" @click="onInputClick" />
</div>
</template>
<script>
import { mapActions } from 'vuex'
export default {
data() {
return {
videoInput: {}
}
},
mounted() {
this.videoInput = this.$refs.videoInput
},
methods: {
...mapActions({
upload: 'uploader/upload'
}),
onVideoInputChange() {
let file = this.videoInput.files[0]
console.log('turbo: onVideoInputChange -> file', file)
},
onInputClick() {
const vm = this
window.addEventListener('focus', function h() {
vm.clearInputValue(vm.videoInput)
console.log('turbo: h -> this.videoInput', vm.videoInput)
window.removeEventListener('focus', h)
})
},
clearInputValue(el) {
if (el) {
el.value = ''
}
}
}
}
</script>
<style lang="scss" scoped></style>
<template>
<div>
complete content
</div>
</template>
<script>
export default {
data() {
return {}
},
methods: {}
}
</script>
<style lang="scss" scoped></style>
<template>
<modal name="completeModal" :click-to-close="false">
<complete-content></complete-content>
</modal>
</template>
<script>
import CompleteContent from './completeContent'
export default {
components: {
CompleteContent
},
data() {
return {}
},
methods: {}
}
</script>
<style lang="scss" scoped></style>
<template>
<div class="modal-layer">
<complete-modal></complete-modal>
<select-modal></select-modal>
</div>
</template>
<script>
import CompleteModal from '@/components/modal/completeModal'
import SelectModal from '@/components/modal/selectModal'
export default {
components: {
CompleteModal,
SelectModal
},
data() {
return {}
},
methods: {}
}
</script>
<style lang="scss" scoped>
.modal-layer {
position: absolute;
left: 0;
top: 0;
width: 0;
height: 0;
}
</style>
<template>
<div>
<div class="close-btn" @click="close">
close
</div>
<div>选择视频</div>
<ul>
<li v-for="(item, i) in items" :key="i" class="item" @click="itemClick({ item, index: i })">
{{ item.text }}
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
items: [{ text: '本地上传', type: 'upload' }, { text: '视频库' }, { text: '我的作品' }]
}
},
methods: {
close() {
this.$modal.hide('selectModal')
},
triggerUpload() {
const el = document.getElementById('video-input')
el && el.click()
},
itemClick({ item = {} } = {}) {
if (item.type === 'upload') {
this.triggerUpload()
}
}
}
}
</script>
<style lang="scss" scoped></style>
<template>
<modal name="selectModal" :click-to-close="false">
<select-content></select-content>
</modal>
</template>
<script>
import SelectContent from './selectContent'
export default {
components: {
SelectContent
},
data() {
return {}
},
methods: {}
}
</script>
<style lang="scss" scoped></style>
...@@ -6,14 +6,8 @@ ...@@ -6,14 +6,8 @@
<router-link to="/about"> <router-link to="/about">
About About
</router-link> </router-link>
<router-link to="/cutter"> <router-link to="/bao2">
cutter bao2
</router-link>
<router-link to="/videoConverter">
转换宝
</router-link>
<router-link to="/screenshot">
screenshot
</router-link> </router-link>
</div> </div>
</template> </template>
......
<template>
<div class="taskComplete"></div>
</template>
<script>
export default {
name: 'TaskComplete',
components: {},
props: {},
data() {
return {}
},
computed: {},
watch: {},
methods: {}
}
</script>
<style scoped lang="scss">
.taskComplete {
width: 100%;
height: 100%;
background-color: #fff;
border: 0px solid black;
margin: 0px;
}
</style>
<template>
<div class="taskEdit">
<ul>
<li v-for="(item, index) in taskList" :key="index">
<div class="info">
<div class="cove">
视频封面
</div>
<div>
<div>{{ item.name }}.mp4</div>
<div>时长:{{ item.duration }}</div>
</div>
</div>
<div class="operationPanel">
<div v-show="item.state == 0" class="wait">
<div>输出格式</div>
<div class="selectionFormat">
mp4
</div>
<div class="delete" @click="clearTask(item)">
删除
</div>
</div>
<div v-show="item.state == 1" class="active">
<div class="progress">
<div>转换中{{ item.progress }}%</div>
<div class="slide">
<div></div>
</div>
</div>
<div class="stop" @click="stopTask(item)">
取消
</div>
</div>
</div>
</li>
</ul>
<div class="editBar">
<div class="addVideo" @click="addVideo">
添加视频
</div>
<div class="clearList" @click="clearAllTasks">
清空列表
</div>
<div class="clearWatermark">
去除水印
</div>
</div>
<div class="startAll" @click="startAllTasks">
开始转换
</div>
</div>
</template>
<script>
import { start, stop, clear, checkStatus } from './webApi'
export default {
name: 'TaskEdit',
components: {},
props: {},
data() {
return {
taskList: []
}
},
computed: {},
watch: {},
created() {
for (let i = 1; i < 10; i++) {
this.taskList.push({
cover: '',
name: '视频片段' + i,
duration: '10:00',
state: 0,
progress: 60,
outputFormat: 'mp4'
})
}
},
methods: {
async startTask(item) {
let result = await start()
if (result) {
item.state = 1
} else {
item.state = 2
}
},
async stopTask(item) {
let result = await stop()
if (result) {
item.state = 0
}
},
async clearTask(item) {
let result = await clear()
if (result) {
let index = this.taskList.indexOf(item)
if (index > -1) {
this.taskList.splice(index, 1)
}
}
},
async checkTaskStatus() {
await checkStatus()
},
addVideo() {
this.taskList.push({
cover: '',
name: '视频片段' + (this.taskList.length + 1),
duration: '10:00',
state: 0,
progress: 60,
outputFormat: 'mp4'
})
},
clearAllTasks() {
this.taskList = []
},
startAllTasks() {
this.taskList.forEach((task) => {
task.state = 1
})
}
}
}
</script>
<style scoped lang="scss">
.taskEdit {
width: 100%;
height: 100%;
background-color: #fff;
border: 0px solid black;
margin: 0px;
padding: 0 20px;
display: flex;
flex-direction: column;
align-items: center;
cursor: default;
overflow: hidden;
> ul {
width: 100%;
height: 100%;
border: 1px solid black;
flex-grow: 1;
overflow-y: auto;
> li {
padding: 5px 0;
height: 60px;
display: flex;
justify-content: space-between;
align-items: center;
}
> li:nth-of-type(odd) {
background-color: gainsboro;
}
.info {
display: flex;
align-items: center;
.cove {
width: 100px;
height: 40px;
background-color: #ccc;
line-height: 40px;
margin-right: 10px;
}
}
.operationPanel {
width: 300px;
height: 100%;
.wait {
height: 100%;
display: flex;
align-items: center;
.selectionFormat {
height: 30px;
width: 100px;
line-height: 30px;
border: 1px solid black;
margin-left: 20px;
}
.delete {
width: 60px;
height: 30px;
line-height: 30px;
background-color: black;
color: #fff;
margin-left: 20px;
}
}
.active {
height: 100%;
width: 300px;
display: flex;
align-items: center;
.progress {
}
.slide {
width: 200px;
height: 5px;
background: gray;
> div {
width: 120px;
height: 100%;
background-color: black;
}
}
.stop {
width: 60px;
height: 30px;
line-height: 30px;
background-color: black;
color: #fff;
margin-left: 20px;
}
}
}
}
.editBar {
position: relative;
height: 30px;
width: 100%;
margin: 20px 0;
.addVideo {
position: absolute;
left: 0;
height: 30px;
line-height: 30px;
border: 1px solid black;
}
.clearList {
position: absolute;
left: 100px;
height: 30px;
line-height: 30px;
border: 1px solid black;
}
.clearWatermark {
position: absolute;
right: 0;
height: 30px;
line-height: 30px;
border: 1px solid black;
}
}
.startAll {
height: 30px;
width: 100px;
background-color: black;
color: #fff;
line-height: 30px;
}
}
</style>
async function start() {
let result = await new Promise((resolve) => {
setTimeout(() => {
resolve(true)
}, 1000)
})
return result
}
async function stop() {
let result = await new Promise((resolve) => {
setTimeout(() => {
resolve(true)
}, 500)
})
return result
}
async function clear() {
let result = await new Promise((resolve) => {
setTimeout(() => {
resolve(true)
}, 500)
})
return result
}
async function checkStatus(fakeValue) {
let result = await new Promise((resolve) => {
setTimeout(() => {
resolve(fakeValue++)
}, 500)
})
return result
}
export { start, stop, clear, checkStatus }
<template>
<div class="video-change" @click="changeVideo">
替换视频
</div>
</template>
<script>
export default {
methods: {
changeVideo() {
this.$emit('changeVideo')
}
}
}
</script>
<style lang="scss" scoped>
.video-change {
width: 100px;
height: 30px;
line-height: 30px;
text-align: center;
border: 1px solid #dddddd;
border-radius: 4px;
user-select: none;
cursor: pointer;
}
</style>
<template>
<div class="video-control">
<div class="video-play-btn" @click="play()">
播放
</div>
<div class="video-time-content">
<div class="now-time">
{{ nowTime | formatTime }}
</div>
<span>/</span>
<div class="total-time">
{{ duration | formatTime }}
</div>
</div>
</div>
</template>
<script>
export default {
filters: {
formatTime(duration) {
if (duration <= 0) return '00:00'
if (!duration) return '--:--'
let min = ~~(duration / 60)
min = (min + '').length === 1 ? '0' + min : min
let sec = Math.floor(duration % 60)
sec = (sec + '').length === 1 ? '0' + sec : sec
min = min || '00'
sec = sec || '00'
return min + ':' + sec
}
},
props: ['duration', 'nowTime'], // eslint-disable-line
data() {
return {}
},
methods: {
play() {
this.$emit('play')
}
}
}
</script>
<style lang="scss" scoped>
.video-control {
display: flex;
justify-content: flex-start;
align-self: center;
width: 200px;
user-select: none;
}
.video-play-btn {
border: 1px solid #dddddd;
width: 30px;
height: 30px;
border-radius: 100%;
margin-right: 10px;
cursor: pointer;
}
.video-time-content {
display: flex;
> div,
span {
line-height: 30px;
color: #474261;
}
}
</style>
<template>
<div class="video-player">
<video ref="videoDom" src="https://resources.laihua.com/2020-7-27/547adf9b-73b0-4b14-bed6-6ee278a1b2b2.mp4"></video>
</div>
</template>
<script>
export default {
data() {
return {
state: 'pluse',
times: 0,
canPlay: false
}
},
mounted() {
this.$bus.on('videoPlayer.play', (data) => {
if (data.time !== undefined) {
this.currentTime(data.time)
}
if (data.play) {
this.play()
} else {
this.pause()
}
})
this.$nextTick(() => {
this.$refs.videoDom.addEventListener('canplay', this.canPlayFunc)
this.$refs.videoDom.addEventListener('ended', () => {
this.$emit('ended')
})
this.$refs.videoDom.addEventListener('timeupdate', () => {
this.$emit('timeupdate', this.$refs.videoDom.currentTime)
})
})
},
beforeDestroy() {
this.$refs.videoDom.removeEventListener('canplay')
this.$refs.videoDom.removeEventListener('ended')
this.$refs.videoDom.removeEventListener('timeupdate')
},
methods: {
canPlayFunc() {
this.canPlay = true
let from = this.$parent.$options.name || 'videoPlayer'
this.$bus.emit(`${from}.canPlay`, this.$refs.videoDom.duration)
},
play() {
if (!this.canPlay) return
this.$refs.videoDom.play()
},
pause() {
if (!this.canPlay) return
this.$refs.videoDom.pause()
},
currentTime(time) {
if (!this.canPlay) return
this.$refs.videoDom.currentTime = time
}
}
}
</script>
<style lang="scss" scoped>
.video-player {
display: flex;
justify-content: space-around;
align-items: center;
width: 100%;
height: 100%;
background-color: beige;
video {
max-width: 100%;
max-height: 100%;
}
}
</style>
<template>
<div class="video-timeline">
<div ref="sliderWidth" v-drag class="time-slider">
<div class="time-slider-rail"></div>
<div class="time-slider-track" :style="{ width: ((info.val - info.min) / info.max) * 100 + '%' }"></div>
<div data-action="handle" class="time-slider-handle" :style="{ left: ((info.val - info.min) / info.max) * 100 + '%' }"></div>
</div>
</div>
</template>
<script>
export default {
name: 'VideoTimeline',
directives: {
drag(el, binding, vnode) {
let _this = vnode.context,
mousemove = null,
mouseup = null,
dataAction = ''
mousemove = (e) => {
_this.dragMove && _this.dragMove(e.pageX, dataAction, e)
}
mouseup = (e) => {
document.removeEventListener('mousemove', mousemove)
document.removeEventListener('mouseup', mouseup)
_this.dragUp && _this.dragUp(e.pageX, dataAction, e)
}
el.onmousedown = (e) => {
dataAction = e.target.dataset.action
if (e.which === 3 || e.which === 2) {
e.stopPropagation()
return
}
document.addEventListener('mousemove', mousemove)
document.addEventListener('mouseup', mouseup)
_this.dragDown && _this.dragDown(e.pageX, dataAction, e)
}
}
},
props: {
info: {
type: Object,
required: true,
default: function() {
return { step: 0.1, min: 0, max: 10, val: 0, cut: [0, 10] }
}
}
},
data() {
return {
width: 100
}
},
methods: {
dragDown(dis, action) {
if (!action) return
this.width = this.$refs.sliderWidth.clientWidth
this.action = action
this.dragHand = true
this.mpos = {
x: dis,
v: this.info.val
}
this.$emit('changeData', { val: this.mpos.v, action: action, type: 'start' })
},
dragMove(pos) {
if (!this.action) return
let val = 0
console.log(pos, '<_-------------')
// let pre = Math.round(((pos.x - this.mpos.x) / 120 * this.item.len + this.mpos.v) / this.item.step) / (1 / this.item.step);
// this.item.val = pre > this.item.max ? this.item.max : pre < this.item.min ? this.item.min : pre;
this.$emit('changeData', { val: val, action: this.action, type: 'change' })
},
dragUp() {
if (!this.action) return
let val = 0
this.mpos = null
this.dragHand = false
this.action = ''
this.$emit('changeData', { val: val, action: this.action, type: 'end' })
}
}
}
</script>
<style lang="scss" scoped>
.video-timeline {
width: 100%;
height: 50px;
background-color: beige;
}
.time-slider {
position: relative;
height: 15px;
padding: 5px 0;
width: 100%;
margin-right: 1px;
-ms-touch-action: none;
touch-action: none;
-webkit-box-sizing: border-box;
box-sizing: border-box;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
* {
-webkit-box-sizing: border-box;
box-sizing: border-box;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
.time-slider-rail {
position: absolute;
width: 100%;
background-color: #d9ddea;
height: 4px;
border-radius: 3px;
}
.time-slider-track {
position: absolute;
background-color: #737596;
border-radius: 3px;
height: 4px;
left: 0%;
width: 69.1515%;
}
.time-slider-handle {
position: absolute;
margin-left: -6px;
margin-top: -4px;
left: 69.1515%;
width: 12px;
height: 12px;
background-color: #737596;
cursor: -webkit-grab;
cursor: grab;
border-radius: 50%;
-ms-touch-action: pan-x;
touch-action: pan-x;
}
}
</style>
<template>
<div class="comp-default-layout">
<common-header></common-header>
<body class="body-container">
<side-nav></side-nav>
<router-view style="flex:1;border: 1px solid #666;"> </router-view>
<right-panel></right-panel>
</body>
</div>
</template>
<script>
export default {
name: 'DefaultLayout',
components: {
CommonHeader: () => import('@/components/header/index.vue'),
SideNav: () => import('@/components/sideNav/index.vue'),
RightPanel: () => import('@/components/rightPanel/index.vue')
},
data() {
return {}
},
created() {},
mounted() {}
}
</script>
<style scoped lang="scss">
/* @import url(); 引入css类 */
.comp-default-layout {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
display: flex;
flex-direction: column;
height: 100vh;
position: relative;
}
.body-container {
flex: 1;
display: flex;
justify-content: space-between;
overflow: hidden;
}
</style>
import defaultLayout from '@/layout/default.vue'
import layoutA from '@/layout/layoutA.vue'
export default [defaultLayout, layoutA]
<template>
<div class="comp-default-layout">
<div class="comp-sidenav">
<router-link to="/">
Home
</router-link>
<router-link to="/about">
About
</router-link>
<router-link to="/bao2">
bao2
</router-link>
</div>
<router-view> </router-view>
</div>
</template>
<script>
export default {
name: 'LayoutA',
components: {},
data() {
return {}
},
created() {},
mounted() {}
}
</script>
<style scoped lang="scss">
/* @import url(); 引入css类 */
.comp-sidenav {
padding: 30px;
// width: 100px;
border: 1px solid skyblue;
height: 100%;
// display: flex;
a {
font-weight: bold;
color: #2c3e50;
display: inline-block;
width: 100%;
padding: 10px 0;
&.router-link-exact-active {
color: #42b983;
}
}
}
</style>
...@@ -7,6 +7,10 @@ import './assets/style/index.scss' ...@@ -7,6 +7,10 @@ import './assets/style/index.scss'
import axios from 'axios' import axios from 'axios'
import VueBus from 'vue-bus' import VueBus from 'vue-bus'
import VModal from 'vue-js-modal' import VModal from 'vue-js-modal'
import layoutComponents from '@/layout/index.js'
// 全局注册layout组件
layoutComponents.forEach((layout) => Vue.component(layout.name, layout))
Vue.use(VueBus) Vue.use(VueBus)
Vue.use(VModal) Vue.use(VModal)
......
import Vue from 'vue' import Vue from 'vue'
import VueRouter from 'vue-router' import VueRouter from 'vue-router'
import Bao3 from '../views/bao3.vue' // import Bao3 from '../views/bao3.vue'
import Screenshot from '../views/screenshot.vue'
import screenshotPanel from '../components/rightPanel/screenshotPanel.vue'
Vue.use(VueRouter) Vue.use(VueRouter)
...@@ -10,32 +8,28 @@ const routes = [ ...@@ -10,32 +8,28 @@ const routes = [
{ {
path: '/', path: '/',
name: 'Bao3', name: 'Bao3',
component: Bao3 meta: {
layout: 'DefaultLayout',
title: '首页'
},
component: () => import(/* webpackChunkName: "about" */ '../views/bao3.vue')
},
{
path: '/bao2',
name: 'Bao2',
component: () => import(/* webpackChunkName: "about" */ '../views/bao2.vue')
}, },
{ {
path: '/about', path: '/about',
name: 'About', name: 'About',
meta: {
layout: 'layout-a',
title: '页面1'
},
// route level code-splitting // route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route // this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited. // which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue') component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
},
{
path: '/cutter',
name: 'Cutter',
component: () => import(/* webpackChunkName: "bao1" */ '../views/videoCutter.vue')
},
{
path: '/videoConverter',
name: 'VideoConverter',
component: () => import(/* webpackChunkName: "bao2" */ '../views/videoConverter.vue')
},
{
path: '/screenshot',
components: {
default: Screenshot,
panel: screenshotPanel
}
} }
] ]
......
<template>
<div class="page-test">
test
</div>
</template>
<script>
export default {
data() {
return {}
}
}
</script>
<style scoped lang="scss">
/* @import url(); 引入css类 */
</style>
<template> <template>
<div class="about"> <div class="about">
<h1>This is an about page</h1> <!-- <default-layout></default-layout>
<layout-a></layout-a> -->
<h1>about</h1>
</div> </div>
</template> </template>
<script>
export default {
data() {
return {}
}
}
</script>
<template> <template>
<div class="comp-bao2"> <div class="comp-bao2">
bao2 <h2>bao2</h2>
</div> </div>
</template> </template>
......
<template> <template>
<div class="comp-bao2"> <div class="comp-bao2">
bao3 <h1>bao3</h1>
<!-- <img src="../assets/logo.png" alt=""> -->
</div> </div>
</template> </template>
......
<template>
<div class="screenshot">
<div class="content">
<video id="screenshot-video" width="400" height="300" :src="srcUrl" controls></video>
</div>
<div class="operate-area">
<div class="play-area">
<input id="screenshot-input" type="file" style="display:none;" @change="changeFile" />
<label id="select-btn">
<span>选择文件</span>
</label>
</div>
<div class="time-area">
<div id="ss-time-line">
<div class="track"></div>
</div>
</div>
<div class="clip-area"></div>
</div>
</div>
</template>
<script>
export default {
name: 'Screenshot',
data() {
return {
srcUrl: null,
videoEle: null,
current: 0,
duration: 10
}
},
created() {},
mounted() {
let input = document.getElementById('screenshot-input')
let fileBtn = document.getElementById('select-btn')
fileBtn.addEventListener('click', function() {
input.click()
})
let video = document.getElementById('screenshot-video')
video.onerror = function(e) {
console.log('onerror', e)
}
video.addEventListener('loadedmetadata', function(e) {
console.log('loadedmetadata', e)
//webkitVideoDecodedByteCount
if (e.target.webkitVideoDecodedByteCount < 1) {
console.error('格式不支持')
}
})
//loadedmetadata
},
methods: {
changeFile(e) {
//console.log('changeFile', e)
if (e.target.files[0]) {
this.srcUrl = URL.createObjectURL(e.target.files[0])
}
}
}
}
</script>
<style lang="scss" scoped>
.screenshot {
position: relative;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
.content {
height: 100%;
margin: 20px 30px;
background-color: lightcyan;
}
.operate-area {
background-color: aqua;
height: 200px;
display: flex;
flex-shrink: 0;
#select-btn {
background-color: bisque;
width: 100px;
height: 30px;
line-height: 30px;
}
}
}
</style>
<template>
<div class="videoConverter">
<taskEdit></taskEdit>
</div>
</template>
<script>
import taskEdit from '@/components/videoConverter/taskEdit'
export default {
name: 'VideoConverter',
components: { taskEdit },
props: {},
data() {
return {}
},
computed: {},
watch: {},
created() {},
methods: {}
}
</script>
<style scoped lang="scss">
.videoConverter {
width: 100%;
height: 800px;
background-color: #fff;
border: 0px solid black;
margin: 0px;
}
</style>
<template>
<div class="video-cutter">
<div class="video-content">
<videoPlayer @currentTime="changeTime" @end="playEnd" @timeupdate="timeupdate"></videoPlayer>
</div>
<div class="video-btn">
<videoChange @changeVideo="changeVideo"></videoChange>
<videoControl :duration="duration" :now-time="nowTime" @play="videoPlay"></videoControl>
<div class="video-water">
<input id="cutterRemoveWater" v-model="noWater" type="checkbox" />
<label for="cutterRemoveWater">去除ddf 水印</label>
</div>
</div>
<div class="timeline-content">
<videoTimeline :info="timelineObj"></videoTimeline>
</div>
<div></div>
</div>
</template>
<script>
export default {
name: 'VideoCutter',
components: {
VideoPlayer: () => import('@/components/videoCutter/videoPlayer.vue'),
VideoChange: () => import('@/components/videoCutter/videoChange.vue'),
VideoControl: () => import('@/components/videoCutter/videoControl.vue'),
VideoTimeline: () => import('@/components/videoCutter/videoTimeline.vue')
},
data() {
return {
name: '',
nowTime: 0,
duration: 0,
playing: false,
canPlay: false,
noWater: true,
timelineObj: { step: 0.1, min: 0, max: 10, val: 0 }
}
},
created() {},
mounted() {
this.$bus.on('VideoCutter.canPlay', this.canPlayFunc)
},
methods: {
changeVideo() {
console.log('todo change video, <-----lilei')
},
canPlayFunc(data) {
this.duration = data
this.timelineObj.max = this.duration
this.canPlay = true
},
videoPlay() {
if (!this.canPlay) return
let ob = {}
if (this.playing) {
ob.play = false
} else {
ob.play = true
if (this.nowTime >= this.duration) {
ob.time = 0
this.timelineObj.val = 0
}
}
this.playing = !this.playing
this.$bus.emit('videoPlayer.play', ob)
},
changeTime(data) {
console.log(data)
},
playEnd() {
this.playing = false
this.nowTime = this.duration
this.timelineObj.val = this.nowTime
},
timeupdate(time) {
this.nowTime = time
this.timelineObj.val = this.nowTime
}
}
}
</script>
<style scoped lang="scss">
/* @import url(); 引入css类 */
.video-cutter {
width: 100%;
height: 100%;
}
.video-content {
width: 100%;
height: 700px;
}
.video-btn {
display: flex;
justify-content: space-between;
}
.video-water {
display: flex;
align-items: center;
input {
margin-right: 4px;
}
* {
cursor: pointer;
}
}
.timeline-content {
width: 100%;
margin: 10px 0;
padding: 0 20px;
}
</style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment