mirror of
https://github.com/javaLuo/vue-flip-down.git
synced 2025-04-06 03:58:09 +08:00
first commit
This commit is contained in:
parent
e7327debb7
commit
11bd22a50f
1
dist/main.js
vendored
Normal file
1
dist/main.js
vendored
Normal file
File diff suppressed because one or more lines are too long
16
example/index.html
Normal file
16
example/index.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-cn">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0"
|
||||||
|
/>
|
||||||
|
<title>Example</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
<script src="bundle.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
8
example/main.js
Normal file
8
example/main.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import Vue from 'vue';
|
||||||
|
import App from './src/app.vue';
|
||||||
|
|
||||||
|
Vue.config.productionTip = false;
|
||||||
|
|
||||||
|
new Vue({
|
||||||
|
render: h => h(App),
|
||||||
|
}).$mount('#root');
|
29
example/src/app.vue
Normal file
29
example/src/app.vue
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<CountDown :endDate="endDate"
|
||||||
|
:type="type" />
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
<input v-model="type">
|
||||||
|
<input v-model="endDate">
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import CountDown from '../../dist/main.js';
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
type: 4,
|
||||||
|
endDate: new Date().getTime() + 100861100,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
CountDown,
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onTypeChange(t) {
|
||||||
|
this.type = t;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
61
package.json
Normal file
61
package.json
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
{
|
||||||
|
"name": "vue-flip-down",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "vue 翻页效果的倒计时组件",
|
||||||
|
"main": "dist/main.js",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "webpack-dev-server --config webpack.dev.config.js",
|
||||||
|
"build": "webpack --config webpack.production.config.js --progress --profile --colors",
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/javaLuo/vue-flip-down.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"vue"
|
||||||
|
],
|
||||||
|
"author": "L",
|
||||||
|
"license": "ISC",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/javaLuo/vue-flip-down/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/javaLuo/vue-flip-down#readme",
|
||||||
|
"dependencies": {
|
||||||
|
"vue": "^2.5.17"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"autoprefixer": "^9.1.1",
|
||||||
|
"babel-core": "^6.26.3",
|
||||||
|
"babel-loader": "^7.1.5",
|
||||||
|
"babel-plugin-import": "^1.8.0",
|
||||||
|
"babel-plugin-syntax-dynamic-import": "^6.18.0",
|
||||||
|
"babel-plugin-transform-class-properties": "^6.24.1",
|
||||||
|
"babel-plugin-transform-decorators-legacy": "^1.3.5",
|
||||||
|
"babel-plugin-transform-object-rest-spread": "^6.26.0",
|
||||||
|
"babel-plugin-transform-runtime": "^6.23.0",
|
||||||
|
"babel-polyfill": "^6.26.0",
|
||||||
|
"babel-preset-vue-app": "^2.0.0",
|
||||||
|
"babel-runtime": "^6.26.0",
|
||||||
|
"clean-webpack-plugin": "^0.1.19",
|
||||||
|
"css-loader": "^1.0.0",
|
||||||
|
"less": "^3.8.1",
|
||||||
|
"less-loader": "^4.1.0",
|
||||||
|
"postcss-loader": "^3.0.0",
|
||||||
|
"style-loader": "^0.22.1",
|
||||||
|
"uglifyjs-webpack-plugin": "^1.3.0",
|
||||||
|
"url-loader": "^1.1.1",
|
||||||
|
"vue-loader": "^15.3.0",
|
||||||
|
"vue-template-compiler": "^2.5.17",
|
||||||
|
"webpack": "^4.16.5",
|
||||||
|
"webpack-cli": "^3.1.0",
|
||||||
|
"webpack-dev-server": "^3.1.5"
|
||||||
|
},
|
||||||
|
"browserslist": [
|
||||||
|
"iOS >= 8",
|
||||||
|
"Android > 4.1",
|
||||||
|
"last 1 versions",
|
||||||
|
"> 1%",
|
||||||
|
"not dead"
|
||||||
|
]
|
||||||
|
}
|
4
postcss.config.js
Normal file
4
postcss.config.js
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/** postcss-loader 解析器所需的配置文件 **/
|
||||||
|
module.exports = {
|
||||||
|
plugins: [require("autoprefixer")()]
|
||||||
|
};
|
307
src/app.vue
Normal file
307
src/app.vue
Normal file
@ -0,0 +1,307 @@
|
|||||||
|
<!-- 翻页效果 倒计时组件 -->
|
||||||
|
<template>
|
||||||
|
<div class="vue-countdown-component">
|
||||||
|
<!-- 天 -->
|
||||||
|
<div class="time-box"
|
||||||
|
v-if="type>=4">
|
||||||
|
{{day}}
|
||||||
|
<div :class="['b0',{'anime': isDayAnime}]">
|
||||||
|
<div>{{day}}</div>
|
||||||
|
</div>
|
||||||
|
<div :class="['a0',{'anime': isDayAnime}]"
|
||||||
|
@animationend="onDayAnimateEnd">
|
||||||
|
<div>{{dayDelay}}</div>
|
||||||
|
</div>
|
||||||
|
<div class="a1">
|
||||||
|
<div>{{dayDelay}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 时 -->
|
||||||
|
<div class="time-box"
|
||||||
|
v-if="type>=3">
|
||||||
|
{{hour}}
|
||||||
|
<div :class="['b0',{'anime': isHourAnime}]">
|
||||||
|
<div>{{hour}}</div>
|
||||||
|
</div>
|
||||||
|
<div :class="['a0',{'anime': isHourAnime}]"
|
||||||
|
@animationend="onHourAnimateEnd">
|
||||||
|
<div>{{hourDelay}}</div>
|
||||||
|
</div>
|
||||||
|
<div class="a1">
|
||||||
|
<div>{{hourDelay}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 分 -->
|
||||||
|
<div class="time-box"
|
||||||
|
v-if="type>=2">
|
||||||
|
{{min}}
|
||||||
|
<div :class="['b0',{'anime': isMinAnime}]">
|
||||||
|
<div>{{min}}</div>
|
||||||
|
</div>
|
||||||
|
<div :class="['a0',{'anime': isMinAnime}]"
|
||||||
|
@animationend="onMinAnimateEnd">
|
||||||
|
<div>{{minDelay}}</div>
|
||||||
|
</div>
|
||||||
|
<div class="a1">
|
||||||
|
<div>{{minDelay}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 秒 -->
|
||||||
|
<div class="time-box">
|
||||||
|
{{second}}
|
||||||
|
<div :class="['b0',{'anime': isSecondAnime}]">
|
||||||
|
<div>{{second}}</div>
|
||||||
|
</div>
|
||||||
|
<div :class="['a0',{'anime': isSecondAnime}]"
|
||||||
|
@animationend="onSecondAnimateEnd">
|
||||||
|
<div>{{secondDelay}}</div>
|
||||||
|
</div>
|
||||||
|
<div class="a1">
|
||||||
|
<div>{{secondDelay}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
day: '', // 剩余日
|
||||||
|
dayDelay: '',
|
||||||
|
hour: '', // 剩余小时
|
||||||
|
hourDelay: '',
|
||||||
|
min: '', // 剩余分钟
|
||||||
|
minDelay: '',
|
||||||
|
second: '', // 剩余秒
|
||||||
|
secondDelay: '',
|
||||||
|
timer: null, // 计时器
|
||||||
|
isDayAnime: false, // 日 执行动画
|
||||||
|
isHourAnime: false, // 时 执行动画
|
||||||
|
isMinAnime: false, // 分 执行动画
|
||||||
|
isSecondAnime: false, // 秒 执行动画
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
endDate: { type: [Date, Number, String], default: 0 }, // 截止时间
|
||||||
|
type: { type: [Number, String], default: 4 }, // 时间精度 4/3/2/1
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
endTime() {
|
||||||
|
if (this.endDate instanceof Date) {
|
||||||
|
return this.endDate.getTime();
|
||||||
|
}
|
||||||
|
return Number(this.endDate) > 0 ? Number(this.endDate) : 0;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
day(newV) {
|
||||||
|
this.isDayAnime = true;
|
||||||
|
setTimeout(() => {
|
||||||
|
this.dayDelay = newV;
|
||||||
|
}, 350);
|
||||||
|
},
|
||||||
|
hour(newV) {
|
||||||
|
this.isHourAnime = true;
|
||||||
|
setTimeout(() => {
|
||||||
|
this.hourDelay = newV;
|
||||||
|
}, 350);
|
||||||
|
},
|
||||||
|
min(newV) {
|
||||||
|
this.isMinAnime = true;
|
||||||
|
setTimeout(() => {
|
||||||
|
this.minDelay = newV;
|
||||||
|
}, 350);
|
||||||
|
},
|
||||||
|
second(newV) {
|
||||||
|
this.isSecondAnime = true;
|
||||||
|
setTimeout(() => {
|
||||||
|
this.secondDelay = newV;
|
||||||
|
}, 350);
|
||||||
|
},
|
||||||
|
endTime(newV) {
|
||||||
|
if (newV > 0) {
|
||||||
|
this.start();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.start();
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
clearTimeout(this.timer);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 开始倒计时
|
||||||
|
start() {
|
||||||
|
clearTimeout(this.timer);
|
||||||
|
console.log('每秒1次啊');
|
||||||
|
this.timer = setTimeout(() => {
|
||||||
|
let t = this.endTime - new Date().getTime(); // 剩余的毫秒数
|
||||||
|
t = t < 0 ? 0 : t;
|
||||||
|
let day = 0; // 剩余的天
|
||||||
|
let hour = 0; // 剩余的小时 已排除天
|
||||||
|
let min = 0; // 剩余的分钟 已排除天和小时
|
||||||
|
let second = 0; // 剩余的秒
|
||||||
|
let type = Number(this.type);
|
||||||
|
if (type >= 4) {
|
||||||
|
day = Math.floor(t / 86400000); // 剩余的天
|
||||||
|
hour = Math.floor(t / 3600000 - day * 24); // 剩余的小时 已排除天
|
||||||
|
min = Math.floor(t / 60000 - day * 1440 - hour * 60); // 剩余的分钟 已排除天和小时
|
||||||
|
second = Math.floor(t / 1000 - day * 86400 - hour * 3600 - min * 60); // 剩余的秒
|
||||||
|
} else if (type >= 3) {
|
||||||
|
hour = Math.floor(t / 3600000); // 剩余的小时 已排除天
|
||||||
|
min = Math.floor(t / 60000 - hour * 60); // 剩余的分钟 已排除天和小时
|
||||||
|
second = Math.floor(t / 1000 - hour * 3600 - min * 60); // 剩余的秒
|
||||||
|
} else if (type >= 2) {
|
||||||
|
min = Math.floor(t / 60000); // 剩余的分钟 已排除天和小时
|
||||||
|
second = Math.floor(t / 1000 - min * 60); // 剩余的秒
|
||||||
|
} else {
|
||||||
|
second = Math.floor(t / 1000); // 剩余的秒
|
||||||
|
}
|
||||||
|
|
||||||
|
this.day = String(day).padStart(2, '0');
|
||||||
|
this.hour = String(hour).padStart(2, '0');
|
||||||
|
this.min = String(min).padStart(2, '0');
|
||||||
|
this.second = String(second).padStart(2, '0');
|
||||||
|
|
||||||
|
if (t > 0) this.start();
|
||||||
|
}, 1000);
|
||||||
|
},
|
||||||
|
// 日 动画结束
|
||||||
|
onDayAnimateEnd() {
|
||||||
|
this.isDayAnime = false;
|
||||||
|
},
|
||||||
|
onHourAnimateEnd() {
|
||||||
|
this.isHourAnime = false;
|
||||||
|
},
|
||||||
|
onMinAnimateEnd() {
|
||||||
|
this.isMinAnime = false;
|
||||||
|
},
|
||||||
|
onSecondAnimateEnd() {
|
||||||
|
this.isSecondAnime = false;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.vue-countdown-component {
|
||||||
|
display: flex;
|
||||||
|
@keyframes animate-filp {
|
||||||
|
0% {
|
||||||
|
transform: rotateX(0);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotateX(-180deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes animate-filp2 {
|
||||||
|
0% {
|
||||||
|
transform: rotateX(180deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotateX(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.time-box {
|
||||||
|
position: relative;
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: 30px;
|
||||||
|
min-width: 28px;
|
||||||
|
font-size: 16px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 30px;
|
||||||
|
background-color: #6c96e8;
|
||||||
|
color: #ffffff;
|
||||||
|
perspective: 50px;
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 0 2px;
|
||||||
|
&:before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
background: #a7c7ff;
|
||||||
|
width: 2px;
|
||||||
|
height: 6px;
|
||||||
|
top: 50%;
|
||||||
|
left: -1px;
|
||||||
|
margin-top: -3px;
|
||||||
|
}
|
||||||
|
&:after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
background: #a7c7ff;
|
||||||
|
width: 2px;
|
||||||
|
height: 6px;
|
||||||
|
top: 50%;
|
||||||
|
right: -1px;
|
||||||
|
margin-top: -3px;
|
||||||
|
}
|
||||||
|
& + .time-box {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
& > div {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 50%;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
transform-style: preserve-3d;
|
||||||
|
& > div {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
&.a0 {
|
||||||
|
top: 0;
|
||||||
|
// opacity: 0;
|
||||||
|
border-radius: 3px 3px 0 0;
|
||||||
|
background-color: #6c96e8;
|
||||||
|
transform-origin: 50% bottom;
|
||||||
|
animation-duration: 500ms;
|
||||||
|
// animation-fill-mode: none;
|
||||||
|
transform: rotateX(0);
|
||||||
|
backface-visibility: hidden;
|
||||||
|
z-index: 2;
|
||||||
|
&.anime {
|
||||||
|
animation-name: animate-filp;
|
||||||
|
}
|
||||||
|
& > div {
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.b0 {
|
||||||
|
top: 15px;
|
||||||
|
border-radius: 0 0 3px 3px;
|
||||||
|
background-color: #73a1f8;
|
||||||
|
transform-origin: 50% top;
|
||||||
|
animation-duration: 500ms;
|
||||||
|
// animation-fill-mode: none;
|
||||||
|
transform: rotateX(180deg);
|
||||||
|
backface-visibility: hidden;
|
||||||
|
z-index: 2;
|
||||||
|
& > div {
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
&.anime {
|
||||||
|
animation-name: animate-filp2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.a1 {
|
||||||
|
top: 15px;
|
||||||
|
border-radius: 0 0 3px 3px;
|
||||||
|
background-color: #73a1f8;
|
||||||
|
& > div {
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
2
src/index.js
Normal file
2
src/index.js
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
import App from './app.vue';
|
||||||
|
export default App;
|
28
webpack.dev.config.js
Normal file
28
webpack.dev.config.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
var path = require('path');
|
||||||
|
const VueLoaderPlugin = require('vue-loader/lib/plugin');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
mode: 'development',
|
||||||
|
entry: path.join(__dirname, 'example', 'main.js'),
|
||||||
|
output: {
|
||||||
|
filename: 'bundle.js',
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /.vue$/,
|
||||||
|
use: ['vue-loader'],
|
||||||
|
include: [path.join(__dirname, 'example')],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.js$/,
|
||||||
|
use: ['babel-loader'],
|
||||||
|
include: [path.join(__dirname, 'example')],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
devServer: {
|
||||||
|
contentBase: path.join(__dirname, 'example'),
|
||||||
|
},
|
||||||
|
plugins: [new VueLoaderPlugin()],
|
||||||
|
};
|
79
webpack.production.config.js
Normal file
79
webpack.production.config.js
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
/** 这是用于开发环境的webpack配置文件 **/
|
||||||
|
|
||||||
|
const path = require('path'); // 获取绝对路径用
|
||||||
|
const webpack = require('webpack'); // webpack核心
|
||||||
|
const CleanWebpackPlugin = require('clean-webpack-plugin'); // 每次打包前清除旧的build文件夹
|
||||||
|
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
|
||||||
|
const VueLoaderPlugin = require('vue-loader/lib/plugin');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
mode: 'production',
|
||||||
|
entry: [
|
||||||
|
'./src/index.js', // 项目入口
|
||||||
|
],
|
||||||
|
output: {
|
||||||
|
path: path.resolve(__dirname, 'dist'), // 将打包好的文件放在此路径下,dev模式中,只会在内存中存在,不会真正的打包到此路径
|
||||||
|
filename: '[name].js', //编译后的文件名字
|
||||||
|
library: ['vue-flip-down'],
|
||||||
|
libraryTarget: 'umd',
|
||||||
|
},
|
||||||
|
externals: {
|
||||||
|
vue: 'vue',
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.vue$/,
|
||||||
|
use: ['vue-loader'],
|
||||||
|
include: path.resolve(__dirname, 'src'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// .js .jsx用babel解析
|
||||||
|
test: /\.js?$/,
|
||||||
|
use: ['babel-loader'],
|
||||||
|
include: path.resolve(__dirname, 'src'),
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// // .css 解析
|
||||||
|
// test: /\.css$/,
|
||||||
|
// use: ['style-loader', 'css-loader', 'postcss-loader'],
|
||||||
|
// include: path.resolve(__dirname, 'src'),
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
// .less 解析
|
||||||
|
test: /\.less$/,
|
||||||
|
use: ['style-loader', 'css-loader', 'postcss-loader', 'less-loader'],
|
||||||
|
include: path.resolve(__dirname, 'src'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// 文件解析
|
||||||
|
test: /\.(eot|woff|otf|svg|ttf|woff2|appcache|mp3|mp4|pdf)(\?|$)/,
|
||||||
|
include: path.resolve(__dirname, 'src'),
|
||||||
|
use: ['file-loader?name=assets/[name].[ext]'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// 图片解析
|
||||||
|
test: /\.(png|jpg|gif)(\?|$)/,
|
||||||
|
include: path.resolve(__dirname, 'src'),
|
||||||
|
use: ['url-loader?limit=8192&name=assets/[name].[ext]'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new VueLoaderPlugin(),
|
||||||
|
new CleanWebpackPlugin(['dist']),
|
||||||
|
new UglifyJsPlugin({
|
||||||
|
uglifyOptions: {
|
||||||
|
compress: {
|
||||||
|
drop_console: true, // 是否删除代码中所有的console
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.js', '.vue', '.less', '.css'], //后缀名自动补全
|
||||||
|
alias: {
|
||||||
|
'@': path.resolve(__dirname, 'src'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user