纯前端实现分享短链接

背景

线上的一个项目因为嵌套路由过深,客户觉得复制分享的链接地址太长,所以需要增加一个分享短链接的功能。

方案

在网上搜索短链接跳转的方法大部分都是使用node服务实现的。

虽然实现并不复杂,但是考虑到多维护一个服务就多一份加班的可能性。我还是想要一个更加简单的方法。

而VueRouter就可以实现短链接跳转的功能。

直接往路由表插入一组短链接路由,redirect指向对应的路由。示例如下:

javascript 复制代码
// shortLinks.js - 短链接配置
export const shortRoutes = [
  {
    path: '/sbKLEy/:id',
    redirect: '/consectetur/adipiscing/elit/:id',
    name: 'sbKLEy',
    meta: { title: '页面1' },
  },
];
javascript 复制代码
import { shortRoutes } from './shortLinks';

const routes = [
  ...shortRoutes,
  {
    path: '/consectetur/adipiscing/elit/:id',
    name: 'consectetur',
    meta: { title: '页面1' },
    component: () => import('@/views/consectetur/adipiscing/elit.vue'),
  },
];

const router = new VueRouter({
  routes,
  mode: 'history',
});

这样的访问/sbKLEy/:id路径的时候,直接就会跳转到/consectetur/adipiscing/elit/:id

query、params也都能正常重定向到源页面。

这个方案缺点就是只能缩短URL的 路径 部分。如果你的页面上有大量的查询参数部分,那这个方法能缩短的字符很有限。

好了,跳转功能没有问题,接下来就可以实现分享功能了。

分享功能

我们分享的逻辑是,用当前的路由地址去 短链接路由表 查询有无对应地址。有则使用短链接为分享路径,无则继续使用当前路由。然后将分享路径写入到粘贴板。

在实现分享功能之前,先准备两个工具函数:

javascript 复制代码
/**
 * 根据给定的路径和参数对象,生成一个包含占位符的路径字符串
 * @param {Object} route - 包含路径和参数的对象
 * @param {string} route.path - 路径字符串
 * @param {Object} route.params - 参数对象
 * @returns {string} - 替换参数后的路径字符串,其中参数被替换为占位符
 * @example
 * 输入: "/users/123", { id: "123" }
 * 输出: "/users/:id"
 */
