Ably 免费版纯前端单聊

前言:对于前端开发如果实现即时通讯需要对接第三方例如腾讯IM,环信等。或者使用websocket,需要后台部署。
可是有些客户项目仅仅需要一个简单的单聊功能,没有第三方哪些复杂的功能。如果我们去对接第三方或者websokect显得有点大题小用,成本也随之增高。客户接受不了。
例如腾讯IM对于免费版还有人员限制,非常不适合这种简单的项目需求。
下面是一款免费的,仅仅需要前端就可以实现单聊的插件,非常适合小型单聊项目和开发人员测试使用,也可以根据项目需求进行自定义需求功能。
以下是页面效果图:支持移动端,pc web端

 

 

 

 

 

 

 

 

 

 

 

 

 

1.点击注册一个账号,qq和网易邮箱都支持。
2.复制API key
3.安装ably     pnpm add ably @ably/chat 
4.引入并使用,下面是demo测试完整代码:

<template>
    <div class="chat">
        <uv-navbar title="张三"></uv-navbar>
        <div class="allcards">
            <div v-for="(item,index) in messages" :key="index">
                <div class="alone_left" v-if="item.sender=='张三'">
                    <image src="https://ww2.sinaimg.cn/mw690/006faMndly1htwlunnhn5j30zj0zjjv8.jpg" mode=""></image>
                    <div style="margin-left: 20rpx;">
                        {{item.text}}
                    </div>
                </div>
                <div class="alone_right alone_left" v-else>
                    <div style="margin-right: 20rpx;">{{item.text}}</div>
                    <image
                        src="https://img0.baidu.com/it/u=3974643408,1028378712&fm=253&fmt=auto&app=120&f=JPEG?w=800&h=800"
                        mode=""></image>
                </div>
            </div>
        </div>
        <div class="input-area">
            <input class="input-area-input" v-model="input" @keyup.enter="sendMessage" placeholder="输入内容..." />
            <button class="input-area-button" @click="sendMessage">发送</button>
        </div>
    </div>
</template>

<script setup lang="ts">
    import {
        ref,
        onMounted
    } from 'vue'
    import * as Ably from 'ably'

    // 修改为你自己的 Ably 公钥
    const ABLY_API_KEY = 'xxx'

    const client = new Ably.Realtime(ABLY_API_KEY)
    const channel = client.channels.get('chat-room')

    const input = ref('')
    const messages = ref([]) as any

    // 当前用户的名字
    const userName = '李四'

    function sendMessage() {
        if (!input.value.trim()) return
        const message = {
            sender: userName,
            text: input.value.trim()
        }
        channel.publish('message', message)
        input.value = ''
    }

    onMounted(() => {
        channel.subscribe('message', (msg) => {
            messages.value.push(msg.data)
        })
    })
</script>

<style>
    page {
        background-color: #ededed;
    }

    .input-area {
        width: 100%;
        padding: 30rpx 0rpx;
        box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04);
        position: fixed;
        bottom: 0;
        display: flex;
        align-items: center;
        justify-content: space-between;
        z-index: 9;
        background-color: #f7f7f7;
    }

    .input-area-input {
        background-color: #fff;
        width: 70%;
        font-size: 26rpx;
        padding: 16rpx;
        border-radius: 10rpx;
        margin-left: 24rpx;
    }

    .input-area-button {
        width: 120rpx;
        color: #fff;
        background: #00c75a;
        font-size: 24rpx;
        margin-right: 24rpx;
        outline: none;
        border: none;
    }

    .allcards {
        /* background-color: aqua; */
        width: 95%;
        height: 300rpx;
        margin: 108rpx auto 0;
        height: 80vh;
        overflow-y: scroll;
    }

    .alone_left {
        display: flex;
        padding: 20rpx 0;
    }

    .alone_left image {
        width: 60rpx;
        height: 60rpx;
        border-radius: 5rpx;
    }

    .alone_right {
        justify-content: flex-end;
    }

    .alone_left div {
        background-color: #fff;
        font-size: 24rpx;
        color: #333;
        padding: 14rpx;
        border-radius: 8rpx;
        max-width: 70%;
    }

    .alone_right div {
        background-color: #00c75a;
        color: #fff;
    }
</style>

 

<template>
    <div class="chat">
        <uv-navbar title="李四"></uv-navbar>
        <div class="allcards">
            <div v-for="(item,index) in messages" :key="index">
                <div class="alone_left" v-if="item.sender=='李四'">
                    <image src="https://ww2.sinaimg.cn/mw690/006faMndly1htwlunnhn5j30zj0zjjv8.jpg" mode=""></image>
                    <div style="margin-left: 20rpx;">
                        {{item.text}}
                    </div>
                </div>
                <div class="alone_right alone_left" v-else>
                    <div style="margin-right: 20rpx;">{{item.text}}</div>
                    <image
                        src="https://img0.baidu.com/it/u=3974643408,1028378712&fm=253&fmt=auto&app=120&f=JPEG?w=800&h=800"
                        mode=""></image>
                </div>
            </div>
        </div>
        <div class="input-area">
            <input class="input-area-input" v-model="input" @keyup.enter="sendMessage" placeholder="输入内容..." />
            <button class="input-area-button" @click="sendMessage">发送</button>
        </div>
    </div>
</template>

<script setup lang="ts">
    import {
        ref,
        onMounted
    } from 'vue'
    import * as Ably from 'ably'

    // 修改为你自己的 Ably 公钥
    const ABLY_API_KEY = 'xxx'

    const client = new Ably.Realtime(ABLY_API_KEY)
    const channel = client.channels.get('chat-room')

    const input = ref('')
    const messages = ref([]) as any

    // 当前用户的名字(随机生成一个)
    const userName = '张三'

    function sendMessage() {
        if (!input.value.trim()) return
        const message = {
            sender: userName,
            text: input.value.trim()
        }
        channel.publish('message', message)
        input.value = ''
    }

    onMounted(() => {
        channel.subscribe('message', (msg) => {
            messages.value.push(msg.data)
        })
    })
</script>

<style>
    page {
        background-color: #ededed;
    }

    .input-area {
        width: 100%;
        padding: 30rpx 0rpx;
        box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04);
        position: fixed;
        bottom: 0;
        display: flex;
        align-items: center;
        justify-content: space-between;
        z-index: 9;
        background-color: #f7f7f7;
    }

    .input-area-input {
        background-color: #fff;
        width: 70%;
        font-size: 26rpx;
        padding: 16rpx;
        border-radius: 10rpx;
        margin-left: 24rpx;
    }

    .input-area-button {
        width: 120rpx;
        color: #fff;
        background: #00c75a;
        font-size: 24rpx;
        margin-right: 24rpx;
        outline: none;
        border: none;
    }

    .allcards {
        /* background-color: aqua; */
        width: 95%;
        height: 300rpx;
        margin: 108rpx auto 0;
        height: 80vh;
        overflow-y: scroll;
    }

    .alone_left {
        display: flex;
        padding: 20rpx 0;
    }

    .alone_left image {
        width: 60rpx;
        height: 60rpx;
        border-radius: 5rpx;
    }

    .alone_right {
        justify-content: flex-end;
    }

    .alone_left div {
        background-color: #fff;
        font-size: 24rpx;
        color: #333;
        padding: 14rpx;
        border-radius: 8rpx;
        max-width: 70%;
    }
    .alone_right div{
        background-color: #00c75a;
        color: #fff;
    }
</style>

 

 



posted @ 2025-04-10 10:47  脆脆啥  阅读(72)  评论(0)    收藏  举报