更新记录

1.0.0(2025-05-30) 下载此版本

完成基本功能


平台兼容性

uni-app(4.01)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
-
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 快应用-华为 快应用-联盟
- - - - - - - - - -

anfun-supabase

Supabase UniApp 版本 - 为 uni-app 开发者提供的 Supabase JavaScript 客户端

📖 插件介绍

anfun-supabase 是 Supabase 官方 JavaScript 客户端的 uni-app 适配版本,专为 uni-app 开发者打造。Supabase 是一个开源的 Firebase 替代方案,提供实时数据库、身份验证、即时 API、边缘函数、文件存储等功能。

本插件让您可以在 uni-app 项目中轻松使用 Supabase 的所有功能,支持多端开发(H5、小程序、App)。

✨ 主要特性

  • 🔐 身份验证 - 完整的用户认证系统,支持邮箱、手机号、第三方登录
  • 📊 实时数据库 - PostgreSQL 数据库,支持实时订阅数据变化(未测试)
  • 🗄️ 文件存储 - 安全的文件上传和管理
  • 边缘函数 - 服务端逻辑执行
  • 🔄 实时通信 - WebSocket 实时数据同步(未测试)
  • 📱 多端支持 - 支持 H5、微信小程序、App 等多个平台

📦 安装使用

1. 基础配置

在项目中创建 Supabase 客户端:

import { createClient } from "@/uni_modules/anfun-supabase";

const supabaseUrl = "https://your-project.supabase.co";
const supabaseKey = "your-anon-key";

export const supabase = createClient(supabaseUrl, supabaseKey);

📚 使用示例

用户认证

// 用户注册
async function signUp() {
  const { data, error } = await supabase.auth.signUp({
    email: "user@example.com",
    password: "password123",
  });

  if (error) {
    console.error("注册失败:", error.message);
  } else {
    console.log("注册成功:", data.user);
  }
}

// 用户登录
async function signIn() {
  const { data, error } = await supabase.auth.signInWithPassword({
    email: "user@example.com",
    password: "password123",
  });

  if (error) {
    console.error("登录失败:", error.message);
  } else {
    console.log("登录成功:", data.user);
  }
}

// 获取当前用户
async function getCurrentUser() {
  const {
    data: { user },
  } = await supabase.auth.getUser();
  return user;
}

// 退出登录
async function signOut() {
  const { error } = await supabase.auth.signOut();
  if (error) {
    console.error("退出失败:", error.message);
  }
}

数据库操作

// 查询数据
async function fetchTodos() {
  const { data, error } = await supabase
    .from("todos")
    .select("*")
    .order("created_at", { ascending: false });

  if (error) {
    console.error("查询失败:", error.message);
  } else {
    return data;
  }
}

// 插入数据
async function addTodo(title) {
  const { data, error } = await supabase
    .from("todos")
    .insert([{ title: title, completed: false }])
    .select();

  if (error) {
    console.error("添加失败:", error.message);
  } else {
    console.log("添加成功:", data);
  }
}

// 更新数据
async function updateTodo(id, updates) {
  const { data, error } = await supabase
    .from("todos")
    .update(updates)
    .eq("id", id)
    .select();

  if (error) {
    console.error("更新失败:", error.message);
  } else {
    console.log("更新成功:", data);
  }
}

// 删除数据
async function deleteTodo(id) {
  const { error } = await supabase.from("todos").delete().eq("id", id);

  if (error) {
    console.error("删除失败:", error.message);
  }
}

实时订阅

// 订阅数据变化
function subscribeToTodos() {
  const subscription = supabase
    .channel("todos")
    .on(
      "postgres_changes",
      { event: "*", schema: "public", table: "todos" },
      (payload) => {
        console.log("数据变化:", payload);
        // 处理数据变化
        handleDataChange(payload);
      }
    )
    .subscribe();

  return subscription;
}

// 取消订阅
function unsubscribe(subscription) {
  supabase.removeChannel(subscription);
}

文件存储

// 上传文件
async function uploadFile(file, fileName) {
  const { data, error } = await supabase.storage
    .from("avatars")
    .upload(fileName, file);

  if (error) {
    console.error("上传失败:", error.message);
  } else {
    console.log("上传成功:", data);
  }
}

