cbvirtua 1.0.122 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/package.json +2 -4
  2. package/valid.txt +468 -0
  3. package/vue3-hash-calendar-main.zip +0 -0
  4. package/1.zip +0 -0
  5. package/7.zip +0 -0
  6. package/888.zip +0 -0
  7. package/Checkbox Checked-1.png +0 -0
  8. package/_/345/217/267 (1).svg" +0 -1
  9. package/_/345/217/267.svg +0 -1
  10. package/a.png +0 -0
  11. package/babel-plugin-async-lock-master.zip +0 -0
  12. package/build-own-react-main.zip +0 -0
  13. package/check_box.svg +0 -1
  14. package/check_box_outline_blank.svg +0 -1
  15. package/checkbox_unchecked.svg +0 -1
  16. package/floating-vue-main.zip +0 -0
  17. package/font_2009600_gpzp7pxtnw.zip +0 -0
  18. package/font_2553510_ciljc7axaw7.woff +0 -0
  19. package/font_2553510_ciljc7axaw7.woff2 +0 -0
  20. package/leetcode-javascript-master.zip +0 -0
  21. package/loginDemo-master.zip +0 -0
  22. package/mi.txt +0 -374
  23. package/mitt-main.zip +0 -0
  24. package/mp-weixin-back-main.zip +0 -0
  25. package/pdfsss.txt +0 -900
  26. package/sms-check-code-master.zip +0 -0
  27. package/sss.txt +0 -2
  28. package/study-summarize-master.zip +0 -0
  29. package/tool.txt +0 -19
  30. package/v-dropdown-menu-master.zip +0 -0
  31. package/v-track-master/v-track-master/.browserslistrc +0 -3
  32. package/v-track-master/v-track-master/.eslintignore +0 -3
  33. package/v-track-master/v-track-master/.eslintrc.js +0 -15
  34. package/v-track-master/v-track-master/.gitattributes +0 -1
  35. package/v-track-master/v-track-master/.github/FUNDING.yml +0 -12
  36. package/v-track-master/v-track-master/.github/workflows/node.js.yml +0 -29
  37. package/v-track-master/v-track-master/.travis.yml +0 -22
  38. package/v-track-master/v-track-master/.yarnrc +0 -1
  39. package/v-track-master/v-track-master/LICENSE +0 -21
  40. package/v-track-master/v-track-master/README.md +0 -131
  41. package/v-track-master/v-track-master/babel.config.js +0 -25
  42. package/v-track-master/v-track-master/build/rollup.config.base.js +0 -14
  43. package/v-track-master/v-track-master/build/rollup.config.browser.js +0 -21
  44. package/v-track-master/v-track-master/build/rollup.config.es.js +0 -11
  45. package/v-track-master/v-track-master/docs/.babelrc +0 -5
  46. package/v-track-master/v-track-master/docs/App.vue +0 -61
  47. package/v-track-master/v-track-master/docs/assets/app.scss +0 -197
  48. package/v-track-master/v-track-master/docs/assets/index.scss +0 -10
  49. package/v-track-master/v-track-master/docs/assets/mixins.scss +0 -64
  50. package/v-track-master/v-track-master/docs/assets/normalize.scss +0 -349
  51. package/v-track-master/v-track-master/docs/components/button.vue +0 -15
  52. package/v-track-master/v-track-master/docs/components/code-snippet.vue +0 -72
  53. package/v-track-master/v-track-master/docs/dist/css/app.2e14d2d6.css +0 -4
  54. package/v-track-master/v-track-master/docs/dist/css/chunk-vendors.c687a9b2.css +0 -1
  55. package/v-track-master/v-track-master/docs/dist/favicon.ico +0 -0
  56. package/v-track-master/v-track-master/docs/dist/fonts/element-icons.535877f5.woff +0 -0
  57. package/v-track-master/v-track-master/docs/dist/fonts/element-icons.732389de.ttf +0 -0
  58. package/v-track-master/v-track-master/docs/dist/js/app.efe84ade.js +0 -2
  59. package/v-track-master/v-track-master/docs/dist/js/app.efe84ade.js.map +0 -1
  60. package/v-track-master/v-track-master/docs/dist/js/chunk-vendors.c94e27ba.js +0 -13
  61. package/v-track-master/v-track-master/docs/dist/js/chunk-vendors.c94e27ba.js.map +0 -1
  62. package/v-track-master/v-track-master/docs/index.html +0 -1
  63. package/v-track-master/v-track-master/docs/main.js +0 -78
  64. package/v-track-master/v-track-master/docs/pages/block-show.vue +0 -177
  65. package/v-track-master/v-track-master/docs/pages/custom-events.vue +0 -291
  66. package/v-track-master/v-track-master/docs/pages/home.vue +0 -269
  67. package/v-track-master/v-track-master/docs/pages/started.vue +0 -151
  68. package/v-track-master/v-track-master/docs/pages/track-view.vue +0 -234
  69. package/v-track-master/v-track-master/docs/tracks/action.js +0 -37
  70. package/v-track-master/v-track-master/docs/tracks/events.js +0 -140
  71. package/v-track-master/v-track-master/docs/tracks/index.js +0 -13
  72. package/v-track-master/v-track-master/docs/utils/date.js +0 -219
  73. package/v-track-master/v-track-master/docs/utils/dom.js +0 -26
  74. package/v-track-master/v-track-master/jest.config.js +0 -18
  75. package/v-track-master/v-track-master/package.json +0 -67
  76. package/v-track-master/v-track-master/postcss.config.js +0 -5
  77. package/v-track-master/v-track-master/public/favicon.ico +0 -0
  78. package/v-track-master/v-track-master/public/index.html +0 -18
  79. package/v-track-master/v-track-master/src/hooks/index.js +0 -217
  80. package/v-track-master/v-track-master/src/index.js +0 -79
  81. package/v-track-master/v-track-master/src/utils/debug.js +0 -13
  82. package/v-track-master/v-track-master/src/utils/dom.js +0 -73
  83. package/v-track-master/v-track-master/src/utils/helper.js +0 -122
  84. package/v-track-master/v-track-master/src/utils/vis-monitor.js +0 -183
  85. package/v-track-master/v-track-master/tests/helper.js +0 -37
  86. package/v-track-master/v-track-master/tests/unit/.eslintrc.js +0 -5
  87. package/v-track-master/v-track-master/tests/unit/track-click-async.spec.js +0 -52
  88. package/v-track-master/v-track-master/tests/unit/track-click-delay.spec.js +0 -46
  89. package/v-track-master/v-track-master/tests/unit/track-click-native.spec.js +0 -84
  90. package/v-track-master/v-track-master/tests/unit/track-click-param.spec.js +0 -55
  91. package/v-track-master/v-track-master/tests/unit/track-click.spec.js +0 -47
  92. package/v-track-master/v-track-master/tests/unit/track-custom-event-async.spec.js +0 -61
  93. package/v-track-master/v-track-master/tests/unit/track-custom-event-delay.spec.js +0 -59
  94. package/v-track-master/v-track-master/tests/unit/track-custom-event-param.spec.js +0 -68
  95. package/v-track-master/v-track-master/tests/unit/track-custom-event.spec.js +0 -55
  96. package/v-track-master/v-track-master/tests/unit/track-show-custom-scroll-once.spec.js +0 -62
  97. package/v-track-master/v-track-master/tests/unit/track-show-custom-scroll.spec.js +0 -62
  98. package/v-track-master/v-track-master/tests/unit/track-show-once.spec.js +0 -55
  99. package/v-track-master/v-track-master/tests/unit/track-show-param.spec.js +0 -51
  100. package/v-track-master/v-track-master/tests/unit/track-show.spec.js +0 -55
  101. package/v-track-master/v-track-master/tests/unit/track-view-vif.spec.js +0 -54
  102. package/v-track-master/v-track-master/tests/unit/track-view-watch-delay.spec.js +0 -63
  103. package/v-track-master/v-track-master/tests/unit/track-view-watch.spec.js +0 -61
  104. package/v-track-master/v-track-master/tests/unit/track-view.spec.js +0 -32
  105. package/v-track-master/v-track-master/vue.config.js +0 -45
  106. package/v-track-master/v-track-master/yarn.lock +0 -10186
  107. package/v-track-master.zip +0 -0
  108. package/vant-weapp-dev.zip +0 -0
  109. package/vue-autosize-input-master.zip +0 -0
  110. package/vue-awesome-dropdown-master.zip +0 -0
  111. package/vue-codemod-main.zip +0 -0
  112. package/vue-collapsed-main.zip +0 -0
  113. package/vue-input-code-master.zip +0 -0
  114. package/vue-jscodeshift-adapter-master.zip +0 -0
  115. package/vue-verify-master.zip +0 -0
  116. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/.hbuilderx/launch.json +0 -11
  117. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/App.vue +0 -17
  118. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/README.md +0 -13
  119. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/components/xiaolu-tree/code.js +0 -408
  120. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/components/xiaolu-tree/css/icon.css +0 -342
  121. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/components/xiaolu-tree/css/style.scss +0 -119
  122. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/components/xiaolu-tree/search/index.vue +0 -66
  123. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/components/xiaolu-tree/tree.vue +0 -70
  124. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/main.js +0 -11
  125. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/manifest.json +0 -78
  126. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/pages/chooseUser/chooseUser.vue +0 -69
  127. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/pages/chooseUser/data.js +0 -96
  128. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/pages/index/index.vue +0 -122
  129. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/pages.json +0 -25
  130. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-popup/changelog.md +0 -80
  131. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-popup/components/uni-popup/i18n/en.json +0 -7
  132. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-popup/components/uni-popup/i18n/index.js +0 -8
  133. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hans.json +0 -7
  134. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hant.json +0 -7
  135. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-popup/components/uni-popup/keypress.js +0 -45
  136. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-popup/components/uni-popup/popup.js +0 -26
  137. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-popup/components/uni-popup/uni-popup.uvue +0 -90
  138. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-popup/components/uni-popup/uni-popup.vue +0 -496
  139. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-popup/components/uni-popup-dialog/keypress.js +0 -45
  140. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-popup/components/uni-popup-dialog/uni-popup-dialog.vue +0 -313
  141. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-popup/components/uni-popup-message/uni-popup-message.vue +0 -143
  142. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-popup/components/uni-popup-share/uni-popup-share.vue +0 -187
  143. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-popup/package.json +0 -87
  144. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-popup/readme.md +0 -17
  145. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-scss/changelog.md +0 -8
  146. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-scss/index.scss +0 -1
  147. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-scss/package.json +0 -82
  148. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-scss/readme.md +0 -4
  149. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-scss/styles/index.scss +0 -7
  150. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-scss/styles/setting/_border.scss +0 -3
  151. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-scss/styles/setting/_color.scss +0 -66
  152. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-scss/styles/setting/_radius.scss +0 -55
  153. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-scss/styles/setting/_space.scss +0 -56
  154. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-scss/styles/setting/_styles.scss +0 -167
  155. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-scss/styles/setting/_text.scss +0 -24
  156. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-scss/styles/setting/_variables.scss +0 -146
  157. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-scss/styles/tools/functions.scss +0 -19
  158. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-scss/theme.scss +0 -31
  159. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-scss/variables.scss +0 -62
  160. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-transition/changelog.md +0 -22
  161. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-transition/components/uni-transition/createAnimation.js +0 -131
  162. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-transition/components/uni-transition/uni-transition.vue +0 -286
  163. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-transition/package.json +0 -84
  164. package/xiaolu-tree-plugin-main/xiaolu-tree-plugin-main/uni_modules/uni-transition/readme.md +0 -11
  165. package//346/224/266/347/274/251/344/270/212/347/256/255/345/244/264 (1).svg" +0 -1
  166. package//346/224/266/347/274/251/344/270/212/347/256/255/345/244/264.svg +0 -1
  167. package//346/224/266/347/274/251/344/270/213/347/256/255/345/244/264.svg +0 -1
  168. package//346/224/266/347/274/251/347/256/255/345/244/264.svg +0 -1
  169. package//346/226/260/345/273/272 /346/226/207/346/234/254/346/226/207/346/241/243 (2).txt" +0 -90
  170. package//346/226/260/345/273/272 /346/226/207/346/234/254/346/226/207/346/241/243 (3).txt" +0 -142
  171. package//346/226/260/345/273/272 /346/226/207/346/234/254/346/226/207/346/241/243 (3).zip +0 -0
  172. package//346/226/260/345/273/272 /346/226/207/346/234/254/346/226/207/346/241/243.txt" +0 -59
  173. package//351/227/256/345/217/267.svg +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cbvirtua",
