经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » JS/JS库/框架 » Vue.js » 查看文章
基于vue3的Crontab组件
来源:cnblogs  作者:Vrapile  时间:2024/4/8 9:32:34  对本文有异议

网上找的没有满意的,决定从若依前后端分离其前端vue2中的crontab进行转换,先上效果

若依v2版:

 改v3后:

 

 

v2转v3没什么难度,其中有大量的将 this.*** 替换为 ***.value,笔者写了个正则替换,希望可以帮助大家

  1. this.(\w+) $1.value

 

需要注意的有,在v2中【this.$refs[refName].cycle01 = indexArr[0]】这样写

在v3中要转换一下,在子组件中用【defineExpose】抛出一个setData方法,然后【proxy.$refs[refName].setData("cycle01", Number(indexArr[0]))】赋值

 

其中子组件CrontabSecond.vue的代码,其它分/时/日/月/周/年的类似,参照着改就可以了

  1. <template>
  2. <el-form size="small">
  3. <el-form-item>
  4. <el-radio v-model='radioValue' :label="1">
  5. 每秒,允许的通配符[, - * /]
  6. </el-radio>
  7. </el-form-item>
  8.  
  9. <el-form-item>
  10. <el-radio v-model='radioValue' :label="2">
  11. 周期,从
  12. <el-input-number v-model='cycle01' :min="0" :max="58" /> -
  13. <el-input-number v-model='cycle02' :min="cycle01 ? cycle01 + 1 : 1" :max="59" />
  14. </el-radio>
  15. </el-form-item>
  16.  
  17. <el-form-item>
  18. <el-radio v-model='radioValue' :label="3">
  19. <el-input-number v-model='average01' :min="0" :max="58" /> 秒开始,每
  20. <el-input-number v-model='average02' :min="1" :max="59 - average01 || 0" /> 秒执行一次
  21. </el-radio>
  22. </el-form-item>
  23.  
  24. <el-form-item class="crontab-select">
  25. <el-radio v-model='radioValue' :label="4">
  26. 指定
  27. <el-select clearable v-model="checkboxList" placeholder="可多选" multiple style="width:300px">
  28. <el-option v-for="item in 60" :key="item" :value="String(item-1)" :label="'第' + String(item-1) + '秒'">第 {{item-1}} 秒</el-option>
  29. </el-select>
  30. </el-radio>
  31. </el-form-item>
  32. </el-form>
  33. </template>
  34.  
  35. <script setup name="CrontabSecond">
  36. import { ref } from 'vue';
  37. const emits = defineEmits(["update"]);
  38. const props = defineProps({
  39. check: {
  40. type: Function,
  41. require:false
  42. },
  43. cron: {
  44. type: Object,
  45. default: function(){
  46. return {}
  47. }
  48. },
  49. });
  50. const radioValue = ref(1);
  51. const cycle01 = ref(1);
  52. const cycle02 = ref(2);
  53. const average01 = ref(0);
  54. const average02 = ref(1);
  55. const checkboxList = ref([]);
  56. // 计算两个周期值
  57. const cycleTotal = computed(() => {
  58. const c01 = props.check(cycle01.value, 0, 58)
  59. const c02 = props.check(cycle02.value, c01 ? c01 + 1 : 1, 59)
  60. return c01 + '-' + c02;
  61. })
  62. // 计算平均用到的值
  63. const averageTotal = computed(() => {
  64. const a01 = props.check(average01.value, 0, 58)
  65. const a02 = props.check(average02.value, 1, 59 - a01 || 0)
  66. return a01 + '/' + a02;
  67. })
  68. // 计算勾选的checkbox值合集
  69. const checkboxString = computed(() => {
  70. let str = checkboxList.value.join();
  71. return str == '' ? '*' : str;
  72. })
  73. watch(()=>radioValue.value, ()=>{
  74. radioChange();
  75. })
  76. watch(()=>cycleTotal.value, ()=>{
  77. cycleChange();
  78. })
  79. watch(()=>averageTotal.value, ()=>{
  80. averageChange();
  81. })
  82. watch(()=>checkboxString.value, ()=>{
  83. checkboxChange();
  84. })
  85. // 单选按钮值变化时
  86. function radioChange() {
  87. switch (radioValue.value) {
  88. case 1:
  89. emits('update', 'second', '*', 'second');
  90. break;
  91. case 2:
  92. emits('update', 'second', cycleTotal.value);
  93. break;
  94. case 3:
  95. emits('update', 'second', averageTotal.value);
  96. break;
  97. case 4:
  98. emits('update', 'second', checkboxString.value);
  99. break;
  100. }
  101. }
  102. // 周期两个值变化时
  103. function cycleChange() {
  104. if (radioValue.value == '2') {
  105. emits('update', 'second', cycleTotal.value);
  106. }
  107. }
  108. // 平均两个值变化时
  109. function averageChange() {
  110. if (radioValue.value == '3') {
  111. emits('update', 'second', averageTotal.value);
  112. }
  113. }
  114. // checkbox值变化时
  115. function checkboxChange() {
  116. if (radioValue.value == '4') {
  117. emits('update', 'second', checkboxString.value);
  118. }
  119. }
  120. defineExpose({
  121. setData(key, value){
  122. eval(key).value = value
  123. }
  124. })
  125. </script>

 