// 获取文件 URL
function getFileUrl(fileName) {
  const { data } = supabase.storage.from("avatars").getPublicUrl(fileName);

  return data.publicUrl;
}

// 下载文件
async function downloadFile(fileName) {
  const { data, error } = await supabase.storage
    .from("avatars")
    .download(fileName);

  if (error) {
    console.error("下载失败:", error.message);
  } else {
    return data;
  }
}

边缘函数调用

// 调用边缘函数
async function invokeFunction(functionName, params) {
  const { data, error } = await supabase.functions.invoke(functionName, {
    body: params,
  });

  if (error) {
    console.error("函数调用失败:", error.message);
  } else {
    return data;
  }
}

🔧 完整示例

以下是一个完整的 Todo 应用示例:

<template>
  <view class="container">
    <view class="header">
      <input v-model="newTodo" placeholder="添加新任务" @confirm="addTodo" />
      <button @click="addTodo">添加</button>
    </view>

    <view class="todo-list">
      <view
        v-for="todo in todos"
        :key="todo.id"
        class="todo-item"
        :class="{ completed: todo.completed }"
      >
        <text @click="toggleTodo(todo)">{{ todo.title }}</text>
        <button @click="deleteTodo(todo.id)">删除</button>
      </view>
    </view>
  </view>
</template>

<script>
import { createClient } from "@/uni_modules/anfun-supabase";

const supabaseUrl = "https://your-project.supabase.co";
const supabaseKey = "your-anon-key";
export const supabase = createClient(supabaseUrl, supabaseKey);

export default {
  data() {
    return {
      todos: [],
      newTodo: "",
      subscription: null,
    };
  },

  async onLoad() {
    await this.fetchTodos();
    this.subscribeToChanges();
  },

  onUnload() {
    if (this.subscription) {
      supabase.removeChannel(this.subscription);
    }
  },

  methods: {
    async fetchTodos() {
      const { data, error } = await supabase
        .from("todos")
        .select("*")
        .order("created_at", { ascending: false });

      if (error) {
        uni.showToast({ title: "加载失败", icon: "error" });
      } else {
        this.todos = data;
      }
    },

    async addTodo() {
      if (!this.newTodo.trim()) return;

      const { error } = await supabase
        .from("todos")
        .insert([{ title: this.newTodo, completed: false }]);

      if (error) {
        uni.showToast({ title: "添加失败", icon: "error" });
      } else {
        this.newTodo = "";
      }
    },

    async toggleTodo(todo) {
      const { error } = await supabase
        .from("todos")
        .update({ completed: !todo.completed })
        .eq("id", todo.id);

      if (error) {
        uni.showToast({ title: "更新失败", icon: "error" });
      }
    },

    async deleteTodo(id) {
      const { error } = await supabase.from("todos").delete().eq("id", id);

      if (error) {
        uni.showToast({ title: "删除失败", icon: "error" });
      }
    },

    subscribeToChanges() {
      this.subscription = supabase
        .channel("todos")
        .on(
          "postgres_changes",
          { event: "*", schema: "public", table: "todos" },
          () => {
            this.fetchTodos();
          }
        )
        .subscribe();
    },
  },
};
</script>

<style>
.container {
  padding: 20px;
}

.header {
  display: flex;
  margin-bottom: 20px;
}

.todo-item {
  display: flex;
  justify-content: space-between;
  padding: 10px;
  border-bottom: 1px solid #eee;
}

.completed {
  opacity: 0.6;
  text-decoration: line-through;
}
</style>

📋 注意事项

  1. 环境配置:确保在 Supabase 控制台中正确配置了数据库表和 RLS 策略
  2. 密钥安全:不要在客户端代码中暴露 service_role 密钥,只使用 anon 密钥
  3. 网络请求:在小程序中使用时,需要在小程序后台配置 Supabase 域名为合法域名
  4. 实时功能:实时订阅功能在某些小程序平台可能受限(未测试)

让 uni-app 开发更简单,让 Supabase 更好用! 🚀

隐私、权限声明

1. 本插件需要申请的系统权限列表:

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

许可协议

MIT协议

暂无用户评论。

使用中有什么不明白的地方,就向插件作者提问吧~ 我要提问