function getSourcePath(path, params) {
    let sourcePath = path;
    // 按占位符名称的长度排序,从长到短,避免替换错误
    const keys = Object.keys(params).sort((a, b) => b.length - a.length);
    
    for (const key of keys) {
        if (!Object.hasOwnProperty.call(params, key)) continue;
        const value = params[key];
        const regex = new RegExp(value, 'g'); // 全局匹配该值
        sourcePath = sourcePath.replace(regex, `:${key}`);
    }
    return sourcePath.replace(//+$/, "");
}

/**
 * 根据给定的路径和参数对象,生成一个包含实际参数值的路径字符串
 * @param {string} path - 路径模板,其中包含占位符,如 ":id"
 * @param {Object} params - 参数对象,包含占位符对应的值
 * @returns {string} - 替换占位符后的实际路径字符串
 * @example
 * 输入: "/users/:id", { id: "123" }
 * 输出: "/users/123"
 */
function getParamsPath(path, params) {
    let paramsPath = path;
    // 遍历占位符,确保每个占位符都能被替换
    for (const key in params) {
        if (!Object.hasOwnProperty.call(params, key)) continue;
        const value = params[key];
        const regex = new RegExp(`:${key}(?=\/|$)`, 'g'); // 确保只替换占位符
        paramsPath = paramsPath.replace(regex, value);
    }
    return paramsPath.replace(//+$/, "");
}

这两个函数是相反的功能,一个是将/users/123转为/users/:id,另一个是将/users/:id转回/users/123

getSourcePath方法是按值查找替换,在两个param值相同的情况下可能会替换错误。这里有需要的可以深入再完善一下。

因为我项目内没有多个param的路由,所以就不再继续完善该函数了。

接下来就是分享函数 handleShare

javascript 复制代码
export function handleShare (route) {
    // 待分享的路由路径
    let sharePath = route.path
    // 源路径
    const sourcePath = getSourcePath(route.path, route.params)
    // 映射的短链接路由
    const redirectMapRoute = redirectMap.find(item => item.redirect === sourcePath)

    if (redirectMapRoute) {
        sharePath = getParamsPath(redirectMapRoute.path, route.params)
    }

    // 将完整路径中的路径替换为分享路径-省去处理 query 部分
    sharePath = route.fullPath.replace(route.path, sharePath)

    // 复制内容
    const shareUrl = `【${document.title}】 ${window.location.origin + sharePath}`

    // 将分享路径复制到剪切板,并且处理兼容问题
    try {
        navigator.clipboard.writeText(shareUrl)
        .then(() => {
            Message({
                message: '分享链接复制成功',
                type: 'success'
            })
        })
    } catch (err) {
        var copyInput = document.createElement('input')
        copyInput.setAttribute('value', shareUrl)
        document.body.appendChild(copyInput)
        copyInput.select()
        document.execCommand('copy')
        document.body.removeChild(copyInput)

        Message({
            message: '分享链接复制成功',
            type: 'success'
        })
    }
    
}

功能大致就是:从短链接路由表中查找是否有对应映射的路由,有就使用该短链接路由作为分享地址,然后复制。

随后只需要在页面分享按钮的上添加上这个方法调用就ok了。

javascript 复制代码
// vue2
<div @click="handleShare($route)">
  分享
</div>

// vue3
<div @click="handleShare(route)">
  分享
</div>
...
import { useRoute } from 'vue-router'
const route = useRoute()

短链接路由生成

原先的页面路由如果很多的话。我们就再写个一次性的工具函数,遍历页面路由然后生成短链接路由表。

javascript 复制代码
/**
* 路径中提取参数部分
* @param {string} path - 包含参数的路径字符串
* @returns {string} - 提取出的参数部分,以斜杠分隔
*/
function getParams (path) {
    const params = path.split('/').filter(i => i.startsWith(':'))

    if (params.length)
        return '/' + params.join('/')

    return ''
}

// 生成分享短链接路由表
function getShortRoutes () {
    const shortRoutes = []
  
    function getRedirect(currentRoutes, parentPath = '') {
        currentRoutes.forEach(route => {
            let path = route.path
    
            // 相对路径需要拼接父路径
            if (!route.path.startsWith('/'))
                path = parentPath + '/' + route.path
    
            // 随机生成一个短链接
            const shortPath = nanoid(6)
          
            shortRoutes.push({
                path: `/${shortPath}${getParams(path)}`,
                redirect: path,
                name: shortPath,
                props: route.props,
                meta: route.meta
            })

            // 继续递归子路由
            if (route.children)
                getRedirect(route.children, path)
        })
    }

    getRedirect(routes)

    return shortRoutes
}

console.log(getShortRoutes())

很简单的函数,执行后到控制台取生成的结果就好了。这里有两点需要说一下。

  1. 相对路径需要拼接上父路径才是完整的redirect路径。
  2. 生成短链接路径使用的是nanoid随机生成,nanoid默认使用URL友好字符,不需要担心字符问题。
相关推荐
huoyueyi3 分钟前
超详细Chatbot UI的配置及使用
前端·ui·chatgpt
_不是惊风9 分钟前
vue预览和下载 pdf、ppt、word、excel文档,文件类型为链接或者base64格式或者文件流,
vue.js·pdf·powerpoint
Qlittleboy16 分钟前
vue的elementUI 给输入框绑定enter事件失效
前端·vue.js·elementui
Violet_Stray29 分钟前
用bootstrap搭建侧边栏
前端·bootstrap·html
软件聚导航31 分钟前
对uniApp 组件 picker-view 的二次封装,实现日期,时间、自定义数据滚动选择,容易扩展
前端·javascript·html
码农丁丁1 小时前
[前端]mac安装nvm(node.js)多版本管理
前端·macos·node.js·nvm
TWenYuan1 小时前
【上传文件过大进行的切片式上传】
javascript·vue.js
正小安1 小时前
Vite 系列课程|1课程道路,2什么是构建工具
前端·vite
阿髙2 小时前
ios的safari下载文件 文件名乱码
前端·axios·safari·下载
LaiJying2 小时前
图书馆管理系统(四)基于jquery、ajax--完结篇
前端·ajax·jquery