# 需求

vue template里面的事件名只能已on 开头

实现效果

image-20230528172725188

实现步骤

创建调试程序和 eslint 插件程序

创建调试程序

我创建的文件夹名称为eslint-demo

1
pnpm create vue

创建eslint 插件程序

我创建的文件夹名称为v-on-name-sartwith-on

首先安装eslint 脚手架

1
2
3
pnpm i -g yo
pnpm i -g generator-eslint

生成 Eslint 插件工程。

1
yo eslint:plugin

为插件创建一条规则,执行如下命令:

1
yo eslint:rule

文件目录参考

image-20230528173706552

link 插件

v-on-name-sartwith-on 这个项目里面执行

1
pnpm link --global

eslint-demo 这个项目里面执行(注意, 这里的名称是package.json 里面的名称)

1
2
pnpm link --global eslint-plugin-v-on-handler-name-style

编写代码

eslint-demo项目 App.vue

1
2
3
4
5
6
7
8
9
10
<script setup>
const handler = () => {
console.log('123')
}
</script>

<template>
<p @click="handler" class="a"></p>
</template>

v-on-name-sartwith-on 项目

lib/index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/**
* @fileoverview 判断 v-on 的 handler 是否已 on 开头
* @author abigmiu
*/
'use strict';

// const vueParser = require.resolve('vue-eslint-parser');

//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------

const requireIndex = require('requireindex');

//------------------------------------------------------------------------------
// Plugin Definition
//------------------------------------------------------------------------------

const rules = requireIndex(__dirname + '/rules');
module.exports = {
configs: {
recommended: {
plugins: ['v-on-handler-name-style'],
rules: {
'v-on-handler-name-style/v-on-handler-name-style': ['error'],
},
},
},
parser: require.resolve('vue-eslint-parser'), // 这里可能要安装vue-eslint-parser
env: {
browser: true,
es6: true,
},
rules: rules,
};

lib/rules/v-on-handler-name-style.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/**
* @fileoverview 判断 v-on 的 handler 是否已 on 开头
* @author abigmiu
*/
'use strict';
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
meta: {
type: 'suggestion',
docs: {
description: '判断 v-on 的 handler 规则',
},
fixable: 'code', // Or `code` or `whitespace`
schema: [],
messages: {
error: '事件名不已 on 开头',
},
},

create(context) {
// variables should be defined here

//----------------------------------------------------------------------
// Helpers
//----------------------------------------------------------------------

// any helper functions should go here or else delete this section

//----------------------------------------------------------------------
// Public
//----------------------------------------------------------------------
return context.parserServices.defineTemplateBodyVisitor({
"VAttribute[directive=true][key.name.name='on'][key.argument!=null]"(
node
) {
const value = node.value;
if (value.type === 'VExpressionContainer') {
const expression = value.expression;
const reg = /^on[A-Z]/;
if (!reg.test(expression.name)) {
context.report({
node,
messageId: 'error',
loc: value.loc,
});
}
}
},
// visitor functions for different types of nodes
});
},
};

为什么需要context.parserServices.defineTemplateBodyVisitor

vue-eslint-parser 提供了以下三个处理api 方法:

1
2
3
4
5
6
7
// 处理 template 语法树遍历方法
// Define handlers to traverse the template body
context.parserServices.defineTemplateBodyVisitor()
// 获取缓存的 template 语法树结构
context.parserServices.getTemplateBodyTokenStore()
// 获取根结点 document fragment.
context.parserServices.getDocumentFragment()

VAttribute[directive=true][key.name.name=’on’][key.argument!=null] 这个选择器怎么确定的

AST explorer 用这个网站, 注意红框位置, 要选择对应的选择器 才能选择

image-20230528174142371

参考链接

手把手教你实现一个自定义 eslint 规则 - 掘金 (juejin.cn)

写一个 eslint 插件:vue template 中 class 顺序的检查和自动修复 - 掘金 (juejin.cn)

自定义 Eslint 开发 · Issue #70 · pfan123/Articles (github.com)