refactor: use tsx refactor selector component

This commit is contained in:
xiaoxian521
2021-04-13 17:33:09 +08:00
parent 8a4a39de3a
commit 0d1f5bb673
15 changed files with 1184 additions and 74 deletions

View File

@@ -0,0 +1,10 @@
import { App } from "vue"
import selector from "./src/selector"
export const Selector = Object.assign(selector, {
install(app: App) {
app.component(selector.name, selector)
}
})
export default Selector

View File

@@ -0,0 +1,23 @@
.hs-rate__icon {
font-size: 18px;
transition: 0.3s;
}
.hs-item {
width: 30px;
height: 30px;
box-sizing: border-box;
line-height: 30px;
}
.hs-on {
background-color: #409eff;
border-radius: 50%;
}
.hs-range {
background-color: #f2f6fc;
}
.both-left-sides {
border-radius: 50% 0 0 50%;
}
.both-right-sides {
border-radius: 0 50% 50% 0;
}

View File

@@ -1,9 +1,12 @@
/**
<template>
<table cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td
v-for="(item, key) in max"
:data-index="HsKey"
:ref="'hstd' + HsKey + key"
:class="['hs-select__item' + key]"
@mousemove.prevent="setCurrentValue(key, $event)"
@mouseleave.prevent="resetCurrentValue(key)"
@@ -11,7 +14,7 @@
:style="{ cursor: rateDisabled ? 'auto' : 'pointer', 'text-align': 'center' }"
:key="key"
>
<div :class="[classes[key] + key]" class="hs-item">
<div :ref="'hsdiv' + HsKey + key" :class="[classes[key] + key]" class="hs-item">
<span>{{item}}</span>
</div>
</td>
@@ -21,9 +24,14 @@
</template>
<script lang='ts'>
import { defineComponent, computed, nextTick } from "vue";
import {
defineComponent,
computed,
nextTick,
onBeforeMount,
getCurrentInstance,
} from "vue";
import { addClass, removeClass, toggleClass } from "/@/utils/operate";
import { useDebounceFn } from "@vueuse/core";
// 选中非选中状态
let stayClass = "stay"; //鼠标点击
@@ -40,22 +48,33 @@ let selectedList = [];
let overList = [];
export default defineComponent({
name: "HsSelector",
props: {
HsKey: {
type: Number || String,
default: 0,
},
disabled: {
type: Boolean,
default: false
default: false,
},
value: {
type: Number,
default: 0
default: 0,
},
max: {
type: Number,
default: 10
}
default: 10,
},
// 回显数据的索引长度必须是2
echo: {
type: Array,
default: [],
},
},
emits: ["selectedVal"],
setup(props, { emit }) {
let vm: any;
let currentValue = props.value;
let rateDisabled = computed(() => {
@@ -78,7 +97,9 @@ export default defineComponent({
return result;
});
// 鼠标移入
const setCurrentValue = (index, event) => {
if (props.disabled) return;
// 当选中一个元素后,开始添加背景色
if (selectedList.length === 1) {
if (overList.length < 1) overList.push({ index });
@@ -122,7 +143,9 @@ export default defineComponent({
addClass(document.querySelector("." + voidClass + index), activeClass);
};
const resetCurrentValue = index => {
// 鼠标离开
const resetCurrentValue = (index) => {
if (props.disabled) return;
// 移除先检查是否选中 选中则返回false 不移除
const currentHsDom = document.querySelector("." + voidClass + index);
if (currentHsDom.className.includes(stayClass)) {
@@ -153,7 +176,9 @@ export default defineComponent({
}
};
// 鼠标点击
const selectValue = (index, item) => {
if (props.disabled) return;
let len = selectedList.length;
if (len < 2) {
@@ -189,19 +214,19 @@ export default defineComponent({
emit("selectedVal", {
left: selectedList[0].item,
right: selectedList[1].item,
whole: selectedList
whole: selectedList,
});
} else {
emit("selectedVal", {
left: selectedList[1].item,
right: selectedList[0].item,
whole: selectedList
whole: selectedList,
});
}
}
} else {
nextTick(() => {
selectedList.forEach(v => {
selectedList.forEach((v) => {
removeClass(
document.querySelector("." + voidClass + v.index),
activeClass,
@@ -235,14 +260,55 @@ export default defineComponent({
}
};
// 回显数据
const echoView = (item) => {
if (item.length === 0) return;
if (item.length > 2 || item.length === 1) {
throw "传入的数组长度必须是2";
}
item.sort((a, b) => {
return a - b;
});
addClass(
vm.refs["hsdiv" + props.HsKey + item[0]],
activeClass,
stayClass
);
addClass(vm.refs["hstd" + props.HsKey + item[0]], bothLeftSides);
addClass(
vm.refs["hsdiv" + props.HsKey + item[1]],
activeClass,
stayClass
);
addClass(vm.refs["hstd" + props.HsKey + item[1]], bothRightSides);
while (item[1] >= item[0]) {
addClass(vm.refs["hstd" + props.HsKey + item[0]], inRange);
item[0]++;
}
};
onBeforeMount(() => {
vm = getCurrentInstance();
nextTick(() => {
echoView(props.echo);
});
});
return {
rateDisabled,
setCurrentValue,
resetCurrentValue,
selectValue,
classes
classes,
echoView,
};
}
},
});
</script>
@@ -262,7 +328,7 @@ export default defineComponent({
border-radius: 50%;
}
.hs-range {
background-color: #f2f6fc;
background-color: #ccc;
}
.both-left-sides {
border-radius: 50% 0 0 50%;
@@ -271,3 +337,4 @@ export default defineComponent({
border-radius: 0 50% 50% 0;
}
</style>
*/