关于CrontabResult.vue的组件,转v3时,额外注意数组排序这里就好了,

  1. # 如果改为compare.value会出现bug的
  2. 正确为 arr.sort(this.compare) 改为 arr.sort(compare)

 

贴出核心Crontab.vue的代码,其子组件就不一一贴了,需要的可以自己下若依代码进行转换

  1. <template>
  2. <div class="crontab">
  3. <el-tabs type="border-card">
  4. <el-tab-pane label="秒">
  5. <CrontabSecond
  6. @update="updateCrontabValue"
  7. v-model:check="checkNumber"
  8. v-model:cron="crontabValueObj"
  9. ref="cronsecond"
  10. />
  11. </el-tab-pane>
  12.  
  13. <el-tab-pane label="分钟">
  14. <CrontabMin
  15. @update="updateCrontabValue"
  16. v-model:check="checkNumber"
  17. v-model:cron="crontabValueObj"
  18. ref="cronmin"
  19. />
  20. </el-tab-pane>
  21.  
  22. <el-tab-pane label="小时">
  23. <CrontabHour
  24. @update="updateCrontabValue"
  25. v-model:check="checkNumber"
  26. v-model:cron="crontabValueObj"
  27. ref="cronhour"
  28. />
  29. </el-tab-pane>
  30.  
  31. <el-tab-pane label="日">
  32. <CrontabDay
  33. @update="updateCrontabValue"
  34. v-model:check="checkNumber"
  35. v-model:cron="crontabValueObj"
  36. ref="cronday"
  37. />
  38. </el-tab-pane>
  39.  
  40. <el-tab-pane label="月">
  41. <CrontabMonth
  42. @update="updateCrontabValue"
  43. v-model:check="checkNumber"
  44. v-model:cron="crontabValueObj"
  45. ref="cronmonth"
  46. />
  47. </el-tab-pane>
  48.  
  49. <el-tab-pane label="周">
  50. <CrontabWeek
  51. @update="updateCrontabValue"
  52. v-model:check="checkNumber"
  53. v-model:cron="crontabValueObj"
  54. ref="cronweek"
  55. />
  56. </el-tab-pane>
  57.  
  58. <el-tab-pane label="年">
  59. <CrontabYear
  60. @update="updateCrontabValue"
  61. v-model:check="checkNumber"
  62. v-model:cron="crontabValueObj"
  63. ref="cronyear"
  64. />
  65. </el-tab-pane>
  66. </el-tabs>
  67.  
  68. <div class="crontab-main">
  69. <div class="crontab-main-table">
  70. <table>
  71. <thead>
  72. <th v-for="item of tabTitles" width="40" :key="item">{{item}}</th>
  73. <!-- <th>Cron 表达式</th> -->
  74. </thead>
  75. <tbody>
  76. <td>
  77. <span>{{crontabValueObj.second}}</span>
  78. </td>
  79. <td>
  80. <span>{{crontabValueObj.min}}</span>
  81. </td>
  82. <td>
  83. <span>{{crontabValueObj.hour}}</span>
  84. </td>
  85. <td>
  86. <span>{{crontabValueObj.day}}</span>
  87. </td>
  88. <td>
  89. <span>{{crontabValueObj.month}}</span>
  90. </td>
  91. <td>
  92. <span>{{crontabValueObj.week}}</span>
  93. </td>
  94. <td>
  95. <span>{{crontabValueObj.year}}</span>
  96. </td>
  97. <!-- <td>
  98. <span>{{crontabValueString}}</span>
  99. </td> -->
  100. </tbody>
  101. </table>
  102. <table>
  103. <thead>
  104. <th>Cron 表达式</th>
  105. </thead>
  106. <tbody>
  107. <td>
  108. <span>{{crontabValueString}}</span>
  109. </td>
  110. </tbody>
  111. </table>
  112. </div>
  113. <div class="crontab-main-result">
  114. <CrontabResult v-model:ex="crontabValueString"></CrontabResult>
  115. </div>
  116. </div>
  117.  
  118. </div>
  119. </template>
  120.  
  121. <script setup name="Crontab">
  122. import CrontabSecond from "./crontab/CrontabSecond.vue";
  123. import CrontabMin from "./crontab/CrontabMin.vue";
  124. import CrontabHour from "./crontab/CrontabHour.vue";
  125. import CrontabDay from "./crontab/CrontabDay.vue";
  126. import CrontabMonth from "./crontab/CrontabMonth.vue";
  127. import CrontabWeek from "./crontab/CrontabWeek.vue";
  128. import CrontabYear from "./crontab/CrontabYear.vue";
  129. import CrontabResult from "./crontab/CrontabResult.vue";
  130. const { proxy } = getCurrentInstance();
  131. const emits = defineEmits(["hide", "fill"]);
  132. const props = defineProps({
  133. expression: {type: String, default: ""}
  134. })
  135. const tabTitles = ref(["秒", "分钟", "小时", "日", "月", "周", "年"])
  136. const tabActive = ref(0)
  137. const crontabValueObj = ref({
  138. second: "*",
  139. min: "*",
  140. hour: "*",
  141. day: "*",
  142. month: "*",
  143. week: "?",
  144. year: "",
  145. })
  146. const crontabValueString = computed(() => {
  147. let obj = crontabValueObj.value;
  148. let str =
  149. obj.second +
  150. " " +
  151. obj.min +
  152. " " +
  153. obj.hour +
  154. " " +
  155. obj.day +
  156. " " +
  157. obj.month +
  158. " " +
  159. obj.week +
  160. (obj.year == "" ? "" : " " + obj.year);
  161. return str;
  162. })
  163. onMounted(() => {
  164. resolveExp();
  165. })
  166. watch(() => props.expression, (v) => {
  167. resolveExp();
  168. });
  169. function resolveExp() {
  170. // 反解析 表达式
  171. if (props.expression) {
  172. let arr = props.expression.split(" ");
  173. if (arr.length >= 6) {
  174. //6 位以上是合法表达式
  175. let obj = {
  176. second: arr[0],
  177. min: arr[1],
  178. hour: arr[2],
  179. day: arr[3],
  180. month: arr[4],
  181. week: arr[5],
  182. year: arr[6] ? arr[6] : "",
  183. };
  184. crontabValueObj.value = {
  185. ...obj,
  186. };
  187. for (let i in obj) {
  188. if (obj[i]) changeRadio(i, obj[i]);
  189. }
  190. }
  191. } else {
  192. // 没有传入的表达式 则还原
  193. clearCron();
  194. }
  195. }
  196. // tab切换值
  197. function tabCheck(index) {
  198. tabActive.value = index;
  199. }
  200. // 由子组件触发,更改表达式组成的字段值
  201. function updateCrontabValue(name, value, from) {
  202. // "updateCrontabValue", name, value, from;
  203. crontabValueObj.value[name] = value;
  204. if (from && from !== name) {
  205. console.log(`来自组件 ${from} 改变了 ${name} ${value}`);
  206. changeRadio(name, value);
  207. }
  208. }
  209. // 赋值到组件
  210. function changeRadio(name, value) {
  211. let arr = ["second", "min", "hour", "month"]
  212. let refName = "cron" + name
  213. let insValue;
  214. if (!proxy.$refs[refName]) return;
  215. if (arr.includes(name)) {
  216. if (value === "*") {
  217. insValue = 1;
  218. } else if (value.indexOf("-") > -1) {
  219. let indexArr = value.split("-");
  220. isNaN(indexArr[0])
  221. ? (proxy.$refs[refName].setData("cycle01", 0))
  222. : (proxy.$refs[refName].setData("cycle01", Number(indexArr[0])));
  223. proxy.$refs[refName].setData("cycle02", Number(indexArr[1]));
  224. insValue = 2;
  225. } else if (value.indexOf("/") > -1) {
  226. let indexArr = value.split("/");
  227. isNaN(indexArr[0])
  228. ? (proxy.$refs[refName].setData("average01", 0))
  229. : (proxy.$refs[refName].setData("average01", Number(indexArr[0])));
  230. proxy.$refs[refName].setData("average02", Number(indexArr[1]));
  231. insValue = 3;
  232. } else {
  233. insValue = 4;
  234. let list = value.split(",");
  235. for(let item of list){
  236. item = String(item)
  237. }
  238. proxy.$refs[refName].setData("checkboxList", list);
  239. }
  240. } else if (name == "day") {
  241. if (value === "*") {
  242. insValue = 1;
  243. } else if (value == "?") {
  244. insValue = 2;
  245. } else if (value.indexOf("-") > -1) {
  246. let indexArr = value.split("-");
  247. isNaN(indexArr[0])
  248. ? (proxy.$refs[refName].setData("cycle01", 0))
  249. : (proxy.$refs[refName].setData("cycle01", Number(indexArr[0])));
  250. proxy.$refs[refName].setData("cycle02", Number(indexArr[1]));
  251. insValue = 3;
  252. } else if (value.indexOf("/") > -1) {
  253. let indexArr = value.split("/");
  254. isNaN(indexArr[0])
  255. ? (proxy.$refs[refName].setData("average01", 0))
  256. : (proxy.$refs[refName].setData("average01", Number(indexArr[0])));
  257. proxy.$refs[refName].setData("average02", Number(indexArr[1]));
  258. insValue = 4;
  259. } else if (value.indexOf("W") > -1) {
  260. let indexArr = value.split("W");
  261. isNaN(indexArr[0])
  262. ? (proxy.$refs[refName].setData("workday", 0))
  263. : (proxy.$refs[refName].setData("workday", Number(indexArr[0])));
  264. insValue = 5;
  265. } else if (value === "L") {
  266. insValue = 6;
  267. } else {
  268. let list = value.split(",");
  269. for(let item of list){
  270. item = String(item)
  271. }
  272. proxy.$refs[refName].setData("checkboxList", list);
  273. insValue = 7;
  274. }
  275. } else if (name == "week") {
  276. if (value === "*") {
  277. insValue = 1;
  278. } else if (value == "?") {
  279. insValue = 2;
  280. } else if (value.indexOf("-") > -1) {
  281. let indexArr = value.split("-");
  282. isNaN(indexArr[0])
  283. ? (proxy.$refs[refName].setData("cycle01", "0"))
  284. : (proxy.$refs[refName].setData("cycle01", String(indexArr[0])));
  285. proxy.$refs[refName].setData("cycle02", String(indexArr[1]));
  286. insValue = 3;
  287. } else if (value.indexOf("#") > -1) {
  288. let indexArr = value.split("#");
  289. isNaN(indexArr[0])
  290. ? (proxy.$refs[refName].setData("average01", 1))
  291. : (proxy.$refs[refName].setData("average01", Number(indexArr[0])));
  292. proxy.$refs[refName].setData("average02", String(indexArr[1]));
  293. insValue = 4;
  294. } else if (value.indexOf("L") > -1) {
  295. let indexArr = value.split("L");
  296. isNaN(indexArr[0])
  297. ? (proxy.$refs[refName].setData("weekday", "1"))
  298. : (proxy.$refs[refName].setData("weekday", String(indexArr[0])));
  299. insValue = 5;
  300. } else {
  301. let list = value.split(",");
  302. for(let item of list){
  303. item = String(item)
  304. }
  305. proxy.$refs[refName].setData("checkboxList", list);
  306. insValue = 6;
  307. }
  308. } else if (name == "year") {
  309. if (value == "") {
  310. insValue = 1;
  311. } else if (value == "*") {
  312. insValue = 2;
  313. } else if (value.indexOf("-") > -1) {
  314. insValue = 3;
  315. } else if (value.indexOf("/") > -1) {
  316. insValue = 4;
  317. } else {
  318. let list = value.split(",");
  319. for(let item of list){
  320. item = String(item)
  321. }
  322. proxy.$refs[refName].setData("checkboxList", list);
  323. insValue = 5;
  324. }
  325. }
  326. proxy.$refs[refName].setData("radioValue", insValue);
  327. }
  328. // 表单选项的子组件校验数字格式(通过-props传递)
  329. function checkNumber(value, minLimit, maxLimit) {
  330. // 检查必须为整数
  331. value = Math.floor(Number(value));
  332. if (value < minLimit) {
  333. value = minLimit;
  334. } else if (value > maxLimit) {
  335. value = maxLimit;
  336. }
  337. return value;
  338. }
  339. // 隐藏弹窗
  340. function hidePopup() {
  341. emits("hide");
  342. }
  343. // 填充表达式
  344. function submitFill() {
  345. emits("fill", crontabValueString);
  346. hidePopup();
  347. }
  348. function clearCron() {
  349. // 还原选择项
  350. ("准备还原");
  351. crontabValueObj.value = {
  352. second: "*",
  353. min: "*",
  354. hour: "*",
  355. day: "*",
  356. month: "*",
  357. week: "?",
  358. year: "",
  359. };
  360. for (let j in crontabValueObj.value) {
  361. changeRadio(j, crontabValueObj.value[j]);
  362. }
  363. }
  364. defineExpose({
  365. submitFill, clearCron
  366. })
  367. </script>
  368. <style scoped>
  369. .crontab{
  370. flex: 1;
  371. height: 100%;
  372. display: flex;
  373. flex-direction: column;
  374. }
  375. .crontab-main {
  376. flex: 1;
  377. width: 100%;
  378. margin: 10px auto;
  379. background: #fff;
  380. border-radius: 5px;
  381. font-size: 12px;
  382. border: 1px solid #ccc;
  383. box-sizing: border-box;
  384. line-height: 24px;
  385. padding: 5px 10px 5px;
  386. display: flex;
  387. justify-content: space-between;
  388. overflow-y: auto;
  389. }
  390. .crontab-main-table {
  391. box-sizing: border-box;
  392. line-height: 24px;
  393. padding: 5px 10px 5px;
  394. width: 50%;
  395. display: flex;
  396. flex-direction: column;
  397. justify-content: space-around;
  398. table {
  399. text-align: center;
  400. width: 100%;
  401. margin: 0;
  402. span {
  403. display: block;
  404. width: 100%;
  405. font-family: arial;
  406. line-height: 30px;
  407. height: 30px;
  408. white-space: nowrap;
  409. overflow: hidden;
  410. border: 1px solid #e8e8e8;
  411. }
  412. }
  413. }
  414. .crontab-main-result {
  415. box-sizing: border-box;
  416. padding: 5px 10px 5px;
  417. background-color: #f1f1f1;
  418. background-size: cover;
  419. width: 48%;
  420. display: flex;
  421. flex-direction: column;
  422. .crontab-result-title{
  423. padding: 5px;
  424. }
  425. :deep(.crontab-result-scroll) {
  426. font-size: 12px;
  427. line-height: 24px;
  428. margin: 0 !important;
  429. padding-left: 80px;
  430. }
  431. }
  432. .crontab-footer {
  433. text-align: right;
  434. height: 25px;
  435. padding: 5px 20px;
  436. }
  437. </style>

 

