Vue与Supabase交互文档
Vue与Supabase交互文档
初始化Supabase客户端
// src/lib/supabaseClient.ts
import { createClient } from '@supabase/supabase-js'
// 前端客户端(受RLS限制)
export const supabase = createClient(
import.meta.env.VITE_SUPABASE_URL,
import.meta.env.VITE_SUPABASE_ANON_KEY
)
// 管理端客户端(仅在服务端使用,具有完全权限)
export const adminSupabase = createClient(
process.env.SUPABASE_URL,
process.env.SUPABASE_SERVICE_ROLE_KEY,
{
auth: {
autoRefreshToken: false,
persistSession: false
}
}
)
数据表操作接口 (CRUD)
1. 查询数据 (Read)
// 基本查询
const { data, error } = await supabase
.from('表名')
.select('字段1, 字段2')
// 条件查询
const { data, error } = await supabase
.from('表名')
.select()
.eq('字段', '值') // 等于
.neq('字段', '值') // 不等于
.gt('字段', '值') // 大于
.lt('字段', '值') // 小于
.gte('字段', '值') // 大于等于
.lte('字段', '值') // 小于等于
.like('字段', '%值%') // 模糊匹配(区分大小写)
.ilike('字段', '%值%') // 模糊匹配(不区分大小写)
.in('字段', [值1, 值2]) // 在数组中
.is('字段', null) // 为NULL
// 关联表查询
const { data, error } = await supabase
.from('主表')
.select(`
字段1,
字段2,
关联表(字段1, 字段2)
`)
2. 新增数据 (Create)
// 单条新增
const { data, error } = await supabase
.from('表名')
.insert({ 字段1: '值1', 字段2: '值2' })
.select() // 可选,返回新增的数据
// 批量新增
const { data, error } = await supabase
.from('表名')
.insert([
{ 字段1: '值1', 字段2: '值2' },
{ 字段1: '值3', 字段2: '值4' }
])
3. 更新数据 (Update)
// 单条更新
const { data, error } = await supabase
.from('表名')
.update({ 字段1: '新值' })
.eq('id', 1)
.select() // 可选,返回更新后的数据
// 批量更新
const { data, error } = await supabase
.from('表名')
.update({ 字段1: '新值' })
.in('id', [1, 2, 3])
4. 删除数据 (Delete)
// 单条删除
const { data, error } = await supabase
.from('表名')
.delete()
.eq('id', 1)
.select() // 可选,返回删除的数据
// 批量删除
const { data, error } = await supabase
.from('表名')
.delete()
.in('id', [1, 2, 3])
5. 分页查询
// 基本分页(偏移分页)
const { data, error } = await supabase
.from('表名')
.select('*')
.range(0, 9) // 获取0-9条记录(共10条)
// 页码分页
const page = 1 // 当前页码,从1开始
const pageSize = 10 // 每页条数
const { data, error } = await supabase
.from('表名')
.select('*')
.range((page - 1) * pageSize, page * pageSize - 1)
// 获取总记录数
const { count, error } = await supabase
.from('表名')
.select('*', { count: 'exact', head: true })
6. 排序
// 单字段排序
const { data, error } = await supabase
.from('表名')
.select()
.order('字段', { ascending: true }) // 升序,false为降序
// 多字段排序
const { data, error } = await supabase
.from('表名')
.select()
.order('字段1', { ascending: true })
.order('字段2', { ascending: false })
7. 高级筛选
// 组合条件(OR)
const { data, error } = await supabase
.from('表名')
.select()
.or('字段1.eq.值1,字段2.eq.值2')
// 全文搜索
const { data, error } = await supabase
.from('表名')
.select()
.textSearch('字段', '搜索词', {
type: 'websearch',
config: 'chinese'
})
认证接口
1. 注册和登录
// 邮箱密码注册
const { data, error } = await supabase.auth.signUp({
email: '邮箱',
password: '密码',
options: {
data: {
名称: '值', // 自定义用户元数据
}
}
})
// 邮箱密码登录
const { data, error } = await supabase.auth.signInWithPassword({
email: '邮箱',
password: '密码'
})
// 第三方登录
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'github' // 或 'google', 'facebook' 等
})
// 手机验证码登录
const { data, error } = await supabase.auth.signInWithOtp({
phone: '手机号'
})
2. 会话管理
// 获取当前会话
const { data, error } = await supabase.auth.getSession()
// 获取当前用户
const { data: { user }, error } = await supabase.auth.getUser()
// 刷新会话
const { data, error } = await supabase.auth.refreshSession()
// 更新用户信息
const { data, error } = await supabase.auth.updateUser({
email: '新邮箱',
password: '新密码',
data: { 自定义字段: '新值' }
})
// 退出登录
const { error } = await supabase.auth.signOut()
3. 密码重置
// 发送密码重置邮件
const { data, error } = await supabase.auth.resetPasswordForEmail('邮箱')
// 使用新密码更新(在重置页面)
const { data, error } = await supabase.auth.updateUser({
password: '新密码'
})
4. 多因素认证 (MFA)
// 注册因素
const { data, error } = await supabase.auth.mfa.enroll({
factorType: 'totp'
})
// 创建验证
const { data, error } = await supabase.auth.mfa.challenge({
factorId: 'factor_id'
})
// 验证因素
const { data, error } = await supabase.auth.mfa.verify({
factorId: 'factor_id',
challengeId: 'challenge_id',
code: '验证码'
})
在Vue组件中使用
<script setup>
import { ref, onMounted } from 'vue'
import { supabase } from '@/lib/supabaseClient'
// 状态管理
const loading = ref(true)
const items = ref([])
const error = ref(null)
const currentPage = ref(1)
const pageSize = ref(10)
const totalCount = ref(0)
// 加载数据(带分页)
async function loadItems() {
try {
loading.value = true
// 获取总数
const { count, error: countError } = await supabase
.from('表名')
.select('*', { count: 'exact', head: true })
if (countError) throw countError
totalCount.value = count
// 获取分页数据
const from = (currentPage.value - 1) * pageSize.value
const to = from + pageSize.value - 1
const { data, error: dataError } = await supabase
.from('表名')
.select('*')
.range(from, to)
.order('创建时间', { ascending: false })
if (dataError) throw dataError
items.value = data
} catch (err) {
error.value = err.message
} finally {
loading.value = false
}
}
// 新增项目
async function addItem(item) {
try {
const { data, error: insertError } = await supabase
.from('表名')
.insert(item)
.select()
if (insertError) throw insertError
// 重新加载数据或直接更新列表
await loadItems()
return data
} catch (err) {
error.value = err.message
return null
}
}
// 更新项目
async function updateItem(id, updates) {
try {
const { data, error: updateError } = await supabase
.from('表名')
.update(updates)
.eq('id', id)
.select()
if (updateError) throw updateError
// 更新本地数据
const index = items.value.findIndex(item => item.id === id)
if (index !== -1) {
items.value[index] = data[0]
}
return data
} catch (err) {
error.value = err.message
return null
}
}
// 删除项目
async function deleteItem(id) {
try {
const { error: deleteError } = await supabase
.from('表名')
.delete()
.eq('id', id)
if (deleteError) throw deleteError
// 从本地列表移除
items.value = items.value.filter(item => item.id !== id)
return true
} catch (err) {
error.value = err.message
return false
}
}
// 页码变化
function handlePageChange(page) {
currentPage.value = page
loadItems()
}
// 组件挂载时加载数据
onMounted(() => {
loadItems()
})
</script>
实时数据订阅
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import { supabase } from '@/lib/supabaseClient'
const items = ref([])
let subscription
// 加载初始数据
async function loadItems() {
const { data } = await supabase.from('表名').select()
items.value = data
}
// 设置实时订阅
function setupRealtimeSubscription() {
subscription = supabase
.channel('表变化')
.on('postgres_changes',
{ event: '*', schema: 'public', table: '表名' },
(payload) => {
// 根据变化类型处理数据
if (payload.eventType === 'INSERT') {
items.value.push(payload.new)
} else if (payload.eventType === 'UPDATE') {
const index = items.value.findIndex(item => item.id === payload.new.id)
if (index !== -1) {
items.value[index] = payload.new
}
} else if (payload.eventType === 'DELETE') {
items.value = items.value.filter(item => item.id !== payload.old.id)
}
}
)
.subscribe()
}
onMounted(() => {
loadItems()
setupRealtimeSubscription()
})
onUnmounted(() => {
if (subscription) {
supabase.removeChannel(subscription)
}
})
</script>
以上是Vue应用中使用Supabase的主要接口和用法概述。项目中可根据具体需求进行定制和封装。