View File

@@ -0,0 +1,309 @@
import {
defineComponent,
computed,
nextTick,
onBeforeMount,
getCurrentInstance,
unref
} from "vue"
import { addClass, removeClass, toggleClass } from "/@/utils/operate"
import "./index.css"
let stayClass = "stay" //鼠标点击
let activeClass = "hs-on" //鼠标移动上去
let voidClass = "hs-off" //鼠标移开
let inRange = "hs-range" //当前选中的两个元素之间的背景
let bothLeftSides = "both-left-sides"
let bothRightSides = "both-right-sides"
let selectedDirection = "right" //默认从左往右,索引变大
let overList = []
// 存放第一个选中的元素和最后一个选中元素,只能存放这两个元素
let selectedList = []
export default defineComponent({
name: "HsSelector",
props: {
HsKey: {
type: Number || String,
default: 0,
},
disabled: {
type: Boolean,
default: false,
},
value: {
type: Number,
default: 0,
},
max: {
type: Array,
default: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
},
// 回显数据的索引长度必须是2
echo: {
type: Array,
default: [],
},
},
emits: ["selectedVal"],
setup(props, { emit }) {
let vm: any
let currentValue = props.value
let rateDisabled = computed(() => {
return props.disabled
})
let classes = computed(() => {
let result = []
let i = 0
let threshold = currentValue
if (currentValue !== Math.floor(currentValue)) {
threshold--
}
for (; i < threshold; i++) {
result.push(activeClass)
}
for (; i < props.max.length; i++) {
result.push(voidClass)
}
return result
})
// 鼠标移入
const setCurrentValue = (index) => {
if (props.disabled) return
// 当选中一个元素后,开始添加背景色
if (selectedList.length === 1) {
if (overList.length < 1) overList.push({ index })
let firstIndex = overList[0].index
// 往右走,索引变大
if (index > firstIndex) {
selectedDirection = "right"
toggleClass(
false,
bothRightSides,
document.querySelector(".hs-select__item" + selectedList[0].index)
)
while (index >= firstIndex) {
addClass(
document.querySelector(".hs-select__item" + firstIndex),
inRange
)
firstIndex++
}
} else {
selectedDirection = "left"
toggleClass(
true,
bothRightSides,
document.querySelector(".hs-select__item" + selectedList[0].index)
)
while (index <= firstIndex) {
addClass(
document.querySelector(".hs-select__item" + firstIndex),
inRange
)
firstIndex--
}
}
}
addClass(document.querySelector("." + voidClass + index), activeClass)
}
// 鼠标离开
const resetCurrentValue = (index) => {
if (props.disabled) return
// 移除先检查是否选中 选中则返回false 不移除
const currentHsDom = document.querySelector("." + voidClass + index)
if (currentHsDom.className.includes(stayClass)) {
return false
} else {
removeClass(currentHsDom, activeClass)
}
// 当选中一个元素后,开始移除背景色
if (selectedList.length === 1) {
let firstIndex = overList[0].index
if (index >= firstIndex) {
for (let i = 0; i <= index; i++) {
removeClass(
document.querySelector(".hs-select__item" + i),
inRange
)
}
} else {
while (index <= firstIndex) {
removeClass(
document.querySelector(".hs-select__item" + index),
inRange
)
index++
}
}
}
}
// 鼠标点击
const selectValue = (index, item) => {
if (props.disabled) return
let len = selectedList.length
if (len < 2) {
selectedList.push({ item, index })
addClass(document.querySelector("." + voidClass + index), stayClass)
addClass(
document.querySelector(".hs-select__item" + selectedList[0].index),
bothLeftSides
)
if (selectedList[1]) {
if (selectedDirection === "right") {
addClass(
document.querySelector(
".hs-select__item" + selectedList[1].index
),
bothRightSides
)
} else {
addClass(
document.querySelector(
".hs-select__item" + selectedList[1].index
),
bothLeftSides
)
}
}
if (len === 1) {
// 顺时针排序
if (selectedDirection === "right") {
emit("selectedVal", {
left: selectedList[0].item,
right: selectedList[1].item,
whole: selectedList,
})
} else {
emit("selectedVal", {
left: selectedList[1].item,
right: selectedList[0].item,
whole: selectedList,
})
}
}
} else {
nextTick(() => {
selectedList.forEach((v) => {
removeClass(
document.querySelector("." + voidClass + v.index),
activeClass,
stayClass
)
removeClass(
document.querySelector(".hs-select__item" + v.index),
bothLeftSides,
bothRightSides
)
})
selectedList = []
overList = []
for (let i = 0; i <= props.max.length; i++) {
let currentDom = document.querySelector(".hs-select__item" + i)
if (currentDom) {
removeClass(currentDom, inRange)
}
}
selectedList.push({ item, index })
addClass(document.querySelector("." + voidClass + index), stayClass)
addClass(
document.querySelector(".hs-select__item" + selectedList[0].index),
bothLeftSides
)
})
}
}
// 回显数据
const echoView = (item) => {
if (item.length === 0) return
if (item.length > 2 || item.length === 1) {
throw "传入的数组长度必须是2"
}
item.sort((a, b) => {
return a - b
})
addClass(
vm.refs["hsdiv" + props.HsKey + item[0]],
activeClass,
stayClass
)
addClass(vm.refs["hstd" + props.HsKey + item[0]], bothLeftSides)
addClass(
vm.refs["hsdiv" + props.HsKey + item[1]],
activeClass,
stayClass
)
addClass(vm.refs["hstd" + props.HsKey + item[1]], bothRightSides)
while (item[1] >= item[0]) {
addClass(vm.refs["hstd" + props.HsKey + item[0]], inRange)
item[0]++
}
}
onBeforeMount(() => {
vm = getCurrentInstance()
nextTick(() => {
echoView(props.echo)
})
})
return () => (
<>
<table cellspacing="0" cellpadding="0">
<tbody>
<tr>
{
props.max.map((item, key) => {
return <td
data-index={props.HsKey}
ref={`hstd${props.HsKey}${key}`}
class={`hs-select__item${key}`}
onMousemove={() => setCurrentValue(key)}
onMouseleave={() => resetCurrentValue(key)}
onClick={() => selectValue(key, item)}
style={{
cursor: unref(rateDisabled) ? 'auto' : 'pointer', textAlign: 'center'
}}
key={key}
>
<div ref={`hsdiv${props.HsKey}${key}`} class={`hs-item ${[unref(classes)[key] + key]}`}>
<span>{item}</span>
</div>
</td>
})
}
</tr>
</tbody>
</table>
</>
)
},
})

