把index.html 中引入eel.js 后,eel这个对象就是全局对象了,无论在index.htm中还是组件中,都能使用这个全局对象。
我们组件HelloWorld.vue挂载到组件App.vue上,然后把App.vue挂载到index.html 这样最常见的结构为例:
HelloWorld.vue
//HelloWorld.vue
<script setup>
import { ref } from 'vue'
const count = ref(0)
const message = ref("Hello World!")
const sayHelloByEEL = (x) => {
eel.say_hello_py(x + Math.floor(Math.random() * 101).toString() + 'ee')
}
const sayHelloJS = (x) => {
message.value = 'Say Hello From ' + Math.floor(Math.random() * 101).toString() +x;
}
//暴露sayHelloJS给Python (以say_hello_js为别名)
eel.expose(sayHelloJS, 'say_hello_js')
</script>
<template>
<p><button type="button" @click="count++">count is: {{ count }}</button></p>
<p><button @click="sayHelloByEEL('Javascript Button! ')">调用Python函数</button></p>
<p>{{ message }}</p>
<p><button @click="sayHelloJS(' JS Button!')">调用JS函数</button></p>
</template>
<style scoped>
</style>
App.vue
//App.vue
<template>
<img alt="Vue logo" src="./assets/vue.svg"> python eel + Vue3
<HelloWorld />
</template>
<script setup>
import HelloWorld from './components/HelloWorld.vue';
</script>
<style>
#app {
text-align: center;
margin-top: 60px;
}
</style>
index.html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Apple</title>
<!-- 开发环境python端用9000端口,生产环境请换回相对路径 "/eel.js",及去掉window.eel.set_host("ws://localhost:9000"); 这句 -->
<script type=text/javascript src="http://localhost:9000/eel.js"></script>
<script>
window.eel.set_host("ws://localhost:9000");
</script>
</head>
<body style="margin: 0;">
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
main.js
//main.js
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App);
app.mount('#app');
main.py
# main.py
import eel
eel.init('web', allowed_extensions=['.js', '.html'])
@eel.expose
def say_hello_py(x):
print('Hello from %s' % x)
say_hello_py('Python World!')
eel.say_hello_js('Python World!')
eel.start({'port': 5173},port= 9000)
如果要更灵活的测试,可用通过tkinter触发js_function。代码如下:
# tkinter_test_main.py
import eel
eel.init('web', allowed_extensions=['.js', '.html'])
@eel.expose
def say_hello_py(x):
print('Hello from %s' % x)
def on_button_click():
"""Generate a random number and call the JavaScript function via Eel"""
random_number = random.randint(0, 100)
eel.say_hello_js(f"python {random_number}")
def create_tkinter_window():
"""Create a simple Tkinter window with a button"""
root = tk.Tk()
root.title("Tkinter with Eel")
Button(root, text="Send Random Number to JS", command=on_button_click).pack(pady=20)
root.mainloop()
def run_tkinter():
threading.Thread(target=create_tkinter_window, daemon=True).start()
if __name__ == "__main__":
import tkinter as tk
from tkinter import Button
import random
import threading
run_tkinter() # Create and run the Tkinter window in a separate thread
say_hello_py('Python World!')
eel.say_hello_js('Python World!')
eel.start({'port': 5173},port= 9000)
======================
但VUE并不建议在组件中直接使用全局变量,推荐把全局变量绑定到vue的全局属性中。这样变量的更改是响应性的,会触发组件更新,确保组件反映最新状态。即:vue2使用 Vue.prototype.$eel = window.eel; vue3使用 app.config.globalProperties.$eel = window['eel']
vue2 的例子:https://gitee.com/sunflower.git.isc/python-eel-vue (Vue.prototype)
vue3的例子: https://github.com/youfak/python-eel-vite-vue-ts (app.config.globalProperties)
我把以上vue3的例子化简了一下,把 hooksuseCurrentInstance 合并到组件中,并把ts改为js。
main.js
//main.js
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App);
// 在 Vue 3 中添加全局属性(例如 `$eel`)
app.config.globalProperties.$eel = window.eel;
app.mount('#app');
App.vue
<template>
<img alt="Vue logo" src="./assets/vue.svg"> python eel + Vue3
<HelloWorld />
</template>
<script>
import HelloWorld from './components/HelloWorld.vue';
export default {
name: 'App',
components: {
HelloWorld
}
}
</script>
<style>
#app {
text-align: center;
margin-top: 60px;
}
</style>
HelloWorld.vue
// HelloWorld.vue
<script setup>
//定义getCurrentInstance().appContext.config.globalProperties
import { ref, onMounted,getCurrentInstance } from 'vue'
const instance = getCurrentInstance();
const globalProperties = instance.appContext.config.globalProperties;
// create a reactive count using ref
const count = ref(0)
const message = ref("Hello World!")
const sayHelloByEEL = (x) => {
globalProperties.$eel.say_hello_py(x + Math.floor(Math.random() * 101).toString())
}
const sayHelloJS = (x) => {
message.value = 'Say Hello From ' + Math.floor(Math.random() * 101).toString() +x;
}
//使用 globalProperties 暴露sayHelloJS给Python (以say_hello_js为别名)
globalProperties.$eel.expose(sayHelloJS, 'say_hello_js')
onMounted(() => {
console.log(globalProperties)
})
</script>
<template>
<p><button type="button" @click="count++">count is: {{ count }}</button></p>
<p><button @click="sayHelloByEEL('Javascript Button! ')">调用Python函数</button></p>
<p>{{ message }}</p>
<p><button @click="sayHelloJS(' JS Button!')">调用JS函数</button></p>
</template>
<style scoped>
</style>