将原来组件的按钮移到引用层,引用样例

  1.   <el-dialog title="Cron表达式生成器" v-model="formCrontabOpen" append-to-body destroy-on-close class="nine-tanchuang-001">
  2. <!-- <crontab @change="cronChange" v-model:value="formData.cronExpression" /> -->
  3. <Crontab ref="crontabRef" @hide="formCrontabOpen=false" @fill="crontabFill" v-model:expression="formData.cronExpression"></Crontab>
  4. <template #footer>
  5. <div class="dialog-footer">
  6. <el-button type="primary" @click="formCrontSubmit">确 定</el-button>
  7. <el-button type="warning" @click="formCrontReset">重 置</el-button>
  8. <el-button @click="formCrontabOpen=false">取 消</el-button>
  9. </div>
  10. </template>
  11. </el-dialog>

 

对应引用位置的调用方法

  1. /** 确定访问子组件方法 */
  2. function formCrontSubmit(){
  3. proxy.$refs.crontabRef.submitFill();
  4. }
  5. /** 重置访问子组件方法 */
  6. function formCrontReset(){
  7. proxy.$refs.crontabRef.clearCron();
  8. }
  9. /** 子组件确认回调方法 */
  10. function crontabFill(value) {
  11. formData.value.cronExpression = value;
  12. }

 

原文链接:https://www.cnblogs.com/Vrapile/p/18118548

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号