英文:
Common code visible at root scope in Svelte
问题
我将以下内容翻译为中文:
我在一个 Svelte 应用程序 v.3.54.0 中集成了 Google 登录按钮(https://developers.google.com/identity/gsi/web/guides/personalized-button)。
该按钮需要一个全局范围内的函数作为回调(data-callback
属性),例如:
<div
id="g_id_onload"
data-client_id="<id>.apps.googleusercontent.com"
data-context="signin"
data-ux_mode="popup"
data-callback="handleCredentialResponse"
data-auto_prompt="false"
></div>
<div
class="g_id_signin"
data-type="standard"
data-shape="rectangular"
data-theme="filled_blue"
data-text="signin_with"
data-size="large"
data-logo_alignment="left"
></div>
我希望 handleCredentialResponse
函数不在 app.html
中,因为我需要在实现中使用其他导入的模块,例如:
function handleCredentialResponse(response) {
localStorage.setItem("googleCredentials", JSON.stringify(response));
let jwt = jwt_decode(JSON.parse(response).credential);
localStorage.setItem('decodedJwt', JSON.stringify(jwt));
window.location.reload();
}
在这里,我使用了从 jwt-decode
导入的 jwt_decode
。
如果我将 handleCredentialResponse
包含在 app.html
中的 script
标签中,我会得到一个错误,因为在这个级别上 jwt_decode
未定义。我将不得不通过另一个 script
标签包含 jwt_decode
,这是我想要避免的。
另一方面,如果我在 Svelte 组件中编写函数(即使使用 context="module"
),Google 按钮会抱怨回调对它不可见。
目前,我使用了一个解决方法,在 app.html
中的一部分逻辑和 +layout.svelte
中的一部分逻辑在 onMount
中,但我真的不喜欢这种方式。
在 Svelte 应用程序中,有没有一种处理这种需求的方式?或者换句话说,在 Svelte 应用程序中是否有一个可以编写公共代码并且也可见于根范围的地方(可能仅在第一次加载时执行)?
英文:
I integrated the Google Sign In button (https://developers.google.com/identity/gsi/web/guides/personalized-button) in a Svelte application v.3.54.0.
The button requires a function in the global scope as a callback (data-callback
attribute), e.g.:
<div
id="g_id_onload"
data-client_id="<id>.apps.googleusercontent.com"
data-context="signin"
data-ux_mode="popup"
data-callback="handleCredentialResponse"
data-auto_prompt="false"
/>
<div
class="g_id_signin"
data-type="standard"
data-shape="rectangular"
data-theme="filled_blue"
data-text="signin_with"
data-size="large"
data-logo_alignment="left"
/>
I would like the handleCredentialResponse
function to reside in a source file other than app.html
, because I need to use other imported modules in the implementation, e.g.:
function handleCredentialResponse(response) {
localStorage.setItem("googleCredentials", JSON.stringify(response));
let jwt = jwt_decode(JSON.parse(response).credential);
localStorage.setItem('decodedJwt', JSON.stringify(jwt));
window.location.reload();
}
Here I use jwt_decode
which is imported from jwt-decode
.
If I include handleCredentialResponse
in a script
tag in app.html
, I get an error because jwt_decode
is not defined at this level. I would have to include jwt_decode
via another script
tag, which I rather avoid.
On the other hand, if I write the function in a Svelte component (even with context="module"
), the Google Button complains because the callback is not visible to it.
Currently I use a workaroud where I have part of the logic in app.html and part in the +layout.svelte onMount
, but I really do not like it.
What is the Svelte way to deal with this need? Or, in other words, is there a place in a svelte application where I can write common code that is also visible at the root scope (and, possibly, that gets executed only once at the first loading)?
答案1
得分: 1
事后看来,从一开始就应该很容易。我只需在HTML中省略data-callback
属性,并将其推迟到<script>
部分,像这样:
<script>
import { onMount } from 'svelte';
import jwt_decode from 'jwt-decode';
function handleCredentialResponse(response) {
localStorage.setItem('googleCredentials', JSON.stringify(response));
let jwt = jwt_decode(response.credential);
localStorage.setItem('decodedJwt', JSON.stringify(jwt));
window.location.reload();
}
onMount(() => {
google.accounts.id.initialize({
client_id: '<id>.apps.googleusercontent.com',
callback: handleCredentialResponse
});
const parent = document.getElementById('g_id_onload');
google.accounts.id.renderButton(parent, { theme: 'filled_blue' });
});
</script>
它正常工作。
英文:
In hindsight it should have been very easy from the start. I can just omit the data-callback
attribute in the HTML and defer it to the <script>
section like this:
<script>
import { onMount } from 'svelte';
import jwt_decode from 'jwt-decode';
function handleCredentialResponse(response) {
localStorage.setItem('googleCredentials', JSON.stringify(response));
let jwt = jwt_decode(response.credential);
localStorage.setItem('decodedJwt', JSON.stringify(jwt));
window.location.reload();
}
onMount(() => {
google.accounts.id.initialize({
client_id: '<id>.apps.googleusercontent.com',
callback: handleCredentialResponse
});
const parent = document.getElementById('g_id_onload');
google.accounts.id.renderButton(parent, { theme: 'filled_blue' });
});
</script>
It works fine.
答案2
得分: 0
我不认为有一种"Svelte方式"来处理这个问题,因为通常应该避免这样做。如果没有其他方法,我只会通过将该函数设置在window
上,使其在全局范围内可用:
onMount(() => {
window.handleCredentialResponse = ...
})
(使用onMount
是因为在服务器端进行SSR时,这将无法工作。)
英文:
I don't think there is a "Svelte way" for this, as that should generally be avoided. If there is no other way, I would just make the function globally available by setting it on the window
:
onMount(() => {
window.handleCredentialResponse = ...
})
(onMount
is used because this will not work on the server during SSR.)
答案3
得分: -1
只需创建一个次要的“main”脚本,引入必要的功能并创建HTML的Google按钮。这样应该可以正常工作。这样,按钮在相应的功能加载之前是不存在的。
英文:
Just create a secondary "main" script that brings the necessary function and creates the HTML Google button. That should work ok. This way, the button doesn't exist until the corresponding function has been loaded.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论