Vue3中使用Supabase?Auth方法詳解
引言
Supabase是一個(gè)自稱的 "開源Firebase替代品"。我對(duì)與Supbase合作已經(jīng)有一段時(shí)間了,我想我將嘗試使用他們的認(rèn)證API來(lái)為Vue.js 3應(yīng)用程序進(jìn)行認(rèn)證設(shè)置。
首先,你為什么要使用Supabase Auth?最重要的是,如果你使用Supabase作為你的數(shù)據(jù)存儲(chǔ),(它有一些非常甜蜜的好處),Supabase Auth是你可以管理對(duì)這些數(shù)據(jù)的訪問(wèn)的唯一方法。其次,雖然Supabase Auth也有許多不同的功能。
- 沒(méi)有中間件的用戶權(quán)限(通過(guò)Postgres的行級(jí)安全)。
- 神奇的電子郵件鏈接
- 社交提供者的登錄
- 以及所有其他你期望的封裝在一個(gè)簡(jiǎn)單的JavaScript SDK中的Auth功能
綜上所述,值得一提的是,Supabase Auth不是一個(gè)獨(dú)立的認(rèn)證提供商,它只是為了與其他Supabase服務(wù)(數(shù)據(jù)、存儲(chǔ)等)一起使用。
好了,讓我們開始在我們的Vue.js 3應(yīng)用程序中實(shí)施Supabase Auth。
安裝Supabase
我假設(shè)你已經(jīng)有了一個(gè)用Vue Router設(shè)置的Vue.js 3應(yīng)用程序,如果沒(méi)有,你可以下載這個(gè)模板代碼來(lái)進(jìn)行操作。我還假設(shè)你已經(jīng)有了一個(gè)Supabase賬戶和項(xiàng)目設(shè)置。如果沒(méi)有,你可以前往supabase.io,它將引導(dǎo)你完成第一步。
然后,為了與Supabase auth以及它的任何其他服務(wù)合作,我們需要安裝Supabase JavaScript SDK。
npm install @supabase/supabase-js
設(shè)置Supabase
安裝完Supabase后,我們需要經(jīng)過(guò)幾個(gè)步驟來(lái)設(shè)置它。我將創(chuàng)建一個(gè)名為UseSupabase.js 的組合,用來(lái)組織這個(gè)設(shè)置。
// UseSupabase.js
import { createClient } from "@supabase/supabase-js";
// these can come from an environment variable if desired
// not required however as they are 100% exposed on the client side anyway
// and that's ok, Supabase expects this (security is provided by Row Level Security)
const supabaseUrl = "";
const supabaseKey = "";
// setup client
const supabase = createClient(supabaseUrl, supabaseKey);
// expose supabase client
export default function useSupabase() {
return { supabase };
}
supabaseUrl和supabaseKey可以在Supabase儀表板上的Settings > API 。
當(dāng)你在Supabase界面時(shí),你也可以到Autentication > Settings ,設(shè)置你的網(wǎng)站網(wǎng)址,以便Supabase知道如何正確地重定向確認(rèn)郵件等。它的默認(rèn)值是localhost:3000,但你可以根據(jù)需要進(jìn)行修改。
創(chuàng)建一個(gè)AuthUser組合
設(shè)置好Supabase SDK后,我們現(xiàn)在可以開始使用它了。首先,我將創(chuàng)建一個(gè)AuthUser組合,以抽象出與AuthUser的一些交互,并存留所有我們需要填寫的方法。這在我們將來(lái)想脫離Supabase時(shí)很有幫助,并幫助我們把所有的AuthUser功能集中到一個(gè)地方。
import { ref } from "vue";
// user is set outside of the useAuthUser function
// so that it will act as global state and always refer to a single user
const user = ref(null);
export default function useAuthUser() {
/**
* Login with email and password
*/
const login = async ({ email, password }) => {};
/**
* Login with google, github, etc
*/
const loginWithSocialProvider = (provider) => {};
/**
* Logout
*/
const logout = async () => {};
/**
* Check if the user is logged in or not
*/
const isLoggedIn = () => {};
/**
* Register
*/
const register = async ({ email, password, ...meta }) => {};
/**
* Update user email, password, or meta data
*/
const update = async (data) => {};
/**
* Send user an email to reset their password
* (ie. support "Forgot Password?")
*/
const sendPasswordRestEmail = async (email) => {};
return {
user,
login,
loginWithSocialProvider,
isLoggedIn,
logout,
register,
update,
sendPasswordRestEmail,
maybeHandleEmailConfirmation,
};
}
創(chuàng)建頁(yè)面
接下來(lái),讓我們來(lái)創(chuàng)建典型用戶認(rèn)證流程所需的頁(yè)面。我使用Tailwind CSS做了一些樣式設(shè)計(jì),但可以根據(jù)你的需要自由調(diào)整這些樣式。
注冊(cè).vue
我們需要的第一個(gè)頁(yè)面是一個(gè)注冊(cè)頁(yè)面。它需要包含必要的字段,以便在Supabase中創(chuàng)建一個(gè)用戶。這些字段是電子郵件和密碼。我們也可以在Supabase中為我們的用戶添加任意的元數(shù)據(jù),這意味著我們也可以讓用戶的真實(shí)姓名成為注冊(cè)的一部分。
// Register.vue
<script>...</script>
<template>
<form class="max-w-lg m-auto" @submit.prevent="handleSubmit">
<h1 class="text-3xl mb-5">Register</h1>
<label>Name <input v-model="form.name" type="text" /></label>
<label>Email <input v-model="form.email" type="email" /></label>
<label>Password <input v-model="form.password" type="password" /></label>
<button>Register</button>
</form>
</template>
在腳本部分,我們可以使用一個(gè)反應(yīng)式引用來(lái)跟上表單的數(shù)據(jù),同時(shí)提供一個(gè)函數(shù)來(lái)處理表單的提交。在表單提交時(shí),我們將從AuthUser組合中調(diào)用注冊(cè)函數(shù)(它仍然是空的,但我們將在稍后用supabase的具體調(diào)用來(lái)填充它),然后重定向到一個(gè)頁(yè)面,指示用戶檢查他們的電子郵件以確認(rèn)注冊(cè)。
// Register.vue
<script setup>
import { ref } from "vue";
import useAuthUser from "@/composables/UseAuthUser";
import { useRouter } from "vue-router";
// Use necessary composables
const router = useRouter();
const { register } = useAuthUser();
// Form reactive ref to keep up with the form data
const form = ref({
name: "",
email: "",
password: "",
});
// function to hand the form submit
const handleSubmit = async () => {
try {
// use the register method from the AuthUser composable
await register(form.value);
// and redirect to a EmailConfirmation page the will instruct
// the user to confirm they're email address
router.push({
name: "EmailConfirmation",
query: { email: form.value.email },
});
} catch (error) {
alert(error.message);
}
};
</script>
<template>...</template>
最后,我們需要為該頁(yè)面注冊(cè)路由。
// router/index.js
const routes = [
//...
{
name: "Register",
path: "/register",
component: () => import("@/pages/Register.vue"),
},
]
如果你使用了模板代碼,訪問(wèn)/register ,應(yīng)該會(huì)得到一個(gè)看起來(lái)像這樣的頁(yè)面。
EmailConfirmation.vue
既然我們?cè)谧?cè)后重定向到一個(gè)EmailConfirmation頁(yè)面,我們當(dāng)然需要讓它存在。它將只是一個(gè)簡(jiǎn)單的模板和一條信息。當(dāng)我們?cè)谏厦嬷囟ㄏ驎r(shí),我們也提供了來(lái)自注冊(cè)表單的電子郵件作為一個(gè)查詢變量,所以我們可以在這里顯示它。
<template>
<div>
<h1 class="text-3xl">Thanks for registering!</h1>
<p>
Please confirm your email to finishing registering:
{{ $route.query.email }}
</p>
</div>
</template>
再一次,我們也需要注冊(cè)這個(gè)路由。
// router/index.js
const routes = [
//...
{
name: "EmailConfirmation",
path: "/email-confirmation",
component: () => import("@/pages/EmailConfirmation.vue"),
},
]
現(xiàn)在訪問(wèn)帶有電子郵件查詢變量的/email-confirmation 路由將看起來(lái)像這樣。
登錄.vu
在注冊(cè)并確認(rèn)了他們的電子郵件后,用戶將不得不登錄。讓我們接下來(lái)創(chuàng)建這個(gè)頁(yè)面。
該模板將包括一個(gè)帶有電子郵件和密碼字段的表單,以及一個(gè)指向忘記密碼頁(yè)面的鏈接,還有一個(gè)處理Github登錄的鏈接。
<script>...</script>
<template>
<div class="max-w-lg m-auto">
<form @submit.prevent="handleLogin">
<h1 class="text-3xl mb-5">Login</h1>
<label>Email <input v-model="form.email" type="email" /></label>
<label>Password <input v-model="form.password" type="password" /></label>
<button>Login</button>
<router-link to="/forgotPassword">Forgot Password?</router-link>
</form>
<div class="mt-5">
<a @click.prevent="handleLogin('github')">Github</a>
</div>
</div>
</template>
在腳本部分,我們可以創(chuàng)建一個(gè)反應(yīng)式引用來(lái)跟上表單的值,以及一個(gè)函數(shù)來(lái)處理表單的提交。
<script setup>
import { ref } from "vue";
import useAuthUser from "@/composables/UseAuthUser";
import { useRouter } from "vue-router";
// Use necessary composables
const router = useRouter();
const { login, loginWithSocialProvider } = useAuthUser();
// keep up with form data
const form = ref({
email: "",
password: "",
});
// call the proper login method from the AuthUser composable
// on the submit of the form
const handleLogin = async (provider) => {
try {
provider
? await loginWithSocialProvider(provider)
: await login(form.value);
router.push({ name: "Me" });
} catch (error) {
alert(error.message);
}
};
</script>
<template>...</template>
注冊(cè)完路由后,你可以訪問(wèn)/login 路由,看到一個(gè)漂亮的登錄表單。
// router/index.js
const routes = [
//...
{
name: "Login",
path: "/login",
component: () => import("@/pages/Login.vue"),
},
]
ForgotPassword.vue
由于我們?cè)谏厦鎸?shí)現(xiàn)了一個(gè)忘記密碼的鏈接,讓我們也把這個(gè)頁(yè)面用腳手架搭出來(lái)。
在模板中,我們只需要一個(gè)帶有單個(gè)電子郵件字段的表單,以便收集我們應(yīng)該發(fā)送重置鏈接的電子郵件。
<script>...</script>
<template>
<form class="max-w-lg m-auto" @submit.prevent="handlePasswordReset()">
<h1 class="text-3xl mb-5">Forgot Password?</h1>
<label>Email <input v-model="email" type="email" /></label>
<button>Send Reset Email</button>
</form>
</template>
在腳本部分,我們將創(chuàng)建一個(gè)電子郵件反應(yīng)式參考,以跟上表單中的電子郵件輸入,并定義一個(gè)函數(shù),在表單提交時(shí)調(diào)用AuthUser可組合的sendPasswordRestEmail 函數(shù)。
<script setup>
import useAuthUser from "@/composables/UseAuthUser";
import { ref } from "vue";
// use necessary composables
const { sendPasswordRestEmail } = useAuthUser();
// keep up with email
const email = ref("");
// function to call on submit of the form
// triggers sending the reset email to the user
const handlePasswordReset = async () => {
await sendPasswordRestEmail(email.value);
alert(`Password reset email sent to: ${email.value}`);
};
</script>
最后,我們將注冊(cè)這個(gè)路由。
// router/index.js
const routes = [
//...
{
name: "ForgotPassword",
path: "/forgotPassword",
component: () => import("@/pages/ForgotPassword.vue"),
},
]
現(xiàn)在,點(diǎn)擊登錄頁(yè)面上的 "忘記密碼?"鏈接將把你帶到這里。
Me.vue
我們需要的最后一個(gè)頁(yè)面是一個(gè)個(gè)人資料頁(yè)面,在用戶登錄后顯示他們的秘密信息。我們將它稱為/me 。
// router/index.js
const routes = [
//...
{
name: "Me",
path: "/me",
component: () => import("@/pages/Me.vue"),
},
]
我們還將添加路由中間件,讓我們的程序知道這應(yīng)該是一個(gè)受保護(hù)的路由,只有通過(guò)認(rèn)證的用戶才能訪問(wèn)。
{
name: "Me",
meta: {
requiresAuth: true,
},
//...
},
然后,為了讓這個(gè)中間件真正發(fā)揮作用,我們需要這樣來(lái)實(shí)現(xiàn)它。
const router = createRouter({
history: createWebHistory(),
routes,
});
router.beforeEach((to) => {
// here we check it the user is logged in
// if they aren't and the route requries auth we redirect to the login page
const { isLoggedIn } = useAuthUser();
if (!isLoggedIn() && to.meta.requiresAuth) {
return { name: "Login" };
}
});
export default router;
頁(yè)面本身將是一個(gè)簡(jiǎn)單的問(wèn)候用戶的信息。
<script setup>
import useAuthUser from "@/composables/UseAuthUser";
const { user } = useAuthUser();
</script>
<template>
<div v-if="user">
<!--user_metadata is the key supabase nests all arbitrary meta data under-->
<div>Hello {{ user.user_metadata.name }}</div>
</div>
</template>
我們現(xiàn)在還不會(huì)嘗試查看這個(gè)頁(yè)面,因?yàn)槲覀冞€沒(méi)有實(shí)現(xiàn)登錄。
https://github.com/danielkellyio/supabase-auth-example
現(xiàn)在,頁(yè)面和AuthUser組合已經(jīng)到位,我們可以開始通過(guò)調(diào)用Supabase SDK來(lái)填充AuthUser組合函數(shù)的內(nèi)容。
我們需要做的第一件事是訪問(wèn)我們的Supabase客戶端。我們可以通過(guò)導(dǎo)入U(xiǎn)seSupabase可組合函數(shù)并從中解構(gòu)Supabase客戶端來(lái)做到這一點(diǎn)。
import useSupabase from "@/composables/UseSupabase";
export default function useAuthUser() {
const { supabase } = useSupabase();
//...
}
現(xiàn)在我們可以通過(guò)我們的空函數(shù),一個(gè)一個(gè)地填充它們。
login()
為了登錄Supabase,我們需要調(diào)用supabase.auth.signIn 。我們也可以等待響應(yīng),如果有錯(cuò)誤就拋出一個(gè)新的錯(cuò)誤,否則就返回登錄的用戶。
const login = async ({ email, password }) => {
const { user, error } = await supabase.auth.signIn({ email, password });
if (error) throw error;
return user;
};
loginWithSocialProvider()
loginWithSocialProvider也同樣簡(jiǎn)單。只需要將提供者傳遞給signIn方法。
const loginWithSocialProvider = async (token) => {
const { user, error } = await supabase.auth.signIn({ provider });
if (error) throw error;
return user;
};
logout()
現(xiàn)在,為了注銷,我們需要調(diào)用Supabase的signOut方法。由于用戶不再可用,所以沒(méi)有什么可以從注銷中返回。
const logout = async () => {
const { error } = await supabase.auth.signOut();
if (error) throw error;
};
isLoggedIn()
對(duì)于isLoggedIn函數(shù),我們只需檢查reactive ref user是否有一個(gè)值。
const isLoggedIn = () => {
return !!user.value;
};
如果你在想,我們?cè)诘卿浻脩魰r(shí)從來(lái)沒(méi)有設(shè)置過(guò)這個(gè)值,你是完全正確的,但我們將利用另一個(gè)小的supabase方法來(lái)幫助我們解決這個(gè)問(wèn)題,就在一分鐘之內(nèi)。
register()
register函數(shù)看起來(lái)幾乎和login函數(shù)一樣,接收電子郵件和密碼。然而,它也需要接受其他用戶信息(即元數(shù)據(jù))。另外,我們將重定向到個(gè)人資料頁(yè)面,并附上一些查詢變量,其中包含一些有用的信息。
const register = async ({ email, password, ...meta }) => {
const { user, error } = await supabase.auth.signUp(
{ email, password },
{
//arbitrary meta data is passed as the second argument under a data key
// to the Supabase signUp method
data: meta,
// the to redirect to after the user confirms their email
// window.location wouldn't be available if we were rendering server side
// but since we're all on the client it will work fine
redirectTo: `${window.location.origin}/me?fromEmail=registrationConfirmation"`,
}
);
if (error) throw error;
return user;
};
請(qǐng)注意這個(gè)很酷的小技巧,我們把meta:...meta 。這允許我們?cè)谡{(diào)用函數(shù)時(shí),在傳遞給函數(shù)的對(duì)象中提供同一層次的元數(shù)據(jù),但在函數(shù)中單獨(dú)訪問(wèn)它。
// for example
register({email: '[email protected]', password: 'password123', name: 'Daniel Kelly', favoriteFood: 'Spaghetti'})
// meta will be {name: 'Daniel Kelly', favoriteFood: 'Spaghetti'}
update()
雖然我們實(shí)際上沒(méi)有提供更新用戶的接口,但我們可以去實(shí)現(xiàn)這個(gè)函數(shù),因?yàn)镾upabase讓它變得如此簡(jiǎn)單。
const update = async (data) => {
const { user, error } = await supabase.auth.update(data);
if (error) throw error;
return user;
};
sendPasswordResetEmail()
最后一個(gè)要實(shí)現(xiàn)的函數(shù)是sendPasswordResetEmail 。再一次,supabase有一個(gè)簡(jiǎn)單的解決方案。
const sendPasswordRestEmail = async (email) => {
const { user, error } = await supabase.auth.api.resetPasswordForEmail(email);
if (error) throw error;
return user;
};
觀察Auth狀態(tài)的變化
在這一點(diǎn)上,我們幾乎已經(jīng)準(zhǔn)備好開始使用我們的接口了,但還有一個(gè)關(guān)鍵步驟需要執(zhí)行。我們需要知道用戶何時(shí)登錄或注銷,并相應(yīng)地更新AuthUser組合中的反應(yīng)式ref。
你的第一個(gè)想法可能是在登錄和注銷方法中完成這個(gè)任務(wù),這在某些時(shí)候是可行的。然而,如果用戶因?yàn)闀?huì)話過(guò)期而注銷了呢?或者如果用戶在Supabase那邊被更新或刪除了呢?在這兩種情況下,我們的登錄和注銷方法都不會(huì)被調(diào)用。
為了解決這個(gè)問(wèn)題,Supabase提供了一個(gè)叫做onAuthStateChange 的函數(shù)。
我們可以在我們的supabase組合中調(diào)用這個(gè)函數(shù),讓它監(jiān)聽auth狀態(tài)的所有變化,然后相應(yīng)地設(shè)置我們的用戶reactive ref。
// UseSupabase.js
import { createClient } from "@supabase/supabase-js";
import useAuthUser from "@/composables/UseAuthUser";
// config
const supabaseUrl = "";
const supabaseKey = "";
// setup client
const supabase = createClient(supabaseUrl, supabaseKey);
// ? setup auth state listener ?
supabase.auth.onAuthStateChange((event, session) => {
// the "event" is a string indicating what trigger the state change (ie. SIGN_IN, SIGN_OUT, etc)
// the session contains info about the current session most importanly the user dat
const { user } = useAuthUser();
// if the user exists in the session we're logged in
// and we can set our user reactive ref
user.value = session?.user || null;
});
// expose supabase client
export default function useSupabase() {
return { supabase };
}
我選擇在UseSupabase.js中的函數(shù)調(diào)用之外做這件事,這樣它就只被調(diào)用一次,并與其他Supabase設(shè)置代碼組織在一起。
測(cè)試東西
現(xiàn)在到了關(guān)鍵時(shí)刻。我們應(yīng)該有大部分的工作。(盡管你馬上就會(huì)看到,我們還需要再做一些調(diào)整)。在你的瀏覽器中導(dǎo)航到注冊(cè)頁(yè)面并注冊(cè)。
之后,你應(yīng)該成功地被重定向到EmailConfirmation頁(yè)面,你的電子郵件地址顯示在信息中。
另外,如果你檢查你的收件箱,你會(huì)像預(yù)期那樣收到電子郵件。
順便提一下,如果你想定制這封電子郵件的樣子,你可以在Supabase儀表板上的Authentication > Templates 。
另外,如果你在Authentication > Users ,你就可以看到你的新注冊(cè)用戶的狀態(tài)是:Waiting for Verication!
很好,現(xiàn)在去點(diǎn)擊電子郵件中的那個(gè)鏈接吧。哦,天哪!我們被重新定向到了一個(gè)新的網(wǎng)站。我們被重定向到了登錄頁(yè)面......這不對(duì)。然而,請(qǐng)注意,標(biāo)題右上方的鏈接確實(shí)寫著 "注銷"
如果我們點(diǎn)擊到me 頁(yè)面,它將讓我們?cè)L問(wèn)它,并正確顯示我們?cè)谧?cè)表格中提供的名字。
問(wèn)題是,在我們點(diǎn)擊頁(yè)面的那一瞬間,我們的中間件正在運(yùn)行,我們還沒(méi)有完全登錄,因此authStateChange還沒(méi)有發(fā)生,還沒(méi)有設(shè)置我們的用戶反應(yīng)式。
讓我們?cè)谖覀兊闹虚g件中做一個(gè)例外,如果查詢變量fromEmail存在,我們就繼續(xù)讓導(dǎo)航通過(guò),因?yàn)槲覀冎?,從確認(rèn)郵件中來(lái),用戶將立即登錄。
router.beforeEach((to) => {
const { isLoggedIn } = useAuthUser();
if (
!isLoggedIn() &&
to.meta.requiresAuth &&
!Object.keys(to.query).includes("fromEmail")
) {
return { name: "Login" };
}
});
還要注意,這不是一個(gè)安全問(wèn)題。如果有人在沒(méi)有登錄的情況下隨意在查詢字符串中包括fromEmail ,由于用戶不存在,反正什么都不會(huì)顯示出來(lái),也不會(huì)從Supabase收到關(guān)于用戶的信息。
注銷
現(xiàn)在除了注銷鏈接外,一切都應(yīng)該正常了。我們可以通過(guò)定義注銷路由并直接向其添加一個(gè)路由保護(hù)來(lái)使其工作。
{
name: "Logout",
path: "/logout",
beforeEnter: async () => {
const { logout } = useAuthUser();
await logout();
return { name: "Home" };
},
},
注銷后,如果你愿意,你可以嘗試用不同的電子郵件再次注冊(cè),以確認(rèn)我們上面的修復(fù)對(duì)直接導(dǎo)航到個(gè)人資料頁(yè)面起作用。同樣,當(dāng)注銷后,檢查一下登錄頁(yè)面。你應(yīng)該也能用現(xiàn)有的用戶成功登錄!
家庭作業(yè)
最后,如果你使用忘記密碼的鏈接,Supabase確實(shí)會(huì)向你發(fā)送重置密碼的電子郵件,然而你仍然需要實(shí)現(xiàn)該表格。我敢說(shuō),你可以利用你在文章中所學(xué)到的知識(shí)來(lái)研究這個(gè)問(wèn)題,并利用AuthUser可組合的update 方法。
總結(jié)
Supabase是Firebase的一個(gè)新的和即將到來(lái)的替代品。它有很多誘人的特點(diǎn),比如開源,使用PostgreSQL作為數(shù)據(jù)庫(kù),并提供流行的服務(wù),如數(shù)據(jù)存儲(chǔ)、認(rèn)證和文件存儲(chǔ)。用他們的認(rèn)證服務(wù)來(lái)認(rèn)證你的Vue.js 3應(yīng)用程序是相當(dāng)簡(jiǎn)單的,因?yàn)樗麄兊恼J(rèn)證api很簡(jiǎn)單。
如果你想看看本文討論的完整代碼,你可以查看Github repo。
一旦認(rèn)證完成,你就可以開始向你的Supabase實(shí)例發(fā)出請(qǐng)求,并創(chuàng)建規(guī)則來(lái)限制哪些用戶可以訪問(wèn)哪些數(shù)據(jù)。
因此,去制作真實(shí)的Supabase應(yīng)用程序吧。
https://vueschool.io/courses/vuejs-3-fundamentals?ref=blog
以上就是Vue3中使用Supabase Auth方法詳解的詳細(xì)內(nèi)容,更多關(guān)于Vue3中使用Supabase Auth的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
使用idea創(chuàng)建第一個(gè)Vue項(xiàng)目
最近在學(xué)習(xí)vue,本文主要介紹了使用idea創(chuàng)建第一個(gè)Vue項(xiàng)目,文中根據(jù)圖文介紹的十分詳盡,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
使用vue-cli+webpack搭建vue開發(fā)環(huán)境的方法
這篇文章主要介紹了使用vue-cli+webpack搭建vue開發(fā)環(huán)境的方法,需要的朋友可以參考下2017-12-12
解決vue頁(yè)面刷新或者后退參數(shù)丟失的問(wèn)題
下面小編就為大家分享一篇解決vue頁(yè)面刷新或者后退參數(shù)丟失的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-03-03
Vue+Element實(shí)現(xiàn)網(wǎng)頁(yè)版?zhèn)€人簡(jiǎn)歷系統(tǒng)(推薦)
這篇文章主要介紹了Vue+Element實(shí)現(xiàn)網(wǎng)頁(yè)版?zhèn)€人簡(jiǎn)歷系統(tǒng),需要的朋友可以參考下2019-12-12
Vue.js使用v-show和v-if的注意事項(xiàng)
這篇文章一開始先對(duì)Vue.js中v-show和v-if兩者的區(qū)別進(jìn)行了簡(jiǎn)單的介紹,而后通過(guò)圖文詳細(xì)給大家介紹了Vue.js使用v-show和v-if注意的事項(xiàng),有需要的朋友們可以參考借鑒,下面來(lái)一起看看吧。2016-12-12
基于Vue實(shí)現(xiàn)圖片在指定區(qū)域內(nèi)移動(dòng)的思路詳解
這篇文章主要介紹了基于Vue實(shí)現(xiàn)圖片在指定區(qū)域內(nèi)移動(dòng),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-11-11
Vue實(shí)現(xiàn)淘寶購(gòu)物車三級(jí)選中功能詳解
這篇文章主要介紹了通過(guò)Vue實(shí)現(xiàn)淘寶購(gòu)物車中三級(jí)選中的功能,文中的實(shí)現(xiàn)過(guò)程講解詳細(xì),對(duì)我們學(xué)習(xí)Vue有一定的幫助,感興趣的可以了解一下2022-01-01
vue實(shí)現(xiàn)網(wǎng)頁(yè)語(yǔ)言國(guó)際化切換
這篇文章介紹了vue實(shí)現(xiàn)網(wǎng)頁(yè)語(yǔ)言國(guó)際化切換的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2021-11-11

