Skip to content

Commit def674b

Browse files
committed
refactor: improve readability and add more comments to explain native event handling
1 parent feb4f03 commit def674b

File tree

3 files changed

+110
-81
lines changed

3 files changed

+110
-81
lines changed

README.md

Lines changed: 72 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,78 @@ See more examples [here](https://github.com/ecomfe/vue-echarts/tree/main/src/dem
319319

320320
For performance critical scenarios (having a large dataset) we'd better bypass Vue's reactivity system for `option` prop. By specifying `manual-update` prop with `true` and not providing `option` prop, the dataset won't be watched any more. After doing so, you need to retrieve the component instance with `ref` and manually call `setOption` method to update the chart.
321321

322+
### Events
323+
324+
You can bind events with Vue's `v-on` directive.
325+
326+
```vue
327+
<template>
328+
<v-chart :option="option" @highlight="handleHighlight" />
329+
</template>
330+
```
331+
332+
> **Note**
333+
>
334+
> Only the `.once` event modifier is supported as other modifiers are tightly coupled with the DOM event system.
335+
336+
Vue-ECharts support the following events:
337+
338+
- `highlight` [](https://echarts.apache.org/en/api.html#events.highlight)
339+
- `downplay` [](https://echarts.apache.org/en/api.html#events.downplay)
340+
- `selectchanged` [](https://echarts.apache.org/en/api.html#events.selectchanged)
341+
- `legendselectchanged` [](https://echarts.apache.org/en/api.html#events.legendselectchanged)
342+
- `legendselected` [](https://echarts.apache.org/en/api.html#events.legendselected)
343+
- `legendunselected` [](https://echarts.apache.org/en/api.html#events.legendunselected)
344+
- `legendselectall` [](https://echarts.apache.org/en/api.html#events.legendselectall)
345+
- `legendinverseselect` [](https://echarts.apache.org/en/api.html#events.legendinverseselect)
346+
- `legendscroll` [](https://echarts.apache.org/en/api.html#events.legendscroll)
347+
- `datazoom` [](https://echarts.apache.org/en/api.html#events.datazoom)
348+
- `datarangeselected` [](https://echarts.apache.org/en/api.html#events.datarangeselected)
349+
- `timelinechanged` [](https://echarts.apache.org/en/api.html#events.timelinechanged)
350+
- `timelineplaychanged` [](https://echarts.apache.org/en/api.html#events.timelineplaychanged)
351+
- `restore` [](https://echarts.apache.org/en/api.html#events.restore)
352+
- `dataviewchanged` [](https://echarts.apache.org/en/api.html#events.dataviewchanged)
353+
- `magictypechanged` [](https://echarts.apache.org/en/api.html#events.magictypechanged)
354+
- `geoselectchanged` [](https://echarts.apache.org/en/api.html#events.geoselectchanged)
355+
- `geoselected` [](https://echarts.apache.org/en/api.html#events.geoselected)
356+
- `geounselected` [](https://echarts.apache.org/en/api.html#events.geounselected)
357+
- `axisareaselected` [](https://echarts.apache.org/en/api.html#events.axisareaselected)
358+
- `brush` [](https://echarts.apache.org/en/api.html#events.brush)
359+
- `brushEnd` [](https://echarts.apache.org/en/api.html#events.brushEnd)
360+
- `brushselected` [](https://echarts.apache.org/en/api.html#events.brushselected)
361+
- `globalcursortaken` [](https://echarts.apache.org/en/api.html#events.globalcursortaken)
362+
- `rendered` [](https://echarts.apache.org/en/api.html#events.rendered)
363+
- `finished` [](https://echarts.apache.org/en/api.html#events.finished)
364+
- Mouse events
365+
- `click` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.click)
366+
- `dblclick` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.dblclick)
367+
- `mouseover` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.mouseover)
368+
- `mouseout` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.mouseout)
369+
- `mousemove` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.mousemove)
370+
- `mousedown` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.mousedown)
371+
- `mouseup` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.mouseup)
372+
- `globalout` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.globalout)
373+
- `contextmenu` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.contextmenu)
374+
- ZRender events
375+
- `zr:click`
376+
- `zr:mousedown`
377+
- `zr:mouseup`
378+
- `zr:mousewheel`
379+
- `zr:dblclick`
380+
- `zr:contextmenu`
381+
382+
See supported events [here →](https://echarts.apache.org/en/api.html#events)
383+
384+
#### Native DOM Events
385+
386+
As Vue-ECharts binds events to the ECharts instance by default, there is some caveat when using native DOM events. You need to prefix the event name with `native:` to bind native DOM events (or you can use the `.native` modifier in Vue 2, which is dropped in Vue 3).
387+
388+
```vue
389+
<template>
390+
<v-chart @native:click="handleClick" />
391+
</template>
392+
```
393+
322394
### Provide / Inject
323395

324396
Vue-ECharts provides provide/inject API for `theme`, `init-options`, `update-options` and `loading-options` to help configuring contextual options. eg. for `init-options` you can use the provide API like this:
@@ -402,76 +474,6 @@ import { THEME_KEY } from 'vue-echarts'
402474
403475
Static methods can be accessed from [`echarts` itself](https://echarts.apache.org/en/api.html#echarts).
404476
405-
### Events
406-
407-
You can bind events with Vue's `v-on` directive.
408-
409-
```vue
410-
<template>
411-
<v-chart :option="option" @highlight="handleHighlight" />
412-
</template>
413-
```
414-
415-
> **Note**
416-
>
417-
> Only the `.once` event modifier is supported as other modifiers are tightly coupled with the DOM event system.
418-
419-
Vue-ECharts support the following events:
420-
421-
- `highlight` [](https://echarts.apache.org/en/api.html#events.highlight)
422-
- `downplay` [](https://echarts.apache.org/en/api.html#events.downplay)
423-
- `selectchanged` [](https://echarts.apache.org/en/api.html#events.selectchanged)
424-
- `legendselectchanged` [](https://echarts.apache.org/en/api.html#events.legendselectchanged)
425-
- `legendselected` [](https://echarts.apache.org/en/api.html#events.legendselected)
426-
- `legendunselected` [](https://echarts.apache.org/en/api.html#events.legendunselected)
427-
- `legendselectall` [](https://echarts.apache.org/en/api.html#events.legendselectall)
428-
- `legendinverseselect` [](https://echarts.apache.org/en/api.html#events.legendinverseselect)
429-
- `legendscroll` [](https://echarts.apache.org/en/api.html#events.legendscroll)
430-
- `datazoom` [](https://echarts.apache.org/en/api.html#events.datazoom)
431-
- `datarangeselected` [](https://echarts.apache.org/en/api.html#events.datarangeselected)
432-
- `timelinechanged` [](https://echarts.apache.org/en/api.html#events.timelinechanged)
433-
- `timelineplaychanged` [](https://echarts.apache.org/en/api.html#events.timelineplaychanged)
434-
- `restore` [](https://echarts.apache.org/en/api.html#events.restore)
435-
- `dataviewchanged` [](https://echarts.apache.org/en/api.html#events.dataviewchanged)
436-
- `magictypechanged` [](https://echarts.apache.org/en/api.html#events.magictypechanged)
437-
- `geoselectchanged` [](https://echarts.apache.org/en/api.html#events.geoselectchanged)
438-
- `geoselected` [](https://echarts.apache.org/en/api.html#events.geoselected)
439-
- `geounselected` [](https://echarts.apache.org/en/api.html#events.geounselected)
440-
- `axisareaselected` [](https://echarts.apache.org/en/api.html#events.axisareaselected)
441-
- `brush` [](https://echarts.apache.org/en/api.html#events.brush)
442-
- `brushEnd` [](https://echarts.apache.org/en/api.html#events.brushEnd)
443-
- `brushselected` [](https://echarts.apache.org/en/api.html#events.brushselected)
444-
- `globalcursortaken` [](https://echarts.apache.org/en/api.html#events.globalcursortaken)
445-
- `rendered` [](https://echarts.apache.org/en/api.html#events.rendered)
446-
- `finished` [](https://echarts.apache.org/en/api.html#events.finished)
447-
- Mouse events
448-
- `click` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.click)
449-
- `dblclick` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.dblclick)
450-
- `mouseover` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.mouseover)
451-
- `mouseout` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.mouseout)
452-
- `mousemove` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.mousemove)
453-
- `mousedown` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.mousedown)
454-
- `mouseup` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.mouseup)
455-
- `globalout` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.globalout)
456-
- `contextmenu` [](https://echarts.apache.org/en/api.html#events.Mouse%20events.contextmenu)
457-
- ZRender events
458-
- `zr:click`
459-
- `zr:mousedown`
460-
- `zr:mouseup`
461-
- `zr:mousewheel`
462-
- `zr:dblclick`
463-
- `zr:contextmenu`
464-
465-
See supported events [here →](https://echarts.apache.org/en/api.html#events)
466-
467-
#### Native DOM Events
468-
469-
```vue
470-
<template>
471-
<v-chart @native:click="handleClick" />
472-
</template>
473-
```
474-
475477
## CSP: `style-src` or `style-src-elem`
476478
477479
If you are applying a CSP to prevent inline `<style>` injection, you need to use files from `dist/csp` directory and include `dist/csp/style.css` into your app manually.

README.zh-Hans.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,16 @@ Vue-ECharts 支持如下事件:
381381

382382
请参考支持的事件列表。[前往 →](https://echarts.apache.org/zh/api.html#events)
383383

384+
#### 原生 DOM 事件
385+
386+
由于 Vue-ECharts 默认将事件绑定到 ECharts 实例,因此在使用原生 DOM 事件时需要做一些特殊处理。你需要在事件名称前加上 `native:` 前缀来绑定原生 DOM 事件(可以在 Vue 2 中也可以使用 `.native` 修饰符,但这在 Vue 3 中已被废弃)。
387+
388+
```vue
389+
<template>
390+
<v-chart @native:click="handleClick" />
391+
</template>
392+
```
393+
384394
### Provide / Inject
385395

386396
Vue-ECharts 为 `theme``init-options``update-options``loading-options` 提供了 provide/inject API,以通过上下文配置选项。例如:可以通过如下方式来使用 provide API 为 `init-options` 提供上下文配置:
@@ -464,6 +474,8 @@ import { THEME_KEY } from 'vue-echarts'
464474
465475
静态方法请直接通过 [`echarts` 本身](https://echarts.apache.org/zh/api.html#echarts)进行调用。
466476
477+
478+
467479
## CSP: `style-src``style-src-elem`
468480
469481
如果你正在应用 CSP 来防止内联 `<style>` 注入,则需要使用 `dist/csp` 目录中的文件,并手动引入 `dist/csp/style.css`

src/ECharts.ts

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ export const UPDATE_OPTIONS_KEY =
5555
"ecUpdateOptions" as unknown as InjectionKey<UpdateOptionsInjection>;
5656
export { LOADING_OPTIONS_KEY } from "./composables";
5757

58+
const NATIVE_EVENT_RE = /(^&?~?!?)native:/;
59+
5860
export default defineComponent({
5961
name: "echarts",
6062
props: {
@@ -95,7 +97,7 @@ export default defineComponent({
9597
() => props.updateOptions || unwrapInjected(defaultUpdateOptions, {})
9698
);
9799
const nonEventAttrs = computed(() => omitOn(attrs));
98-
const nativeEventAttrs: Record<string, unknown> = {};
100+
const nativeListeners: Record<string, unknown> = {};
99101

100102
// @ts-expect-error listeners for Vue 2 compatibility
101103
const listeners = getCurrentInstance().proxy.$listeners;
@@ -116,7 +118,14 @@ export default defineComponent({
116118
}
117119

118120
const realListeners: Record<string, any> = {};
121+
119122
if (!listeners) {
123+
// This is for Vue 3.
124+
// We are converting all `on<Event>` props to event listeners compatible with Vue 2
125+
// and collect them into `realListeners` so that we can bind them to the chart instance
126+
// later in the same way.
127+
// For `onNative:<event>` props, we just strip the `Native:` part and collect them into
128+
// `nativeListeners` so that we can bind them to the root element directly.
120129
Object.keys(attrs)
121130
.filter(key => isOn(key))
122131
.forEach(key => {
@@ -125,12 +134,13 @@ export default defineComponent({
125134
let event = key.charAt(2).toLowerCase() + key.slice(3);
126135

127136
// Collect native DOM events
128-
if (event.startsWith("native:")) {
137+
if (event.indexOf("native:") === 0) {
129138
// native:click -> onClick
130-
const nativeKey =
131-
"on" + event.charAt(7).toUpperCase() + event.slice(8);
139+
const nativeKey = `on${event
140+
.charAt(7)
141+
.toUpperCase()}${event.slice(8)}`;
132142

133-
nativeEventAttrs[nativeKey] = attrs[key];
143+
nativeListeners[nativeKey] = attrs[key];
134144
return;
135145
}
136146

@@ -143,13 +153,18 @@ export default defineComponent({
143153
realListeners[event] = attrs[key];
144154
});
145155
} else {
156+
// This is for Vue 2.
157+
// We just need to distinguish normal events and `native:<event>` events and
158+
// collect them into `realListeners` and `nativeListeners` respectively.
159+
// For `native:<event>` events, we just strip the `native:` part and collect them
160+
// into `nativeListeners` so that we can bind them to the root element directly.
146161
// native:click -> click
147162
// ~native:click -> ~click
148163
// &~!native:click -> &~!click
149-
const regex = /(^&?~?!?)native:/;
150164
Object.keys(listeners).forEach(key => {
151-
if (regex.test(key)) {
152-
nativeEventAttrs[key.replace(regex, "$1")] = listeners[key];
165+
if (NATIVE_EVENT_RE.test(key)) {
166+
nativeListeners[key.replace(NATIVE_EVENT_RE, "$1")] =
167+
listeners[key];
153168
} else {
154169
realListeners[key] = listeners[key];
155170
}
@@ -317,7 +332,7 @@ export default defineComponent({
317332
inner,
318333
setOption,
319334
nonEventAttrs,
320-
nativeEventAttrs,
335+
nativeListeners,
321336
...publicApi
322337
};
323338
},
@@ -326,8 +341,8 @@ export default defineComponent({
326341
// See https://v3-migration.vuejs.org/breaking-changes/render-function-api.html#vnode-props-format
327342
const attrs = (
328343
Vue2
329-
? { attrs: this.nonEventAttrs, on: this.nativeEventAttrs }
330-
: { ...this.nonEventAttrs, ...this.nativeEventAttrs }
344+
? { attrs: this.nonEventAttrs, on: this.nativeListeners }
345+
: { ...this.nonEventAttrs, ...this.nativeListeners }
331346
) as any;
332347
attrs.ref = "root";
333348
attrs.class = attrs.class ? ["echarts"].concat(attrs.class) : "echarts";

0 commit comments

Comments
 (0)