3
- "version": "1.0.122",
3
+ "version": "2.0.1",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -8,7 +8,5 @@
8
8
  },
9
9
  "author": "",
10
10
  "license": "ISC",
11
- "dependencies": {
12
- "cbvirtua": "^1.0.0"
13
- }
11
+ "dependencies": {}
14
12
  }
package/valid.txt ADDED
@@ -0,0 +1,468 @@
1
+ 简介
2
+ 这段时间在进行一个新项目的前期搭建,新项目框架采用vue-cli3和typescirpt搭建。因为项目比较轻量,所以基本没有使用额外的ui组件,有时候我们需要的一些基础组件我就直接自己开发了。今天就来介绍一下如何利用vue的自定义指令directive来开发一个表单验证插件的过程。本文是以ts为基础开发的,如果同学们需要js版的只需要把ts语法转为js即可。
3
+
4
+ #1. vue插件开发
5
+ 关于vue的插件开发,官方文档里有很清晰的说明,详情可以去阅读开发文档 (opens new window)。这次开发的表单验证插件validate.ts就是利用了这种方式。
6
+
7
+ vue全局指令
8
+ // myPlugin.js
9
+ export default {
10
+ install: (Vue, options) => {
11
+ // 注册一个my-directive指令
12
+ Vue.directive('my-directive', {
13
+ bind(el, binding, vnode, oldVnode) {
14
+ // 逻辑
15
+ }
16
+ ...
17
+ })
18
+ }
19
+ }
20
+ // main.js
21
+ import Vue from 'vue';
22
+ import myPlugin from 'myPlugin';
23
+ Vue.use(myPlugin);
24
+
25
+ 上面是注册一个vue自定义指令 (opens new window)的写法,注册的时候,bind()函数为指令的钩子函数,其中的参数el表示指令绑定的元素,可以直接操作DOM。binding为一个对象,包括指令名称,绑定值等信息。vnode和oldVnode表示Vue编译生成的虚拟节点。
26
+
27
+ 我们通过注册一个全局指令v-validateParams指令,绑定到输入表单的input标签上来校验当前输入值是否符合要求。
28
+
29
+ #2. v-validateParams指令
30
+ 最开始我参考了网上的一些代码,思路如下:
31
+
32
+ 整体思路
33
+ import Vue from 'vue'
34
+ export default {
35
+ install: (Vue, options) => {
36
+ // 注册一个全局自定义指令 `v-validateParams`
37
+ Vue.directive('validateParams', {
38
+ // 当被绑定的元素插入到 DOM 中时
39
+ inserted: function (el, binding, vNode) {
40
+ // 给指令绑定的Dom元素添加事件监听,监测输入框失焦事件
41
+ // 每次当表单中的输入框失焦时执行函数
42
+ el.addEventListener('blur', function (event) {
43
+ // 1.首先重置所有错误提示
44
+ // 2.获取自定义指令中传入的校验规则参数和表单输入的值
45
+ // 3.依次判断当前输入的值是否符合校验规则
46
+ })
47
+ }
48
+ })
49
+
50
+ // 注册一个全局自定义指令 `v-validateSubmit`,这个指令绑定到表单的提交button上
51
+ Vue.directive('validateSubmit', {
52
+ // 当被绑定的元素插入到 DOM 中时
53
+ inserted: function (el, binding, vNode) {
54
+ // 给提交button添加事件监听
55
+ el.addEventListener('click', function (event) {
56
+ // 获取当前组件内所有含有v-check类名的元素
57
+ let elements = vNode.context.$el.getElementsByClassName('v-check')
58
+ var evObj = vNode.context.$el.createEvent('Event')
59
+ evObj.initEvent('blur', true, true)
60
+ for (let element of elements) {
61
+ // 给所有v-check元素绑定blur事件
62
+ element.dispatchEvent(evObj);
63
+ }
64
+ // 获取当前组件下的所有错误提示元素
65
+ let errorInputs = vNode.context.$el.getElementsByClassName('input-error');
66
+ // 如果组件中没有错误提示元素,则执行当前组件实例中的submit()函数
67
+ if(errorInputs.length === 0){
68
+ vNode.context.submit();
69
+ }
70
+ })
71
+ }
72
+ })
73
+ }
74
+ }
75
+
76
+ 这里需要说明一下validateSubmit指令,这个指令绑定到提交按钮上,在点击的时候执行校验,校验通过之后执行提交操作。但是这里的实现方式不是特别友好:
77
+
78
+ 需要获取当前组件中的所有input元素,给他们绑定并执行blur事件,以此来执行validateParams指令中的校验逻辑。
79
+ 获取当前组件中的所有错误提示元素,如果他们存在就表示没有通过校验,不能继续执行后面的逻辑。
80
+ 当组件内不含任何错误提示元素时,表示校验通过,执行当前组件内的submit函数,所以每个表单组件的提交函数都只能命名为submit
81
+ 我们再看下指令validateParams的内部实现。该指令需要绑定到表单input元素上,并把校验规则当作参数传入。当该input元素失焦时,会执行指令中给当前元素绑定的事件中的逻辑。这些逻辑分为三个步骤,我已经写在注释里了,现在我们来看下具体实现。
82
+
83
+ 重置所有错误提示
84
+ /**
85
+ * 重置当前节点样式
86
+ * @param el: HTMLElement,传入当前绑定的input元素
87
+ */
88
+ const resetError = (el: HTMLElement) => {
89
+ el.className = el.className.replace('input-error', '').trim();
90
+ if ( el.parentNode ) {
91
+ const ErrorNode = el.parentNode.querySelector('.error-tips');
92
+ if (ErrorNode) {
93
+ el.parentNode.removeChild(ErrorNode);
94
+ }
95
+ }
96
+ };
97
+ 获取自定义指令中传入的校验规则参数和表单输入的值
98
+ // binding.value是传入自定义指令的参数,以数组的形式
99
+ for (const rule of binding.value) {
100
+ // 分别获取到自己定义的校验规则并执行
101
+ const { min, max, message, required, pattern } = rule;
102
+ if ( !!required && !InputEl.value ) {
103
+ // 如果不符合校验,执行报错函数
104
+ validateError(InputEl, message);
105
+ break;
106
+ }
107
+ if ( min && InputEl.value.length < min ) {
108
+ validateError(InputEl, message);
109
+ break;
110
+ }
111
+ if ( max && InputEl.value.length > max ) {
112
+ validateError(InputEl, message);
113
+ break;
114
+ }
115
+ if ( pattern && !pattern.test(InputEl.value) ) {
116
+ validateError(InputEl, message);
117
+ break;
118
+ }
119
+ if ( rule && typeof rule === 'function' ) {
120
+ rule(vNode.context, InputEl.value, validateError, InputEl);
121
+ break;
122
+ }
123
+ }
124
+ 校验不符合,执行报错函数
125
+ /**
126
+ * 执行错误提示函数,用input-error 类名和含有错误信息的p元素表示未通过校验
127
+ * @param el: HTMLElement,传入当前绑定的input元素
128
+ * @param errorMsg: string,传入错误提示信息
129
+ */
130
+ const validateError = (el: HTMLElement, errorMsg: string) => {
131
+ if (Array.prototype.includes.call(el.classList, 'input-error')) {
132
+ //如果当前组件里已经有了错误提示信息,什么也不做
133
+ return;
134
+ } else {
135
+ const errorNode = document.createElement('p');
136
+ errorNode.className = 'error-tips';
137
+ errorNode.textContent = errorMsg;
138
+ if (el.parentNode) {
139
+ // 在当前input 元素后追加一个p元素,内容为错误提示
140
+ el.parentNode.appendChild(errorNode);
141
+ }
142
+ // 在当前input 元素上添加一个input-error类名
143
+ el.className += ' input-error';
144
+ }
145
+ };
146
+ 现在我就把自己实现的这个表单校验插件大致说完了,下面我们看下具体使用。
147
+
148
+ #3. 表单插件的使用
149
+ 首先新建校验规则文件:
150
+
151
+ // rules.ts
152
+ export const required = (message) => ({
153
+ message,
154
+ required: true
155
+ });
156
+ export const min = (message, length=3) => ({
157
+ message,
158
+ min: length
159
+ })
160
+ export const max = (message, length=15) => ({
161
+ message,
162
+ max: length
163
+ })
164
+ export const pattern = (message, reg) => ({
165
+ message,
166
+ pattern: reg
167
+ })
168
+
169
+ // form.vue
170
+ <template>
171
+ <div>
172
+ <div class="form-item">
173
+ <label for="userEmail">用户名:</label>
174
+ <input id="userEmail" class='v-check' type="text" v-model="userName"
175
+ v-validateParams="[inputNameRequired, inputNameMin, inputNameMax, inputNamePattern]">
176
+ </div>
177
+ <button class="btn" type="success" v-checkSubmit>确认</button>
178
+ </div>
179
+ </template>
180
+ <script lang='ts'>
181
+ import { Component, Vue, Prop } from 'vue-property-decorator';
182
+ import { max, min, required, name, pattern} from 'rules';
183
+
184
+ @Component({})
185
+ export default class Auth extends Vue {
186
+ private userName: string = '';
187
+ private inputNameMax = max('请不要超过20个字符');
188
+ private inputNameMin = min('请不要小于3个字符');
189
+ private inputNameRequired = required('请输入用户名');
190
+ private inputNamePattern = pattern('请输入符合要求的用户名', /^[a-zA-Z0-9_-]{4,16}$/);
191
+ private submit() {
192
+ alert('通过校验');
193
+ }
194
+ }
195
+ </script>
196
+ 通过这个例子我们可以看到,使用时需要将校验规则引入并赋给vue实例中的数据。然后在模板中,需要给input标签添加v-check类名,再使用v-validateParams指令,并传入参数。提交按钮需要调用v-checkSubmit指令。按照这种方式就能够使用自己开发的这个表单校验插件。
197
+
198
+ #4. 当前方式存在的问题
199
+ 虽然表单校验可以使用了,但是存在一些显而易见的问题:
200
+
201
+ js和html耦合度较高,插件还需要获取dom元素,组件的html模板中还需要添加制定类名。
202
+ 在vue中使用dom操作,不符合vue的设计思路,实现方式也不优雅。
203
+ 校验规则的校验逻辑在指令定义时写定了,添加或删除都需要改动插件代码。
204
+ 提交指令根据当前组件内的是否含有特定dom来判断当前校验状态,且执行提交的函数名称也在指令逻辑中写定了。
205
+ 我根据现有一个demo结合着自己的需求来实现的这个表单校验插件,开发的过程中我已经知道这么写问题很多,同时也清楚的认识到自己的javascript水平还很初级,需要继续努力学习。
206
+
207
+ 当前开发的表单插件的主要问题在于如何将插件中的校验状态返回到组件内。我们可以在插件内维护一个事件处理函数,将校验规则传入并校验,再将校验结果直接传给组件内。这样就可以避免大量的dom操作。之后我需要尽快对这个插件进行更科学合理的重构。
208
+
209
+ #更新:对表单插件的优化(opens new window)
210
+ #参考文章
211
+ vue插件(opens new window)
212
+
213
+ vue自定义指令(opens new window)
214
+
215
+ vue使用自定义指令实现表单校验(opens new window)
216
+
217
+ 重构:从 0.1 构建一个 Vue 表单验证插件(opens new window)
218
+
219
+ va.js——Vue 表单验证插件的写作过程
220
+
221
+
222
+
223
+ Vue3自定义指令实现输入框全局禁止空格输入方案
224
+ avatar
225
+ 2026-02-12 12:05:13
226
+ 在Web开发中,输入框禁止空格输入是常见的表单验证需求。本文基于Vue3的自定义指令机制,提供了一套完整的全局解决方案,可有效拦截所有形式的空格输入(包括键盘输入、粘贴内容等)。
227
+
228
+ 核心实现方案
229
+ 自定义指令封装
230
+ 通过封装v-no-space自定义指令,实现输入框空格的实时过滤:
231
+
232
+ JavaScript
233
+ 复制
234
+ export default {
235
+ mounted(el) {
236
+ const handler = (e) => {
237
+ // 实时替换所有空格(包括粘贴内容)
238
+ const newValue = e.target.value.replace(/\s+/g, '')
239
+ if (e.target.value !== newValue) {
240
+ e.target.value = newValue
241
+ // 触发v-model更新
242
+ el.dispatchEvent(new Event('input'))
243
+ }
244
+ }
245
+ el._noSpaceHandler = handler
246
+ el.addEventListener('input', handler)
247
+ },
248
+ unmounted(el) {
249
+ el.removeEventListener('input', el._noSpaceHandler)
250
+ }
251
+ }
252
+ 关键点说明:
253
+
254
+ 使用正则表达式/\s+/g匹配所有空白字符
255
+ 通过监听input事件实现实时过滤
256
+ 手动触发input事件确保v-model同步
257
+ 组件卸载时自动移除事件监听
258
+ 全局指令注册
259
+ 在应用入口文件注册全局指令:
260
+
261
+ JavaScript
262
+ 复制
263
+ import { createApp } from 'vue'
264
+ import App from './App.vue'
265
+ import noSpace from './directives/noSpace'
266
+
267
+ const app = createApp(App)
268
+ app.directive('no-space', noSpace)
269
+ app.mount('#app')
270
+ 组件使用示例
271
+ 在任意组件中通过v-no-space指令快速应用:
272
+
273
+ Vue
274
+ 复制
275
+ <template>
276
+ <div class="container">
277
+ <h1>禁止空格输入演示</h1>
278
+ <input
279
+ v-model="textValue"
280
+ v-no-space
281
+ placeholder="尝试输入或粘贴带空格的内容"
282
+ class="input-field"
283
+ >
284
+ <p>当前值: "{{ textValue }}"</p>
285
+ </div>
286
+ </template>
287
+
288
+ <script>
289
+ export default {
290
+ data() {
291
+ return {
292
+ textValue: ''
293
+ }
294
+ }
295
+ }
296
+ </script>
297
+
298
+ <style>
299
+ .container {
300
+ max-width: 600px;
301
+ margin: 2rem auto;
302
+ padding: 1rem;
303
+ font-family: Arial, sans-serif;
304
+ }
305
+ .input-field {
306
+ width: 100%;
307
+ padding: 0.5rem;
308
+ border: 2px solid #3498db;
309
+ border-radius: 4px;
310
+ font-size: 1rem;
311
+ }
312
+ </style>
313
+ 方案优势对比
314
+ 实现方式 适用范围 过滤范围 维护成本
315
+ v-model.trim 仅首尾空格 有限 低
316
+ keydown事件 键盘输入 有限 中
317
+ 自定义指令 所有输入场景 全面 低
318
+ 常见问题处理
319
+ 粘贴空格内容:通过监听input事件可拦截粘贴操作
320
+ 中文输入法:不会影响正常中文输入(仅过滤空白字符)
321
+ 内存泄漏:通过unmounted钩子确保事件监听器正确移除
322
+
323
+
324
+ vue3自定义指令验证输入
325
+ 当我简单写几个带输入验证的input时,比如必填和邮件格式等,又不想引入antd那种大型库,就想试一下用vue的自定义指令来验证,确实效果嘎嘎好。
326
+ 自定义指令
327
+ 先来看一下自定义指令的基本语法。
328
+ 一个自定义指令由一个包含类似组件生命周期钩子的对象来定义。钩子函数会接收到指令所绑定元素作为其参数。
329
+ 一个指令的定义对象可以提供几种钩子函数 (都是可选的):
330
+ js 体验AI代码助手 代码解读复制代码const myDirective = {
331
+ // 在绑定元素的父组件
332
+ // 及他自己的所有子节点都挂载完成后调用
333
+ mounted(el, binding, vnode, prevVnode) {},
334
+ // 在绑定元素的父组件
335
+ // 及他自己的所有子节点都更新后调用
336
+ updated(el, binding, vnode, prevVnode) {},
337
+ }
338
+
339
+ 主要会用到的参数是el和binding,el是指令绑定到的元素,可以直接操作DOM,bingding是一个对象,包含value属性,是传递给指令的值。
340
+ 实现
341
+ 最终效果是这样
342
+
343
+ 模版
344
+ 先简单写个模版,也不是那么简单,看input和hint就好了。
345
+ html 体验AI代码助手 代码解读复制代码 <div class="form_field">
346
+ <div class="field">
347
+ <div class="field_label">email:</div>
348
+ <input
349
+ id="email"
350
+ data-rules="required|email"
351
+ v-validate="displayErrors"
352
+ type="text"
353
+ />
354
+ </div>
355
+ <div class="hint">{{ state.errors['email'] }}</div>
356
+ </div>
357
+ <div class="form_field">
358
+ <div class="field">
359
+ <div class="field_label">password:</div>
360
+ <input
361
+ id="password"
362
+ data-rules="required|minLength:8"
363
+ v-validate="displayErrors"
364
+ type="password"
365
+ />
366
+ </div>
367
+ <div class="hint">{{ state.errors['password'] }}</div>
368
+ </div>
369
+
370
+ 在data-rules中写上需要哪些验证,email是必填和邮箱格式,password是必填和长度至少为8。
371
+ 自定义指令是v-validate,需要传递displayErrors函数过去,在这个函数里面可以拿到输入验证的结果,有error的话展现到页面上。hint就是展示错误的地方,需要拿到对应的error,这里的关键字要和input的id属性对应。
372
+ setup
373
+ setup部分比较简单,定义一个state,包含errors对象。displayErrors函数就是拿到验证结果,把错误放入erros中。
374
+ js 体验AI代码助手 代码解读复制代码<script setup>
375
+ import { reactive } from 'vue';
376
+
377
+ const state = reactive({
378
+ errors: {},
379
+ });
380
+ function displayErrors(errors) {
381
+ if (errors) {
382
+ state.errors[errors.name] = errors.error;
383
+ }
384
+ }
385
+ </script>
386
+
387
+ 自定义指令实现
388
+ 接下来是重头戏了。在元素mounted了后,拿到rules。如果有rules,就监听元素的input事件,并验证每一条rule是不是符合,不符合的就给出error,并调用组件传过来displayErrors函数。
389
+ js 体验AI代码助手 代码解读复制代码const validateDirective = {
390
+ mounted(el, binding, vnode, prevVnode) {
391
+ // 获取定义在dataset.rules的规则
392
+ const rules = el.dataset['rules'];
393
+ // 获取组件传递的displayErrors函数
394
+ const displayErrors = binding.value;
395
+ if (!rules) return;
396
+ // 解析rules
397
+ const specRules = getRules(rules);
398
+ el.addEventListener('input', (e) => {
399
+ // input的值
400
+ const value = e.target.value;
401
+ let error;
402
+ if ('email' in specRules) {
403
+ const emailRegex =
404
+ /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
405
+ if (!emailRegex.test(value)) {
406
+ error = `字符串不符合邮件格式`;
407
+ }
408
+ }
409
+ if ('minLength' in specRules) {
410
+ if (value.length < specRules['minLength']) {
411
+ error = `字符串长度至少为${specRules['minLength']}`;
412
+ }
413
+ }
414
+ if ('required' in specRules) {
415
+ if (!value) {
416
+ error = '字符串不能为空';
417
+ }
418
+ }
419
+ displayErrors({
420
+ name: el.id,
421
+ error: error,
422
+ });
423
+ });
424
+ },
425
+ };
426
+
427
+ rules和getRules这里都是简单的实现。
428
+ js 体验AI代码助手 代码解读复制代码function getRules(rules) {
429
+ // rules用|分隔
430
+ const validateRules = rules.split('|');
431
+ const rulesObj = {};
432
+ validateRules.forEach((rule) => {
433
+ // rule参数用:分隔
434
+ const specRule = rule.split(':');
435
+ if (specRule.length > 1) {
436
+ rulesObj[specRule[0]] = specRule[1];
437
+ } else {
438
+ // 没有参数的rule用true代表
439
+ rulesObj[specRule[0]] = true;
440
+ }
441
+ });
442
+ return rulesObj;
443
+ }
444
+
445
+ 注册自定义指令
446
+ 可以在main.js中全局注册自定义指令
447
+ js 体验AI代码助手 代码解读复制代码import validateDirective from './directives/validate';
448
+ const app = createApp(App);
449
+ app.directive('validate', validateDirective);
450
+ app.mount('#app');
451
+
452
+ 也可以通过directives选项注册
453
+ js 体验AI代码助手 代码解读复制代码import validateDirective from './directives/validate';
454
+
455
+ export default {
456
+ directives: {
457
+ // 在模板中启用 v-validate
458
+ validate: validateDirective
459
+ }
460
+ }
461
+
462
+ 总结
463
+ 以上就是通过自定义指令验证输入的全部内容了。除了这个,自定义指令还有更多有趣又有用的功能,如v-copy, v-lazy-img,v-emoji,v-longpress等,可以参考这篇文章。当遇到需要通用的操作原生DOM的情况时,除了$refs,试试看自定义指令吧!
464
+
465
+ 作者:叶之
466
+ 链接:https://juejin.cn/post/7250382724879122489
467
+ 来源:稀土掘金
468
+ 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
Binary file
package/1.zip DELETED
Binary file
package/7.zip DELETED
Binary file
package/888.zip DELETED
Binary file
Binary file
@@ -1 +0,0 @@
1
- <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1746628146445" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1642" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M422.4 128h115.2l-12.8 294.4 268.8-102.4 38.4 102.4-281.6 89.6 192 217.6-89.6 76.8-179.2-243.2-166.4 243.2-89.6-76.8L409.6 512 128 422.4l38.4-102.4 268.8 102.4z" fill="#F34861" p-id="1643"></path></svg>
package/_/345/217/267.svg DELETED
@@ -1 +0,0 @@
1
- <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1746628146445" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1642" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M422.4 128h115.2l-12.8 294.4 268.8-102.4 38.4 102.4-281.6 89.6 192 217.6-89.6 76.8-179.2-243.2-166.4 243.2-89.6-76.8L409.6 512 128 422.4l38.4-102.4 268.8 102.4z" fill="#F34861" p-id="1643"></path></svg>
package/a.png DELETED
Binary file
Binary file
Binary file
package/check_box.svg DELETED
@@ -1 +0,0 @@
1
- <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1749568783409" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4227" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M426.005333 725.994667l384-384-60.010667-61.994667-324.010667 324.010667-152-152-60.010667 60.010667zM810.005333 128q36.010667 0 60.992 26.005333t25.002667 60.010667l0 596.010667q0 34.005333-25.002667 60.010667t-60.992 26.005333l-596.010667 0q-36.010667 0-60.992-26.005333t-25.002667-60.010667l0-596.010667q0-34.005333 25.002667-60.010667t60.992-26.005333l596.010667 0z" fill="#222222" p-id="4228"></path></svg>
@@ -1 +0,0 @@
1
- <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1749569004781" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1551" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M810.005333 128q34.005333 0 60.010667 26.005333t26.005333 60.010667l0 596.010667q0 34.005333-26.005333 60.010667t-60.010667 26.005333l-596.010667 0q-34.005333 0-60.010667-26.005333t-26.005333-60.010667l0-596.010667q0-34.005333 26.005333-60.010667t60.010667-26.005333l596.010667 0zM810.005333 213.994667l-596.010667 0 0 596.010667 596.010667 0 0-596.010667z" fill="#222222" p-id="1552"></path></svg>
@@ -1 +0,0 @@
1
- <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1749568817715" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4450" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M245.333333 128h533.333334A117.333333 117.333333 0 0 1 896 245.333333v533.333334A117.333333 117.333333 0 0 1 778.666667 896H245.333333A117.333333 117.333333 0 0 1 128 778.666667V245.333333A117.333333 117.333333 0 0 1 245.333333 128z m0 64c-29.44 0-53.333333 23.893333-53.333333 53.333333v533.333334c0 29.44 23.893333 53.333333 53.333333 53.333333h533.333334c29.44 0 53.333333-23.893333 53.333333-53.333333V245.333333c0-29.44-23.893333-53.333333-53.333333-53.333333H245.333333z" p-id="4451"></path></svg>
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file