View File

@@ -57,16 +57,14 @@ export default {
justify-content: flex-start;
margin-left: 5px;
.scroll-item {
// border: 1px solid #eee;
border-radius: 3px;
padding: 2px 8px;
display: inline-block;
// margin-right: 2px;
}
a {
text-decoration: none;
color: #666;
padding: 0 10px;
padding: 0 4px 0 10px;
}
}
.el-icon-close {

View File

@@ -17,5 +17,6 @@
"button": "按钮组件",
"cropping": "图片裁剪",
"countTo": "数字动画",
"selector": "选择器组件"
"selector": "选择器组件",
"flowChart": "流程图"
}

View File

@@ -17,5 +17,6 @@
"button": "Button Components",
"cropping": "Picture Cropping",
"countTo": "Digital Animation",
"selector": "Selector Components"
"selector": "Selector Components",
"flowChart": "flow Chart"
}

View File

@@ -103,7 +103,16 @@ const routes: Array<RouteRecordRaw> = [
showLink: false,
savedPosition: true
}
}
},
// {
// path: '/components/flowChart',
// component: () => import(/* webpackChunkName: "components" */ '../views/components/flowChart/index.vue'),
// meta: {
// title: 'flowChart',
// showLink: false,
// savedPosition: true
// }
// }
],
meta: {
icon: 'el-icon-menu',

16
src/shims-tsx.d.ts vendored Normal file
View File

@@ -0,0 +1,16 @@
import Vue, { VNode } from "vue"
declare module '*.tsx' {
import Vue from 'compatible-vue'
export default Vue
}
declare global {
namespace JSX {
interface Element extends VNode { }
interface ElementClass extends Vue { }
interface IntrinsicElements {
[elem: string]: any
}
}
}

View File

@@ -0,0 +1,60 @@
<template>
<div id="container"></div>
</template>
<script lang='ts'>
import LogicFlow from "@logicflow/core";
import "@logicflow/core/dist/style/index.css";
import { onMounted } from "vue";
const data = {
// 节点
nodes: [
{
id: 50,
type: "rect",
x: 100,
y: 150,
text: "你好",
},
{
id: 21,
type: "circle",
x: 300,
y: 150,
},
],
// 边
edges: [
{
type: "polyline",
sourceNodeId: 50,
targetNodeId: 21,
},
],
};
export default {
setup() {
onMounted(() => {
const lf = new LogicFlow({
container: document.querySelector("#container"),
stopScrollGraph: true,
stopZoomGraph: true,
width: 500,
height: 500,
grid: {
type: "dot",
size: 20,
},
});
lf.render(data);
});
return {};
},
};
</script>
<style scoped>
</style>

View File

@@ -1,22 +1,37 @@
<template>
<el-card class="box-card" style="margin:20px">
<template #header>
<div class="card-header">
<span>基本使用</span>
</div>
</template>
<Selector @selectedVal="selectedVal" />
<h4>选中范围{{ selectRange }}</h4>
</el-card>
<div>
<el-card class="box-card" style="margin:10px" v-for="(item,key) in dataLists" :key="key">
<template #header>
<div class="card-header">
<span>{{item.title}}</span>
</div>
</template>
<Selector :HsKey="key" :echo="item.echo" @selectedVal="selectedVal" :disabled="item.disabled" />
<h4 v-if="!item.disabled">选中范围{{ selectRange }}</h4>
</el-card>
</div>
</template>
<script lang='ts'>
import { ref } from "vue";
import Selector from "/@/components/selector/index.vue";
import Selector from "/@/components/selector";
export default {
components: { Selector },
setup() {
let selectRange = ref(null);
let dataLists = ref([
{
title: "基本使用",
echo: [],
disabled: false,
},
{
title: "回显模式",
echo: [2, 7],
disabled: true,
},
]);
const selectedVal = ({ left, right, whole }) => {
selectRange.value = `${left}-${right}`;
@@ -24,11 +39,9 @@ export default {
return {
selectedVal,
selectRange
selectRange,
dataLists,
};
}
},
};
</script>
<style scoped>
</style>

View File

@@ -28,17 +28,21 @@
<script lang='ts'>
import flop from "../components/flop/index.vue";
import { ref, computed, onMounted, inject, nextTick } from "vue";
import { ref, computed, onMounted, nextTick, onUpdated } from "vue";
import { deviceDetection } from "../utils/deviceDetection";
import { echartsJson } from "../api/mock";
import { useEventListener, tryOnUnmounted } from "@vueuse/core";
import {
useEventListener,
tryOnUnmounted,
useTimeoutFn,
} from "@vueuse/core";
import * as echarts from "echarts";
let brokenLine: any = null; //折线图实例
export default {
name: "welcome",
components: {
flop
flop,
},
setup() {
let mobile = ref(deviceDetection());
@@ -71,39 +75,39 @@ export default {
brokenLine.setOption({
title: {
text: "上海 空气质量指数",
left: "1%"
left: "1%",
},
tooltip: {
trigger: "axis"
trigger: "axis",
},
grid: {
left: "5%",
right: "15%",
bottom: "10%"
bottom: "10%",
},
xAxis: {
data: info.map(function(item) {
data: info.map(function (item) {
return item[0];
})
}),
},
yAxis: {},
toolbox: {
right: 10,
feature: {
dataZoom: {
yAxisIndex: "none"
yAxisIndex: "none",
},
restore: {},
saveAsImage: {}
}
saveAsImage: {},
},
},
dataZoom: [
{
startValue: "2014-06-01"
startValue: "2014-06-01",
},
{
type: "inside"
}
type: "inside",
},
],
visualMap: {
top: 50,
@@ -112,67 +116,67 @@ export default {
{
gt: 0,
lte: 50,
color: "#93CE07"
color: "#93CE07",
},
{
gt: 50,
lte: 100,
color: "#FBDB0F"
color: "#FBDB0F",
},
{
gt: 100,
lte: 150,
color: "#FC7D02"
color: "#FC7D02",
},
{
gt: 150,
lte: 200,
color: "#FD0100"
color: "#FD0100",
},
{
gt: 200,
lte: 300,
color: "#AA069F"
color: "#AA069F",
},
{
gt: 300,
color: "#AC3B2A"
}
color: "#AC3B2A",
},
],
outOfRange: {
color: "#999"
}
color: "#999",
},
},
series: {
name: "上海 空气质量指数",
type: "line",
data: info.map(function(item) {
data: info.map(function (item) {
return item[1];
}),
markLine: {
silent: true,
lineStyle: {
color: "#333"
color: "#333",
},
data: [
{
yAxis: 50
yAxis: 50,
},
{
yAxis: 100
yAxis: 100,
},
{
yAxis: 150
yAxis: 150,
},
{
yAxis: 200
yAxis: 200,
},
{
yAxis: 300
}
]
}
}
yAxis: 300,
},
],
},
},
});
});
};
@@ -182,9 +186,13 @@ export default {
};
onMounted(() => {
useEventListener("resize", () => {
if (!brokenLine) return;
brokenLine.resize();
nextTick(() => {
useEventListener("resize", () => {
if (!brokenLine) return;
useTimeoutFn(() => {
brokenLine.resize()
}, 180);
});
});
});
@@ -198,9 +206,9 @@ export default {
greetings,
mobile,
loading,
openDepot
openDepot,
};
}
},
};
</script>