VueMastery

$ npm install element-plus --save # 安装 element-plus 组件库
$ npm install -D unplugin-vue-components unplugin-auto-import # 安装自动导入插件
$ npm install -D sass # 安装 sass 预处理器工具
注意
main.ts
中引入自定义的主题样式文件 styles/element/index.scss
即可。// src/styles/element/index.scss
/* 只需要重写你需要的即可 */
@forward "element-plus/theme-chalk/src/common/var.scss" with (
$colors: (
"white": #ffffff,
"black": #000000,
"primary": (
"base": #0d6efd
),
"success": (
"base": #20c997
),
"warning": (
"base": #ffc107
),
"danger": (
"base": #e03f4f
),
"error": (
"base": #ce2929
),
"info": (
"base": #09b2d4
)
)
);
// 导入element-plus index.scss源文件来进行主题合并编译
@use "element-plus/theme-chalk/src/index.scss" as *;
import './styles/element/index.scss'
import ElementPlus from 'element-plus'
const app = createApp(App)
app.use(ElementPlus)
<script setup lang='ts'>
</script>
<template>
<div>
<el-button type="info">Click</el-button>
<el-button type="primary">Click</el-button>
<el-button type="success">Click</el-button>
<el-button type="danger">Click</el-button>
<el-button type="warning">Click</el-button>
</div>
</template>
<style scoped lang='scss'></style>
注意
vite.config.ts
文件, main.ts
中不再需要进行任何引入。亲测有效!// src/styles/element/index.scss
/* 只需要重写你需要的即可 */
@forward "element-plus/theme-chalk/src/common/var.scss" with (
$colors: (
"white": #ffffff,
"black": #000000,
"primary": (
"base": #0d6efd
),
"success": (
"base": #20c997
),
"warning": (
"base": #ffc107
),
"danger": (
"base": #e03f4f
),
"error": (
"base": #ce2929
),
"info": (
"base": #09b2d4
)
)
);
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// 自动导入
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
// use unplugin-auto-import
AutoImport({
resolvers: [ElementPlusResolver()],
}),
// // use unplugin-vue-components
Components({
resolvers: [
ElementPlusResolver({
importStyle: "sass",
}),
],
}),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
},
},
// use vite-plugin-windicss
css: {
preprocessorOptions: {
scss: {
additionalData: `@use "@/styles/element/index.scss" as *;`,
},
},
}
})
<script setup lang='ts'>
</script>
<template>
<div>
<el-button type="info">Click</el-button>
<el-button type="primary">Click</el-button>
<el-button type="success">Click</el-button>
<el-button type="danger">Click</el-button>
<el-button type="warning">Click</el-button>
</div>
</template>
<script setup lang='ts'>
import { onMounted, ref, watch } from 'vue';
import { Direction, Position, type DirectionOption } from '../types';
// 渐变方向
const direction = ref<Direction>(Direction.bottom);
// 遍历 Direction, 将其转换为 options
const options = ref<DirectionOption[]>([
{
label: Position.top,
value: Direction.top
},
{
label: Position.bottom,
value: Direction.bottom
},
{
label: Position.left,
value: Direction.left
},
{
label: Position.right,
value: Direction.right
},
{
label: Position.leftBottom,
value: Direction.leftBottom
},
{
label: Position.rightTop,
value: Direction.rightTop
},
{
label: Position.leftTop,
value: Direction.leftTop
},
{
label: Position.rightBottom,
value: Direction.rightBottom
}
]);
// related to the div element
const div = ref<HTMLDivElement | null>(null);
// 开始颜色
const startColor = ref<string>('#27ae60');
// 结束颜色
const endColor = ref<string>('#e74c3c');
watch(direction, () => {
div.value!.style.background = `linear-gradient(to ${direction.value}, ${startColor.value}, ${endColor.value})`;
});
onMounted(() => {
div.value!.style.width = '400px';
div.value!.style.height = '200px';
div.value!.style.background = `linear-gradient(to ${direction.value}, ${startColor.value}, ${endColor.value})`;
})
</script>
<template>
<div style="display: flex; justify-content:space-between;">
<div ref="div" style="text-align: center; line-height: 100px;">
{{ `linear-gradient(to ${direction}, ${startColor}, ${endColor})` }}
</div>
<el-select v-model="direction" placeholder="渐变方向" size="large" style="width: 240px; margin-right: 10px;">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
</template>
<style scoped lang='scss'></style>
<script setup lang="ts"></script>
<template>
<div class="dice-box">
<div class="dice">
<div class="face">1</div>
<div class="face">2</div>
<div class="face">3</div>
<div class="face">4</div>
<div class="face">5</div>
<div class="face">6</div>
</div>
</div>
</template>
<style scoped lang="scss">
@use 'sass:math';
@use 'sass:list';
@use 'sass:map';
.dice-box {
width: 200px;
height: 200px;
margin: 80px auto;
}
@mixin d-flex {
display: flex;
justify-content: center;
align-items: center;
}
$colors: (
1: #3498db,
2: #e74c3c,
3: #f1c40f,
4: #9b59b6,
5: #34495e,
6: #e67e22,
);
$size: (200px, 200px);
$font-size: 60px;
// 生成随机角度
@function randomAngle() {
@return math.random($limit: 360) + deg;
}
// 骰子随机旋转
@keyframes randomRotate {
25% {
transform: rotateX(randomAngle()) rotateY(randomAngle()) rotateZ(randomAngle());
}
50% {
transform: rotateX(randomAngle()) rotateY(randomAngle()) rotateZ(randomAngle());
}
75% {
transform: rotateX(randomAngle()) rotateY(randomAngle()) rotateZ(randomAngle());
}
}
.dice {
@include d-flex;
position: relative;
width: list.nth($size, 1);
height: list.nth($size, 2);
transform-style: preserve-3d;
transform: perspective(900px) rotateX(-30deg);
animation: randomRotate 1s forwards infinite;
@for $i from 1 through 6 {
.face:nth-child(#{$i}) {
position: absolute;
width: inherit;
height: inherit;
background: map.get($colors, $i);
line-height: list.nth($list: $size, $n: 1);
font-size: $font-size;
color: #fff;
text-align: center;
}
}
// 对每个面进行旋转定位成骰子立方体的每个面
// 将每个面旋转到立方体的每个面
// 利用for循环快速生成每个面
@for $i from 1 through 6 {
.face:nth-child(#{$i}) {
@if $i ==1 {
transform: rotateX(90deg) translateZ(calc(list.nth($size, 1) / 2));
}
@if $i ==2 {
transform: rotateY(90deg) translateZ(calc(list.nth($size, 1) / 2));
}
@if $i ==3 {
transform: rotateY(-90deg) translateZ(calc(list.nth($size, 1) / 2));
}
@if $i ==4 {
transform: rotateX(-90deg) translateZ(calc(list.nth($size, 1) / 2));
}
@if $i ==5 {
transform: rotateY(180deg) translateZ(calc(list.nth($size, 1) / 2));
}
@if $i ==6 {
transform: rotateX(0deg) translateZ(calc(list.nth($size, 1) / 2));
}
}
}
}
</style>
<template>
<input type="checkbox" class="space" data-before="开启 " data-after=" 探索" />
</template>
<style scoped lang='scss'>
// 太空
.space {
$width: 100%;
$height: 300px;
display: block;
// 清除默认外观效果
appearance: none;
width: $width;
height: $height;
background: url("https://pic3.zhimg.com/v2-1c2ecf961f50e792dad16c3709e9652a_r.jpg") no-repeat;
background-size: cover;
overflow: hidden;
transform-style: preserve-3d;
transform: perspective(1000px);
// 做一扇门
&::before,
&::after {
content: '';
line-height: $height;
display: block;
color: #fff;
letter-spacing: 0.5rem;
font-size: 3rem;
width: calc($width / 2);
height: $height;
background: #34495e;
transition: 3s;
text-shadow: 1px 1px 10px blueviolet;
}
&::before {
content: attr(data-before);
text-align: right;
position: absolute;
top: 0;
left: 0;
border-right: 3px solid #2c3e50;
transform-origin: left bottom;
}
&::after {
content: attr(data-after);
position: absolute;
top: 0;
left: 50%;
border-left: 3px solid #2c3e50;
transform-origin: right bottom;
}
&:checked {
&::before {
text-shadow: -5px -5px 10px rgb(218, 10, 124);
opacity: 0.95;
transform: rotateY(90deg) skewY(5deg);
border-color: transparent;
}
&::after {
text-shadow: -5px -5px 10px rgb(218, 10, 124);
opacity: 0.95;
transform: rotateY(90deg) skewY(-5deg);
border-color: transparent;
}
}
}
</style>
1rem
<template>
<div class="controller">
<h3>行间距</h3>
<input type="range" min="0" max="10" step="0.05" v-model="rowSpan" />
<p>{{ rowSpan }}rem</p>
<h3>列间距</h3>
<input type="range" min="0" max="10" step="0.05" v-model="columnSpan" />
<p class="mt-3">
<el-button @click="mergeAandB">合并列</el-button>
</p>
<p class="mt-3">
<el-button @click="mergeCandD">合并行</el-button>
</p>
<p class="mt-3">
<el-button @click="mergeFandG">合并行和列</el-button>
</p>
</div>
<div class="grid-layout" ref="gridContainer">
<div class="item" ref="item1">1</div>
<div class="item" ref="item2">2</div>
<div class="item">3</div>
<div class="item" ref="item4">4</div>
<div class="item">5</div>
<div class="item" ref="item6">6</div>
<div class="item" ref="item7">7</div>
<div class="item" ref="item8">8</div>
<div class="item">9</div>
<div class="item" ref="item10">10</div>
<div class="item" ref="item11">11</div>
<div class="item">12</div>
<div class="item">13</div>
<div class="item">14</div>
<div class="item">15</div>
<div class="item">16</div>
</div>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
const gridContainer = ref<HTMLDivElement | null>(null)
// 合并 1 和 2 网格元素: 合并行
const item1 = ref<HTMLDivElement | null>(null)
const item2 = ref<HTMLDivElement | null>(null)
// 合并 4 和 8 网格元素: 合并列
const item4 = ref<HTMLDivElement | null>(null)
const item8 = ref<HTMLDivElement | null>(null)
// 合并 6 和 7, 10 和 11 网格元素: 合并行和列
const item6 = ref<HTMLDivElement | null>(null)
const item7 = ref<HTMLDivElement | null>(null)
const item10 = ref<HTMLDivElement | null>(null)
const item11 = ref<HTMLDivElement | null>(null)
const rowSpan = ref(1)
const columnSpan = ref(1)
watch([rowSpan, columnSpan], ([row, column]) => {
// 设置行间距
gridContainer.value?.style.setProperty('grid-row-gap', `${row}rem`)
// 设置列间距
gridContainer.value?.style.setProperty('grid-column-gap', `${column}rem`)
})
// 合并 1 和 2 网格元素: 合并行方法
const mergeAandB = () => {
item2.value?.style.setProperty('display', 'none')
item1.value?.style.setProperty('grid-column', 'span 2')
}
// 合并 4 和 8 网格元素: 合并列方法
const mergeCandD = () => {
item8.value?.style.setProperty('display', 'none')
item4.value?.style.setProperty('grid-row', 'span 2')
}
// 合并 6 和 7, 10 和 11 网格元素: 合并行和列方法
const mergeFandG = () => {
item7.value?.style.setProperty('display', 'none')
item10.value?.style.setProperty('display', 'none')
item11.value?.style.setProperty('display', 'none')
// 或者 span 行数 / span 列数
item6.value?.style.setProperty('grid-area', 'span 2 / span 2')
}
</script>
<style scoped lang="scss">
@use 'sass:list';
@use 'sass:math';
.controller {
width: 200px;
height: 100%;
margin-top: 1rem;
}
.grid-layout {
width: 600px;
height: 500px;
display: grid;
grid-template-rows: repeat(4, 1fr); // 父盒子分成多少行, 每行的高度是1fr, 1fr表示剩余空间的比例, 1fr表示平均分配多少份
grid-template-columns: repeat(4, 1fr);
// gap: 1rem 1.5rem; // 行、列间距的简写, 可以简写一个值
grid-row-gap: 1rem; // 行间距
grid-column-gap: 1rem; // 列间距
transition: 0.5s;
> .item {
display: flex;
justify-content: center;
align-items: center;
background: #e67e22;
color: #fff;
font-size: 1rem;
border-radius: 5px;
transition: all 0.5s;
}
}
@for $i from 0 to 16 {
.item:nth-child(#{$i + 1}) {
// background: hsl(calc($i * 40%), 100%, 74%);
/** 将上面的计算换一种方式, 因为 sass 不支持 calc 运算符 */
background: hsl(calc(#{$i} * 40%), 100%, 74%);
}
.grid-layout:has(.item:nth-child(#{$i + 1}):hover) {
$r: math.floor(calc($i / 4 + 1));
$c: $i % 4 + 1;
$arr: 1fr 1fr 1fr 1fr;
$rows: list.set-nth($arr, $r, 2fr);
$columns: list.set-nth($arr, $c, 2fr);
grid-template-rows: $rows;
grid-template-columns: $columns;
}
}
</style>
<template>
<div class="starsky-container">
<div class="layer1"></div>
<div class="layer2"></div>
<div class="layer3"></div>
<div class="title">Sass 绘制的星空</div>
</div>
</template>
<style scoped lang="scss">
@use 'sass:math';
@use 'sass:list';
@use 'sass:string';
/* 获取随机颜色 */
@function randomColor() {
$r: math.random(255);
$g: math.random(255);
$b: math.random(255);
@return rgb($r, $g, $b);
}
/* 盒子阴影设置 */
@function getShadows(
$n: 500,
$bound-sizes: (
400px,
300px,
)
) {
$bound-width: list.nth(
$list: $bound-sizes,
$n: 1,
);
$bound-height: list.nth(
$list: $bound-sizes,
$n: 2,
);
$shadows: '#{math.random($bound-width)}px #{math.random($bound-height)}px #{randomColor()}';
@for $i from 2 through $n {
$shadows: '#{$shadows},#{math.random($bound-width)}px #{math.random($bound-height)}px #{randomColor()}';
}
@return string.unquote($shadows);
}
.starsky-container {
/** 边界宽高 */
$sizes: (700, 300) !default;
/*动画时长*/
$duration: 100s;
/* 亮点数量 */
$count: 1500;
position: relative;
// Dart 3.0.0 不再支持
width: #{list.nth($list: $sizes, $n: 1)}px;
height: #{list.nth($list: $sizes, $n: 2)}px;
overflow: hidden;
/* 标题*/
.title {
// 当鼠标移动到元素上时 显示指针的形状
touch-action: none;
user-select: none;
cursor: default;
position: absolute;
top: 50%;
left: 0;
right: 0;
color: #fff;
text-align: center;
font-family: 'Arial', 'sans-serif';
font-size: 26px;
letter-spacing: 10px;
margin-top: -60px;
padding-left: 10px;
line-height: #{calc(list.nth($sizes, 2) / 2)}px;
background: linear-gradient(to top, white, #38495a);
background-clip: text;
-webkit-background-clip: text;
-webkit-background-clip: text;
color: transparent;
}
@for $i from 1 through 3 {
$duration: math.floor(math.div($duration, 2));
$count: math.floor(math.div($count, 2));
.layer#{$i} {
$size: #{$i}px;
// position: fixed;
position: relative;
width: $size;
height: $size;
border-radius: 50%;
background: #f40;
left: 0;
top: 0;
box-shadow: getShadows($count, $sizes);
animation: moveUp $duration linear infinite;
&::after {
content: '';
position: fixed;
left: 0;
top: 300px;
width: $size;
height: $size;
border-radius: inherit;
box-shadow: inherit;
}
}
}
@keyframes moveUp {
100% {
transform: translateY(-#{list.nth($list: $sizes, $n: 2)}px);
}
}
}
</style>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
width: 100vw;
height: 100vh;
/* background-color: #334455; */
position: relative;
}
.pointer,
.pointer::after,
.pointer::after::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.pointer {
width: 100px;
height: 100px;
border: 1px solid rgb(239, 239, 239);
border-radius: 50%;
position: absolute;
animation: 0.8s ease-in-out 1 scale;
background-color: rgba(255, 255, 255, 0.7);
transition: all 0.4s;
}
.pointer::after {
content: '';
display: block;
width: 100px;
height: 100px;
border: 1px solid rgb(239, 239, 239);
border-radius: 50%;
position: absolute;
animation: 0.8s ease-in 1 alternate scale;
transition: all 0.8s;
background-color: rgba(255, 255, 255, 0.8);
}
.pointer::after::after {
content: '';
display: block;
width: 100px;
height: 100px;
border: 1px solid rgb(239, 239, 239);
border-radius: 50%;
position: absolute;
animation: 0.7s ease-out 0.1s 1 alternate scale;
transition: all 0.8s;
background-color: rgba(255, 255, 255, 0.9);
}
@keyframes scale {
0% {
opacity: 0;
transform: scale(0);
border-color: rgba(255, 255, 255, 0.2);
}
100% {
opacity: 0.5;
transform: scale(1);
border-color: rgba(255, 255, 255, 0.1);
background-color: transparent;
}
}
</style>
</head>
<body>
<div class="layer1"></div>
<div class="layer2"></div>
<div class="layer3"></div>
<div class="title">Sass 星空</div>
<script>
window.addEventListener("click", (e) => {
const pointer = document.createElement("div");
pointer.classList.add("pointer");
/**获取元素的宽高, 计算点击的是元素的中心位置 */
// 获取元素宽高
const { width, height } = pointer.getBoundingClientRect();
pointer.style.left = `${e.clientX - 50}px`;
pointer.style.top = `${e.clientY - 50}px`;
document.body.appendChild(pointer);
pointer.addEventListener("animationend", () => {
pointer.remove();
});
});
</script>
</body>
</html>
html {
height: 100%;
background: radial-gradient(ellipse at bottom, #1b2735 0%, #090a0f 100%);
overflow: hidden;
}
/* 标题*/
.title {
// 当鼠标移动到元素上时 显示指针的形状
touch-action: none;
user-select: none;
cursor: default;
position: absolute;
top: 50%;
left: 0;
right: 0;
color: #fff;
text-align: center;
font-family: "Arial", "sans-serif";
font-size: 50px;
letter-spacing: 10px;
margin-top: -60px;
padding-left: 10px;
background: linear-gradient(white, #38495a);
background-clip: text;
-webkit-background-clip: text;
-webkit-background-clip: text;
color: transparent;
}
/* 盒子阴影设置 */
@function getShadows($n) {
$shadows: "#{random(100)}vw #{random(100)}vh #{randomColor()}";
@for $i from 2 through $n {
$shadows: "#{$shadows},#{random(100)}vw #{random(100)}vh #{randomColor()}";
}
@return unquote($shadows);
}
/* 获取随机颜色 */
@function randomColor() {
$r: random(255);
$g: random(255);
$b: random(255);
@return rgb($r, $g, $b);
}
/*动画时长*/
$duration: 100s;
/* 亮点数量 */
$count: 1500;
@for $i from 1 through 3 {
$duration: floor($duration / 2);
$count: floor($count / 2);
.layer#{$i} {
$size: #{$i}px;
position: fixed;
width: $size;
height: $size;
border-radius: 50%;
background: #f40;
left: 0;
top: 0;
box-shadow: getShadows($count);
animation: moveUp $duration linear infinite;
&::after {
content: "";
position: fixed;
left: 0;
top: 100vh;
width: $size;
height: $size;
border-radius: inherit;
box-shadow: inherit;
}
}
}
@keyframes moveUp {
100% {
transform: translateY(-100vh);
}
}
<script setup lang='ts'>
import { ref } from 'vue'
</script>
<template>
<div class="heart heartbeat" style="margin: 0 auto;"></div>
</template>
<style scoped lang='scss'>
@keyframes heartbeat {
from {
opacity: 0.2;
}
25% {
opacity: 1;
transform: rotate(45deg) scale(0.35);
}
50% {
transform: rotate(45deg) scale(0.5);
}
75% {
opacity: 1;
transform: rotate(45deg) scale(0.35);
}
to {
transform: rotate(45deg) scale(0.5);
}
}
.heart {
width: 200px;
height: 200px;
background-color: #e74c3c;
position: relative;
transform: rotate(45deg) scale(0.5);
&.heartbeat {
animation-name: heartbeat;
animation-duration: 1s;
animation-iteration-count: infinite;
animation-timing-function: ease-in-out;
animation-direction: reverse;
}
&::before,
&::after {
content: '';
width: 200px;
height: 200px;
border-radius: 100%;
position: absolute;
}
&::before {
background-color: inherit;
transform: translateY(-50%);
}
&::after {
background-color: inherit;
transform: translateX(-50%);
}
}
</style>
<template>
<h1 class="demo">Hello world!</h1>
</template>
<style scoped lang='scss'>
@mixin textDecoration( // solid, double, dotted, dashed, wavy
$textLine: wavy,
// none, underline, overline, line-throughd, blink
$textStyle: underline,
// 颜色
$textColor: red,
// 文本下划线的偏移量
$textOffset: 0.5em,
// 文本渐变颜色
$backgroundImage: linear-gradient(to right, red, green, blue)) {
// 设置下划线的样式
text-decoration: $textLine $textStyle $textColor;
// 设置下划线的偏移量
text-underline-offset: $textOffset;
// 设置下划线渐变颜色
background-image: transparent;
}
/** 使用伪元素设置文本下划线 */
@mixin textDecorationPseudo {
color: linear-gradient(to right, red, blue);
width: max-content;
&::after {
content: "";
display: block;
width: 100%;
height: 1px;
background: linear-gradient(to right, red, green, blue);
}
}
.demo {
@include textDecoration;
}
</style>
<script setup lang='ts'>
import { ref } from 'vue'
</script>
<template>
<div class="taiji"></div>
</template>
<style scoped lang='scss'>
.taiji {
--taiji-width: 300px;
--taiji-height: 300px;
resize: both;
width: var(--taiji-width);
height: var(--taiji-height);
background: #eee;
/** 这两项配合可以实现用户自己放大缩小盒子 */
resize: both;
overflow: auto;
}
</style>
哪个容器盒子要实现平滑滚动,就给哪个盒子添加该属性
html {
scroll-behavior: smooth;
}
<script setup lang='ts'>
import { ref } from 'vue'
</script>
<template>
<div class="cube" style="--cube-width: 300px; --cube-height: 300px;">
<div style="--position: 1"></div>
<div style="--position: 2"></div>
<div style="--position: 3"></div>
<div style="--position: 4"></div>
<div style="--position: 5"></div>
<div style="--position: 6"></div>
</div>
</template>
<style scoped lang='scss'>
@property --last-counter {
syntax: "<integer>";
inherits: false;
initial-value: 4;
}
@property --angle {
syntax: "<angle>";
inherits: false;
initial-value: calc(360deg / 4);
}
@property --transform-origin {
syntax: "<angle>";
inherits: true;
initial-value: 90deg;
}
@keyframes CubeAutoPlay {
to {
transform: perspective(1000px) rotateX(-30deg) rotateY(360deg) rotateZ(360deg);
}
}
.cube {
position: relative;
width: var(--cube-width, 300px);
height: var(--cube-height, 300px);
/* background: #34495e; */
/* border: 1px solid black; */
margin: 200px auto;
transform-style: preserve-3d;
transform: perspective(1000px) rotateX(calc(var(--transform-origin)));
animation: CubeAutoPlay 3s linear infinite alternate;
/* -webkit-box-reflect: below 0px linear-gradient(transparent, rgba(0, 0, 0, 0.2)); */
>div {
position: absolute;
top: 0;
left: 0;
width: inherit;
height: inherit;
background-size: cover;
background-repeat: no-repeat;
&:nth-child(1) {
background-color: #1abc9c;
background-image: url('https://picsum.photos/300/300?random=1');
transform: rotateY(calc(var(--angle) * calc(var(--position) - 1))) translateZ(calc(var(--cube-width) / 2));
}
&:nth-child(2) {
background-color: #2ecc71;
background-image: url('https://picsum.photos/300/300?random=2');
transform: rotateY(calc(var(--angle) * calc(var(--position) - 1))) translateZ(calc(var(--cube-width) / 2));
}
&:nth-child(3) {
background-color: #3498db;
background-image: url('https://picsum.photos/300/300?random=3');
transform: rotateY(calc(var(--angle) * calc(var(--position) - 1))) translateZ(calc(var(--cube-width) / 2));
}
&:nth-child(4) {
background-color: #e67e22;
background-image: url('https://picsum.photos/300/300?random=4');
transform: rotateY(calc(var(--angle) * calc(var(--position) - 1))) translateZ(calc(var(--cube-width) / 2));
}
&:nth-child(5) {
background-color: #e74c3c;
background-image: url('https://picsum.photos/300/300?random=5');
transform: rotateX(calc(-1 * var(--transform-origin))) translateZ(calc(-1 * var(--cube-width) / 2));
}
&:nth-child(6) {
background-color: #f39c12;
background-image: url('https://picsum.photos/300/300?random=6');
transform: translateY(calc(var(--cube-height) / 2)) rotateX(calc(var(--transform-origin)));
}
}
}
</style>
@property --last-counter {
/** 规定这个值的类型, 当允许外部修改时, 如果修改的值类型不属于规定的数据类型, 将不会生效, "*" 表示允许所有的值 */
syntax: "<integer>";
/** 是否允许外部修改该属性 */
inherits: false;
/** 初始值 */
initial-value: 4;
}
syntax
: 规定这个值的类型, 当允许外部修改时, 如果修改的值类型不属于规定的语法的数据类型, 将不会生效, 继续使用初始值, "*" 表示允许所有的值;inherits
: 是否允许外部修改该属性, 即重新给该变量赋值。initial-value
: 给定默认的初始值。<script setup lang='ts'>
import { ref } from 'vue'
</script>
<template>
<div class="cube" style="--cube-width: 200px; --cube-height: 200px;">
<div style="--position: 1"></div>
<div style="--position: 2"></div>
<div style="--position: 3"></div>
<div style="--position: 4"></div>
</div>
</template>
<style scoped lang='scss'>
@property --last-counter {
/** 规定这个值的类型, 当允许外部修改时, 如果修改的值类型不属于规定的数据类型, 将不会生效, "*" 表示允许所有的值 */
syntax: "<integer>";
/** 是否允许外部修改该属性 */
inherits: false;
/** 初始值 */
initial-value: 4;
}
@property --angle {
syntax: "<angle>";
inherits: false;
initial-value: calc(360deg / 4);
}
@property --photo-transform-originX {
syntax: "<angle>";
inherits: true;
initial-value: -30deg;
}
@property --photo-transform-originY {
syntax: "<angle>";
inherits: true;
initial-value: 0deg;
}
@keyframes CubeAutoPlay {
to {
--photo-transform-originY: 360deg;
}
}
.cube {
position: relative;
width: var(--cube-width, 300px);
height: var(--cube-height, 300px);
/* background: #34495e; */
/* border: 1px solid black; */
margin: 200px auto;
transform-style: preserve-3d;
transform: perspective(1000px) rotateX(var(--photo-transform-originX)) rotateY(var(--photo-transform-originY));
animation: CubeAutoPlay 3s linear infinite alternate;
&:hover {
animation-play-state: paused;
}
>div {
position: absolute;
top: 0;
left: 0;
width: inherit;
height: inherit;
background-size: cover;
background-repeat: no-repeat;
-webkit-box-reflect: below 0px linear-gradient(transparent, rgba(0, 0, 0, 0.2));
&:nth-child(1) {
background-color: #1abc9c;
background-image: url('https://picsum.photos/300/300?random=1');
transform: rotateY(calc(var(--angle) * calc(var(--position) - 1))) translateZ(calc(var(--cube-width)));
}
&:nth-child(2) {
background-color: #2ecc71;
background-image: url('https://picsum.photos/300/300?random=2');
transform: rotateY(calc(var(--angle) * calc(var(--position) - 1))) translateZ(calc(var(--cube-width)));
}
&:nth-child(3) {
background-color: #3498db;
background-image: url('https://picsum.photos/300/300?random=3');
transform: rotateY(calc(var(--angle) * calc(var(--position) - 1))) translateZ(calc(var(--cube-width)));
}
&:nth-child(4) {
background-color: #e67e22;
background-image: url('https://picsum.photos/300/300?random=4');
transform: rotateY(calc(var(--angle) * calc(var(--position) - 1))) translateZ(calc(var(--cube-width)));
}
}
}
</style>
非常简单的实现各种常见网页布局
<script setup lang='ts'>
</script>
<template>
<div class="body-demo">
<header>1</header>
<aside>2</aside>
<main>3</main>
<footer>4</footer>
</div>
</template>
<style scoped lang='css'>
@property --sidebar-width {
/** 属性值的数据类型, 后续更改会依据数据类型是否一致从而决定是否覆盖该属性 */
syntax: "<length>";
/** 是否允许继承, 允许继承也就表示可以重写, 不允许继承则会始终使用初始值 */
inherits: true;
/** 初始值 */
initial-value: 200px;
}
.body-demo {
* {
margin: 0;
padding: 0;
box-sizing: content-box;
}
min-height: 300px;
display: grid;
grid-template-rows: auto 1fr auto;
grid-template-columns: var(--sidebar-width) 1fr;
grid-template-areas: "navbar navbar"
"sidebar main"
"sidebar footer";
}
header {
grid-area: navbar;
background-color: #f1c40f;
height: 100px;
}
aside {
grid-area: sidebar;
background-color: #3498db;
}
main {
grid-area: main;
background-color: #2ecc71;
}
footer {
grid-area: footer;
background-color: #e74c3c;
}
</style>