feat:滚动标题

This commit is contained in:
李想 2025-04-23 17:15:41 +08:00
parent f7cdcce8cb
commit b71ba53a9c
16 changed files with 295 additions and 91 deletions

2
components.d.ts vendored
View File

@ -18,7 +18,6 @@ declare module 'vue' {
CustomEchartPictorialBar: typeof import('./src/components/custom-echart-pictorial-bar/index.vue')['default']
CustomEchartPie: typeof import('./src/components/custom-echart-pie/index.vue')['default']
CustomEchartPie3d: typeof import('./src/components/custom-echart-pie-3d/index.vue')['default']
CustomEchartPieCircle: typeof import('./src/components/custom-echart-pie-circle/index.vue')['default']
CustomEchartPieGauge: typeof import('./src/components/custom-echart-pie-gauge/index.vue')['default']
CustomEchartRadar: typeof import('./src/components/custom-echart-radar/index.vue')['default']
CustomEchartScatterBlister: typeof import('./src/components/custom-echart-scatter-blister/index.vue')['default']
@ -29,6 +28,7 @@ declare module 'vue' {
CustomRankList: typeof import('./src/components/custom-rank-list/index.vue')['default']
CustomRichEditor: typeof import('./src/components/custom-rich-editor/index.vue')['default']
CustomScrollBoard: typeof import('./src/components/custom-scroll-board/index.vue')['default']
CustomScrollTitle: typeof import('./src/components/custom-scroll-title/index.vue')['default']
CustomTableOperate: typeof import('./src/components/custom-table-operate/index.vue')['default']
CustomTableTree: typeof import('./src/components/custom-table-tree/index.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']

View File

@ -129,103 +129,90 @@ const handlePlay = () => {
</script>
<style lang="scss" scoped>
.carousel {
width: 100%;
display: flex;
width: 100%;
flex-direction: column;
&-container {
display: flex;
flex-direction: row;
align-items: center;
margin-top: 30px;
}
&-list {
flex: 3;
:deep(.el-scrollbar__bar) {
display: none !important;
}
:deep(.el-scrollbar__view) {
display: flex;
flex-direction: row;
align-items: center;
}
&-item {
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
align-items: center;
margin: 10px;
width: 100px;
height: 100px;
margin: 10px;
border: 2px solid #fff;
text-align: center;
border: 2px solid #ffffff;
border-radius: 4px;
background: var(--el-color-danger-light-9);
text-align: center;
color: var(--el-color-danger);
background: var(--el-color-danger-light-9);
flex-shrink: 0;
cursor: pointer;
&.active {
border-color: var(--el-color-primary);
}
}
}
&-arrow {
width: 50px;
text-align: center;
.el-icon {
display: inline-block;
margin: 0 auto;
width: 40px;
height: 40px;
margin: 0 auto;
line-height: 40px;
font-size: 32px;
line-height: 40px;
cursor: pointer;
}
}
&-video {
overflow: hidden;
position: relative;
overflow: hidden;
width: 100%;
height: 100%;
min-height: 300px;
&-picture {
position: absolute;
z-index: 10;
}
&-video {
position: absolute;
z-index: 11;
}
&-btn {
position: absolute;
left: 50%;
top: 50%;
left: 50%;
z-index: 12;
width: 50px;
height: 50px;
margin-left: -25px;
margin-top: -25px;
border-radius: 25px;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
background: rgba(0, 0, 0, 0.2);
margin-top: -25px;
margin-left: -25px;
width: 50px;
height: 50px;
border-radius: 25px;
background: rgb(0 0 0 / 20%);
flex-direction: row;
cursor: pointer;
.el-icon {
font-size: 32px;
color: #fff;
color: #ffffff;
}
}
}

View File

@ -91,12 +91,12 @@ defineExpose({
<style lang="scss" scoped>
.import {
&-tips {
@include flex-row();
@include flex-row;
align-items: center;
margin-bottom: 20px;
font-size: 14px;
color: #979797;
p {
flex: 3;
}

View File

@ -178,53 +178,46 @@ onUnmounted(() => {
<style lang="scss" scoped>
.go-tables-rank {
overflow: hidden;
width: 100%;
height: 100%;
overflow: hidden;
.row-item {
transition: all 0.3s;
display: flex;
flex-direction: column;
justify-content: center;
overflow: hidden;
transition: all 0.3s;
flex-direction: column;
}
.ranking-info {
display: flex;
align-items: center;
width: 100%;
font-size: 13px;
align-items: center;
.rank {
margin-right: 5px;
}
.info-name {
flex: 1;
}
}
.ranking-column {
border-bottom: 2px solid #1370fb80;
margin-top: 5px;
border-bottom: 2px solid #1370fb80;
.inside-column {
position: relative;
height: 6px;
margin-bottom: 2px;
border-radius: 1px;
overflow: hidden;
margin-bottom: 2px;
height: 6px;
border-radius: 1px;
}
.shine {
position: absolute;
left: 0%;
top: 2px;
height: 2px;
left: 0%;
width: 50px;
height: 2px;
background: radial-gradient(rgb(40 248 255) 5%, transparent 80%);
transform: translateX(-100%);
background: radial-gradient(rgb(40, 248, 255) 5%, transparent 80%);
animation: shine 3s ease-in-out infinite alternate;
}
}
@ -235,7 +228,6 @@ onUnmounted(() => {
left: 0;
transform: translateX(-100%);
}
100% {
left: 100%;
transform: translateX(0%);

View File

@ -157,8 +157,8 @@ export default {
</script>
<style lang="scss" scoped>
.rich-editor {
border: 1px solid $color-border;
z-index: 9999;
border: 1px solid $color-border;
&-toolbar {
border-bottom: 1px solid $color-border;
:deep(.w-e-bar-divider) {

View File

@ -332,34 +332,29 @@ onUnmounted(() => {
position: relative;
width: 100%;
height: 100%;
color: #fff;
color: #ffffff;
.text {
padding: 0 10px;
box-sizing: border-box;
white-space: nowrap;
overflow: hidden;
padding: 0 10px;
text-overflow: ellipsis;
white-space: nowrap;
box-sizing: border-box;
}
.header {
display: flex;
flex-direction: row;
font-size: 15px;
.header-item {
transition: all 0.3s;
}
}
.rows {
overflow: hidden;
.row-item {
display: flex;
overflow: hidden;
font-size: 14px;
transition: all 0.3s;
overflow: hidden;
}
}
}

View File

@ -0,0 +1,191 @@
<template>
<section class="header_title" :style="{ '--titleContentW': titleContentW + 'px', '--itemW': itemW + 'px', '--gap': gap + 'px' }">
<el-button icon="el-icon-arrow-left" class="left_btn" @click="handleTitleBtn(1)"></el-button>
<el-button icon="el-icon-arrow-right" class="right_btn" @click="handleTitleBtn(-1)"></el-button>
<section class="left_titles_container">
<section class="title_content" :style="{ left: `-${position}px` }">
<section
v-for="(item, i) in leftTitles"
:key="`left_title_${i}`"
:class="['title_item', activeTitle == item.value ? 'active' : '']"
@click="handleTitleClick(item.value)"
>
{{ item.label }}
</section>
</section>
</section>
<section class="right_titles_container">
<section class="title_content" :style="{ left: `${right ? right + 'px' : '-' + position + 'px'}` }">
<section
v-for="(item, i) in rightTitles"
:key="`right_title_${i}`"
:class="['title_item', activeTitle == item.value ? 'active' : '']"
@click="handleTitleClick(item.value)"
>
{{ item.label }}
</section>
</section>
</section>
</section>
</template>
<script setup>
import { ref, watch, onMounted } from 'vue';
onMounted(() => {
handleWidth();
});
const emit = defineEmits(['changeTitle']);
const props = defineProps({
titles: {
type: Array,
default() {
return [
{ label: '标题1', value: '1' },
{ label: '标题2', value: '2' },
{ label: '标题3', value: '3' },
{ label: '标题4', value: '4' },
{ label: '标题5', value: '5' },
{ label: '标题6', value: '6' },
{ label: '标题7', value: '7' },
{ label: '标题8', value: '8' },
{ label: '标题9', value: '9' },
{ label: '标题10', value: '10' },
{ label: '标题11', value: '11' },
{ label: '标题12', value: '12' },
{ label: '标题13', value: '13' },
{ label: '标题14', value: '14' },
{ label: '标题15', value: '15' },
{ label: '标题16', value: '16' },
{ label: '标题17', value: '17' },
{ label: '标题18', value: '18' },
{ label: '标题19', value: '19' },
];
},
},
});
const titleContentW = ref('0');
const itemW = ref('1');
const gap = ref(24);
const leftNum = ref(0);
const position = ref(0);
const right = ref(null);
const activeTitle = ref('1');
const leftTitles = ref([]);
const rightTitles = ref([]);
watch(
() => props.titles,
(val) => {
if (val && val.length) {
let l = val.length;
if (l > 6) {
leftTitles.value = val.slice(0, l - 3);
rightTitles.value = val.slice(3);
} else {
leftTitles.value = val.slice(0, 3);
if (l > 3) {
rightTitles.value = val.slice(3);
}
}
}
},
{
deep: true,
immediate: true,
}
);
function handleWidth() {
let ld = document.querySelector('.left_titles_container');
let w = ld.clientWidth;
itemW.value = (w - 2 * gap.value) / 3;
titleContentW.value = itemW.value * leftTitles.value.length + leftTitles.value.length * gap.value;
if (props.titles.length > 3 && props.titles.length < 6) {
let l = 3 - (props.titles.length - 3);
right.value = l * itemW.value + (l - 1) * gap.value;
}
}
function handleTitleBtn(t = -1) {
if (props.titles.length > 6) {
if (leftNum.value > -1) leftNum.value = leftNum.value + t;
if (leftNum.value < 0) leftNum.value = 0;
if (leftNum.value > leftTitles.value.length - 3) leftNum.value = leftTitles.value.length - 3;
position.value = leftNum.value * itemW.value + leftNum.value * gap.value;
}
}
function handleTitleClick(val) {
activeTitle.value = val;
emit('changeTitle', val);
}
</script>
<style lang="scss" scoped>
* {
box-sizing: border-box;
}
.header_title {
background-color: #f5f5f5;
position: relative;
padding: 0 68px;
display: flex;
justify-content: space-between;
width: 100vw;
height: 60px;
// background: url('./headerBG.png') no-repeat center/cover;
background-color: skyblue;
.left_btn,
.right_btn {
position: absolute;
top: 15px;
padding: 6px 6px;
width: 30px;
height: 30px;
background-color: rgb(39, 172, 255);
border-radius: 8px;
cursor: pointer;
z-index: 1;
user-select: none;
color: #fff;
font-weight: bold;
}
.left_btn {
left: 14px;
}
.right_btn {
right: 14px;
}
.left_titles_container,
.right_titles_container {
position: relative;
width: 30%;
height: 60px;
overflow: hidden;
.title_content {
position: absolute;
top: 10px;
width: var(--titleContentW);
height: 40px;
transition: all 0.4s ease;
font-size: 20px;
font-weight: bold;
color: #f5f5f5;
.active {
color: #fff;
text-shadow: 1px 1px 2px red;
}
.title_item {
margin-right: var(--gap);
display: inline-block;
width: var(--itemW);
height: 40px;
line-height: 40px;
text-align: center;
// background: url('./titleBG.png') no-repeat center/cover;
background-color: aquamarine;
cursor: pointer;
user-select: none;
}
}
}
}
</style>

View File

@ -86,33 +86,28 @@ const handleNodeClick = (data, node) => {
<style lang="scss" scoped>
.custom-table-tree {
width: 100%;
min-width: 200px;
height: 100%;
min-height: 400px;
min-width: 200px;
@include flex-column();
@include flex-column;
&__shadow {
box-shadow: 2px 0px 5px rgba(0, 0, 0, 0.1);
box-shadow: 2px 0 5px rgb(0 0 0 / 10%);
}
.title {
height: 36px;
padding: 0 20px;
line-height: 36px;
border-radius: 4px;
height: 36px;
font-size: 16px;
color: #fff;
border-radius: 4px;
color: #ffffff;
background: var(--el-color-primary);
line-height: 36px;
}
.panel {
padding: 16px 10px 10px;
&-filter {
margin-bottom: 10px;
}
}
.el-tree {
box-sizing: border-box;
}

View File

@ -19,6 +19,7 @@ import CustomEchartPieGauge from './custom-echart-pie-gauge';
import CustomEchartWordCloud from './custom-echart-word-cloud';
import customEchartScatterBlister from './custom-echart-scatter-blister';
import customEchartMaps from './custom-echart-maps';
import customScrollTitle from './custom-scroll-title';
export {
SvgIcon,
@ -42,4 +43,5 @@ export {
CustomEchartWordCloud,
customEchartScatterBlister,
customEchartMaps,
customScrollTitle,
};

View File

@ -66,16 +66,15 @@ const styleExternalIcon = computed(() => {
<style scoped>
.svg-icon {
overflow: hidden;
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
fill: currentcolor;
}
.svg-external-icon {
background-color: currentColor;
mask-size: cover !important;
display: inline-block;
background-color: currentcolor;
mask-size: cover !important;
}
</style>

View File

@ -32,6 +32,12 @@ export const constantRoutes = [
// ],
// },
...demoRouters,
{
path: '/test',
name: 'test',
component: () => import('@/views/test/index.vue'),
hidden: true,
},
];
/**

View File

@ -1,6 +1,5 @@
@import 'common/base';
@import 'common/define';
#app {
position: relative;
width: 100%;
@ -8,8 +7,9 @@
font-family: Avenir, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background-color: #fff;
background-color: #ffffff;
}
// .el-dialog__body {
// overflow: hidden auto;
// height: auto;

View File

@ -52,12 +52,11 @@ const options = ref({
</script>
<style lang="scss" scoped>
.demo {
width: 500px;
height: 500px;
margin: 30px auto 0;
padding: 50px;
background-color: #999;
width: 500px;
height: 500px;
background-color: #999999;
&-title {
margin-bottom: 20px;
}

View File

@ -38,11 +38,10 @@ const boardOption = ref({
</script>
<style lang="scss" scoped>
.demo {
margin: 30px auto 0;
width: 500px;
height: 500px;
margin: 30px auto 0;
background-color: #fff;
background-color: #ffffff;
&-title {
margin-bottom: 20px;
}

27
src/views/test/index.vue Normal file
View File

@ -0,0 +1,27 @@
<template>
<section class="test_container">
<customScrollTitle />
</section>
</template>
<script setup>
import { ref } from 'vue';
/* --------------- data --------------- */
// #region
// #endregion
/* --------------- methods --------------- */
// #region
// #endregion
</script>
<style lang="scss" scoped>
.test_container {
width: 100vw;
height: 100vh;
background-color: #f5f5f5;
}
</style>

View File

@ -6611,6 +6611,18 @@ vue-demi@*, vue-demi@^0.14.10:
resolved "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.10.tgz#afc78de3d6f9e11bf78c55e8510ee12814522f04"
integrity sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==
vue-demi@^0.13.11:
version "0.13.11"
resolved "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.11.tgz#7d90369bdae8974d87b1973564ad390182410d99"
integrity sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==
vue-echarts@^7.0.3:
version "7.0.3"
resolved "https://registry.npmmirror.com/vue-echarts/-/vue-echarts-7.0.3.tgz#bf79f7ee0144bbdc6aee5610e8443fed91f6abbe"
integrity sha512-/jSxNwOsw5+dYAUcwSfkLwKPuzTQ0Cepz1LxCOpj2QcHrrmUa/Ql0eQqMmc1rTPQVrh2JQ29n2dhq75ZcHvRDw==
dependencies:
vue-demi "^0.13.11"
vue-eslint-parser@^9.4.3:
version "9.4.3"
resolved "https://registry.npmmirror.com/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz#9b04b22c71401f1e8bca9be7c3e3416a4bde76a8"