Vue多页面路由与模版解析

上篇文章中我们成功打包并输出了多页文件,而构建一个多页应用能够让我们进一步了解项目配置的可拓展性,可以对学习 Vue 和 webpack 起到强化训练的效果,本文将在此基础上主要针对多页路由及模板的配置进行系列的介绍。

路由配置

1. 跳转

在配置路由前,首先我们要明确一点就是,多页应用中的每个单页都是相互隔离的,即如果你想从 page1 下的路由跳到 page2 下的路由,你无法使用 vue-router 中的方法进行跳转,需要使用原生方法:location.href location.replace

此外为了能够清晰的分辨路由属于哪个单页,我们应该给每个单页路由添加前缀,比如:

  • index 单页:/vue/

  • page1 单页:/vue/page1/

  • page2 单页:/vue/page2/

其中 /vue/ 为项目的二级目录,其后的目录代表路由属于哪个单页。因此我们每个单页的路由配置可以像这样:

/* page1 单页路由配置 */

import Vue from 'vue'
import Router from 'vue-router'

// 首页
const Home = (resolve => {
    //使用了 require.ensure 方法来实现懒加载
    require.ensure(['../views/home.vue'], () => {
        resolve(require('../views/home.vue'))
    })
})

Vue.use(Router)

//通过 process.env.BASE_URL 动态获取基础 URL,并添加 'page1' 作为前缀
let base = `${process.env.BASE_URL}` + 'page1'; // 添加单页前缀

export default new Router({
    mode: 'history',
    base: base,
    routes: [
        {
            path: '/',
            name: 'home',
            //动态加载 Home 组件
            component: Home
        },
    ]
})

我们通过设置路由的 base 值来为每个单页添加路由前缀,如果是 index 单页我们无需拼接路由前缀,直接跳转至二级目录即可。

那么在单页间跳转的地方,我们可以这样写:

<template>
  <div id="app">
    <div id="nav">
      <a @click="goFn('')">Index</a> |
      <a @click="goFn('page1')">Page1</a> |
      <a @click="goFn('page2')">Page2</a> |
    </div>
    <router-view/>
  </div>
</template>

<script>
export default {
    methods: {
        goFn(name) {
            location.href = `${process.env.BASE_URL}` + name
        }
    }
}
</script>

location.href 进行导航会导致页面完全刷新,从而失去单页应用(SPA)的优点。为了保持 SPA 的特性,可以使用 Vue Router 提供的 $router.push 方法进行路由导航,

export default {

    methods: {

        goFn(name) {

                 this.$router.push(name); // 使用 Vue Router 进行路由导航

         }

     }

}

但是为了保持和 Vue 路由跳转同样的风格,我可以对单页之间的跳转做一下封装,实现一个 Navigator 类,类的代码可以查看本文最后的示例,封装完成后我们可以将跳转方法修改为:

this.$openRouter({
    name: name, // 跳转地址
    query: {
        text: 'hello' // 可以进行参数传递
    },
})

使用上述 this.$openRouter() 来调用 Navigator.openRouter方法我们还需要一个前提条件,便是通过 Vue.prototype将其绑定到 Vue 的原型链上,我们在所有单页的入口文件中添加:

//引入navigator对象
import { Navigator } from '../../common' // 引入 Navigator

// 添加至 Vue 原型链
Vue.prototype.$openRouter = Navigator.openRouter; 

Vue 3 示例

import { createApp } from 'vue';
import App from './App.vue';
import { Navigator } from '../../common';

const app = createApp(App);

// 添加到全局属性
app.config.globalProperties.$openRouter = Navigator.openRouter;

app.mount('#app');

至此我们已经能够成功模仿 vue-router 进行单页间的跳转,但是需要注意的是因为其本质使用的是 location 跳转,所以必然会产生浏览器的刷新与重载。

2. 重定向

当我们完成上述路由跳转的功能后,可以在本地服务器上来进行一下测试,你会发现 Index 首页可以正常打开,但是跳转 Page1、Page2 却仍然处于 Index 父组件下,这是因为浏览器认为你所要跳转的页面还是在 Index 根路由下,同时又没有匹配到 Index 单页中对应的路由。这时候我们服务器需要做一次重定向,将下方路由指向对应的 html 文件即可:

/vue/page1 -> /vue/page1.html
/vue/page2 -> /vue/page2.html

vue.config.js 中,我们需要对 devServer 进行配置,添加 historyApiFallback 配置项,该配置项主要用于解决 HTML5 History API 产生的问题,比如其 rewrites 选项用于重写路由:

/* vue.config.js */

let baseUrl = '/vue/';

module.exports = {
    ...
    
    devServer: {
        historyApiFallback: {
            rewrites: [
                { from: new RegExp(baseUrl + 'page1'), to: baseUrl + 'page1.html' },
                { from: new RegExp(baseUrl + 'page2'), to: baseUrl + 'page2.html' },
            ]
        }
    }
    
    ...
}

上方我们通过 rewrites 匹配正则表达式的方式将 /vue/page1 这样的路由替换为访问服务器下正确 html 文件的形式。当请求的路径符合 from 中的正则表达式时,会被重定向到 to 指定的 HTML 文件,例如,如果用户请求 /vue/page1,则开发服务器会返回 /vue/page1.html 文件的内容。如此不同单页间便可以进行正确跳转和访问了。最后需要注意的是如果你的应用发布到正式服务器上,你同样需要让服务器或者中间层作出合理解析。

参考:HTML5 History 模式 # 后端配置例子

而更多关于 historyApiFallback 的信息可以访问:connect-history-api-fallback

拓展1

new RegExp的简易概括

new RegExp 是 JavaScript 中用于创建正则表达式对象的构造函数。正则表达式是一种强大的文本处理工具,可以用于模式匹配和搜索。通过 new RegExp,你可以动态构造正则表达式,而不仅限于字面量表示法(使用斜杠 / 包围的形式)。

基本语法

let regex = new RegExp(pattern, flags);
  • pattern: 一个字符串,定义了正则表达式的模式。
  • flags: 可选字符串,定义了正则表达式的修饰符(例如,g 表示全局匹配,i 表示不区分大小写,m 表示多行匹配等)。

示例

基本示例:

let pattern = 'abc';
let regex = new RegExp(pattern);
console.log(regex.test('abcdef')); // true
console.log(regex.test('xyz'));    // false

使用修饰符:

let pattern = 'abc';
let regex = new RegExp(pattern, 'i'); // 'i' 表示不区分大小写
console.log(regex.test('ABCdef')); // true

动态构造正则表达式

使用 new RegExp 可以根据变量动态构造正则表达式:

let searchTerm = 'page';
let regex = new RegExp(searchTerm);
console.log(regex.test('This is a page.')); // true

在 Vue.js 配置中的使用

在之前的 vue.config.js 中,使用 new RegExp 创建动态正则表达式,用于匹配特定的 URL 路径。例如:

rewrites: [
    { from: new RegExp(baseUrl + 'page1'), to: baseUrl + 'page1.html' },
    { from: new RegExp(baseUrl + 'page2'), to: baseUrl + 'page2.html' },
]

new RegExp(baseUrl + 'page1') 创建了一个正则表达式,用于匹配以 /vue/page1 开头的 URL。当用户直接访问这个 URL 时,开发服务器会将请求重定向 page1.html

总结

  • 使用 new RegExp 可以动态创建正则表达式,适用于需要根据变量或用户输入构造正则的场景。
  • 正则表达式在很多情况下非常有用,尤其是在处理文本、匹配模式和验证输入等方面。
  • 在 Vue.js 或其他框架的配置中,可以利用正则表达式进行复杂的路由匹配和 URL 重写。

模板配置

上篇文章我们已经介绍了关于多模板的读取和配置,在配置 html-webpack-plugin 的时候我们提到了自定义配置,这里我将结合模板渲染的功能来进行统一介绍。

1. 模板渲染

这里所说的模板渲染是在我们的 html 模板文件中使用 html-webpack-plugin 提供的 default template 语法进行模板编写,比如:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>模板</title>
    <% for (var chunk in htmlWebpackPlugin.files.css) { %>
        <% if(htmlWebpackPlugin.files.css[chunk]) {%>
            <link href="<%= htmlWebpackPlugin.files.css[chunk] %>" rel="stylesheet" />
        <%}%>
    <% } %>
  </head>
  <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->

    <% for (var chunk in htmlWebpackPlugin.files.js) { %>
        <% if(htmlWebpackPlugin.files.js[chunk]) {%>
            <script type="text/javascript" src="<%= htmlWebpackPlugin.files.js[chunk] %>"></script>
        <%}%>
    <% } %>
  </body>
</html>
  1. 文档类型声明和头部:

    • <!DOCTYPE html>: 声明 HTML5 文档类型。
    • <head> 部分包含页面的元数据,如字符集、视口设置和标题。
  2. 动态注入 CSS:

    • 使用 EJS 模板语法 (<% ... %>) 来循环遍历 htmlWebpackPlugin.files.css 中的 CSS 文件。
    • 如果文件存在,则生成对应的 <link> 标签,将 CSS 文件链接到页面中。
  3. 主体内容:

    • <body> 部分包含一个 <div id="app"></div>,这是 Vue.js 或其他前端框架通常用于挂载应用的根元素。
  4. 动态注入 JavaScript:

    • 类似于 CSS 的处理,使用 EJS 模板语法来遍历 htmlWebpackPlugin.files.js 中的 JavaScript 文件。
    • 如果文件存在,则生成对应的 <script> 标签,将 JS 文件链接到页面中。

以上我们使用模板语法手动获取并遍历 htmlWebpackPlugin 打包后的文件并生成到模板中,其中的 htmlWebpackPlugin 变量是模板提供的可访问变量,其有以下特定数据:

"htmlWebpackPlugin": {
    "files": {
        "css": [ "main.css" ],
        "js": [ "assets/head_bundle.js", "assets/main_bundle.js"],
        "chunks": {
            "head": {
                "entry": "assets/head_bundle.js",
                "css": [ "main.css" ]
            },
            "main": {
                "entry": "assets/main_bundle.js",
                "css": []
            },
        }
    }
}

我们通过 htmlWebpackPlugin.files 可以获取打包输出的 js 及 css 文件路径,包括入口文件路径等。

结合 html 模板文件和的 htmlWebpackPlugin 配置,最终生成的 HTML 文件会像下面这样:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>模板</title>

    <!-- 注入的 CSS -->
    <link href="main.css" rel="stylesheet" />
  </head>
  <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->

    <!-- 注入的 JavaScript -->
    <script type="text/javascript" src="assets/head_bundle.js"></script>
    <script type="text/javascript" src="assets/main_bundle.js"></script>
  </body>
</html>

需要注意的是如果你在模板中编写了插入对应 js 及 css 的语法,你需要设置 inject 的值为 false 来关闭资源的自动注入:

/* utils.js */
...

let conf = {
    entry: filePath, // page 的入口
    template: filePath, // 模板路径
    filename: filename + '.html', // 生成 html 的文件名
    chunks: ['manifest', 'vendor',  filename],
    inject: false, // 关闭资源自动注入
}

...

否则在页面会引入两次资源,如下图所示:

2. 自定义配置

在模板渲染中,我们只能够使用 htmlWebpackPlugin 内部的一些属性和方法来进行模板的定制化开发,那么如果遇到需要根据不同环境来引入不同资源,同时不同模板间的配置还可能不一样的需求情况的话,我们使用自定义配置会比较方便。比如我们需要在生产环境模板中引入第三方统计脚本:

/* vue.config.js */

module.exports = {
    ...
    
    pages: utils.setPages({
        addScript() {
            if (process.env.NODE_ENV === 'production') {
                return `
                    <script src="https://s95.cnzz.com/z_stat.php?id=xxx&web_id=xxx" language="JavaScript"></script>
                `
            }

            return ''
        }
    }),
    
    ...
}

然后在页面模板中通过 htmlWebpackPlugin.options 获取自定义配置对象并进行输出:

<% if(htmlWebpackPlugin.options.addScript){ %>
    <%= htmlWebpackPlugin.options.addScript() %>
<%}%>

同时你也可以针对个别模板进行配置,比如我想只在 Index 单页中添加统计脚本,在 Page1 单页中添加其他脚本,那么你可以给 addScript 传入标识符来进行判断输出,比如:

<% if(htmlWebpackPlugin.options.addScript){ %>
    <%= htmlWebpackPlugin.options.addScript('index') %>
<%}%>

同时为 addScript 方法添加参数 from:

addScript(from) {
    if (process.env.NODE_ENV === 'production') {
        let url = "https://xxx";
    
        if (from === 'index') {
            url = "https://s95.cnzz.com/z_stat.php?id=xxx&web_id=xxx";
        }
        
        return `
            <script src=${url} language="JavaScript"></script>
        `
    }

    return ''
}

这样我们就完成了自定义配置中的模板渲染功能。当然根据实际项目需求你的自定义配置项可能会更加复杂和灵活。

拓展2

1、多页应用中各自的 Vuex Store 信息能实现共享吗

1. 使用 Local Storage 或 Session Storage

通过使用浏览器的 Local Storage 或 Session Storage,可以在不同页面之间共享状态。每个页面在加载时可以从 Local Storage 中读取状态,在状态变化时更新 Local Storage。

// 设置状态到 Local Storage
localStorage.setItem('myStoreState', JSON.stringify(store.state));

// 从 Local Storage 获取状态
const savedState = JSON.parse(localStorage.getItem('myStoreState'));
if (savedState) {
    store.replaceState(savedState);
}

这种方法具有一定的局限性,因为它不能实时同步状态,用户在一个页面上进行的修改不会立即反映到其他页面上。

2. 使用 URL 参数

如果状态比较简单,可以通过 URL 参数在页面间传递状态。例如,在一个页面中点击链接,带上状态参数:

<a href="page2.html?myState=value">Go to Page 2</a>

在目标页面中,可以读取 URL 参数来获取状态:

const urlParams = new URLSearchParams(window.location.search);
const myState = urlParams.get('myState');
3. 使用 WebSocket 或其他实时通信技术

如果需要在页面间实现实时的状态共享,可以使用 WebSocket、Server-Sent Events 或其他实时通信技术。每个页面都可以连接到同一个 WebSocket 服务器,以便在状态变化时进行广播。

4. 使用 Shared Worker

Shared Worker 是一种在多个浏览器上下文(如多个标签页或窗口)间共享的 Worker。通过 Shared Worker,你可以在多个页面间共享状态。

// sharedWorker.js
let connections = [];
const storeState = { /* initial state */ };

self.onconnect = function(event) {
    const port = event.ports[0];
    connections.push(port);

    port.onmessage = function(e) {
        // 更新状态逻辑
        storeState.value = e.data;
        connections.forEach(conn => conn.postMessage(storeState));
    };
};

然后在每个页面中连接到这个 Shared Worker

const worker = new SharedWorker('sharedWorker.js');

worker.port.onmessage = function(e) {
    // 处理状态更新
    const sharedState = e.data;
};

worker.port.postMessage(newState);
5. 使用 Service Workers

Service Workers 可以缓存数据并在多个页面间共享,虽然通常它们用于缓存请求和离线功能,但也可以通过 IndexedDB 或其他方式存储状态。

注意事项

  1. 复杂性: 实现状态共享可能会增加应用的复杂性,特别是在处理状态同步和冲突时。
  2. 性能: 考虑性能影响,尤其是当状态较大或更新频繁时,使用 WebSocket 或 Shared Worker 可能更合适。
  3. 设计模式: 设计时要考虑如何管理状态的生命周期,确保在适当的时间清理不再需要的状态。

2.html-webpack-plugin 如何解析非 .html 的模板,比如 .hbs,应该如何配置?

html-webpack-plugin 是用于生成 HTML 文件的 Webpack 插件,默认情况下,它使用 .html 文件作为模板。但是,如果想使用其他类型的模板文件(如 .hbs,即 Handlebars 模板),可以通过配置相应的加载器来实现。

以下是如何配置 html-webpack-plugin 以解析 .hbs 模板的步骤:

1. 安装必要的依赖

首先,确保安装了 html-webpack-plugin handlebars-loader(用于处理 Handlebars 模板):


npm install html-webpack-plugin handlebars-loader --save-dev
2. 配置 Webpack

然后,需要在 Webpack 配置文件中配置这两个包。一个典型的 Webpack 配置可能类似于以下内容:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: './src/index.js', // 你的入口文件
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist'),
    },
    module: {
        rules: [
            {
                test: /\.hbs$/,
                loader: 'handlebars-loader', // 使用 Handlebars 加载器
            },
            // 其他加载器...
        ],
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/template.hbs', // 指定你的 Handlebars 模板
            filename: 'index.html', // 输出的 HTML 文件名
        }),
    ],
};
3. 使用 Handlebars 模板

在 .hbs 模板文件中,可以使用 Handlebars 的语法来定义 HTML 结构。例如:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{title}}</title>
</head>
<body>
    <div id="app"></div>
    <script src="bundle.js"></script>
</body>
</html>
4. 提供模板数据

如果需要在模板中使用动态数据(如标题等),可以在插件配置中通过 templateParameters 属性提供这些数据:

new HtmlWebpackPlugin({
    template: './src/template.hbs',
    filename: 'index.html',
    templateParameters: {
        title: 'My Handlebars Template',
        // 其他参数...
    },
}),

这样,{{title}} 将会被替换为 'My Handlebars Template'

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/945351.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

UE5材质节点SimpleGrassWind

SimpleGrassWind节点可以模拟树叶扰动&#xff0c;或小草晃动效果 用来做风格化树、风格化草效果很好 主要节点 前三个节点分别用来控制&#xff0c;风强度&#xff0c;风重力&#xff0c;风速度&#xff0c;WPO是世界位置偏移

macrodroid通过http请求控制手机运行宏

macrodroid adb命令 adb shell pm grant com.arlosoft.macrodroid android.permission.WRITE_SECURE_SETTINGS例:http请求手机播放指定MP3文件 声音素材_电量过低提醒 新建一个宏 添加触发器-连接-http服务器请求 路径随意填,最好不要有特殊符号,不然浏览器识别链接会出错,…

单片机中运行多个定时器

在单片机的裸机编程环境中&#xff0c;同时运行多个定时器是完全可行的&#xff0c;但需要注意一些关键点以确保系统的稳定性和效率。以下是一些考虑因素和实现方法&#xff1a; 1. 硬件支持 定时器数量&#xff1a;首先确认您的单片机是否具备足够的定时器资源。大多数现代…

快速上手LangChain(一)

文章目录 LangChain一、背景二、什么是langchain三、Components 组件Prompt templates 提示模板Chat models 聊天模型Messages 消息Document loadersText Spltters 文本分割Vectorstores 向量数据库 四、langchain基础概念Tool calling 工具调用&#xff08;1&#xff09; 工具…

大模型Weekly 03|OpenAI o3发布;DeepSeek-V3上线即开源!

大模型Weekly 03&#xff5c;OpenAI o3发布&#xff1b;DeepSeek-V3上线即开源&#xff01;DeepSeek-V3上线即开源&#xff1b;OpenAI 发布高级推理模型 o3https://mp.weixin.qq.com/s/9qU_zzIv9ibFdJZ5cTocOw?token47960959&langzh_CN 「青稞大模型Weekly」&#xff0c;持…

记录一下图像处理的基础知识

记录一下自己学习的图像处理的基础知识。 一、图像的文件格式以及常用的图像空间 1、文件格式 常见的图像文件格式有 jpg, png, bmp, gif &#xff08;1&#xff09;jpg&#xff1a;有损压缩算法&#xff0c;大幅减小文件大小&#xff0c;便于存储和传输&#xff0c;兼容性…

时间敏感网络中全面分析与调度的模型驱动方法

论文&#xff1a;A Model-Driven Approach for the Comprehensive Analysis and Scheduling in Time-Sensitive Networks》 背景与动机 TSN 的发展与应用领域&#xff1a;自 2012 年起&#xff0c;IEEE 802.1 TSN 任务组致力于开发通信标准&#xff0c;增强 IEEE 802 网络&…

QT---------GUI程序设计基础

代码UI化设计&#xff08;QT&#xff09; 实例功能概述 假设我们要创建一个简单的计算器应用程序。该应用程序具有以下功能&#xff1a; 包含数字按钮&#xff08;0-9&#xff09;、操作符按钮&#xff08;、-、*、/&#xff09;、等于按钮&#xff08;&#xff09;和清除按…

大模型提示词初探

大模型提示词初探 在与大模型交互的过程中&#xff0c;提示词起着至关重要的作用&#xff0c;它犹如给模型下达的精准任务指令&#xff0c;直接影响着模型生成内容的准确性、高效性与合理性。合理运用提示词&#xff0c;能够有效减少模型出现错误和幻觉的情况&#xff0c;从而…

Navicat 连接 SQL Server 详尽指南

Navicat 是一款功能强大的数据库管理工具&#xff0c;它提供了直观的图形界面&#xff0c;使用户能够轻松地管理和操作各种类型的数据库&#xff0c;包括 SQL Server。本文将详尽介绍如何使用 Navicat 连接到 SQL Server 数据库&#xff0c;包括安装设置、连接配置、常见问题排…

【Linux】进程间通信-> 共享内存

共享内存原理 在C语言/C中&#xff0c;malloc也可以在物理内存申请空间&#xff0c;将申请的物理内存空间通过页表映射到进程地址空间&#xff0c;将内存空间的起始地址&#xff08;虚拟地址&#xff09;返回&#xff0c;进而进程可以使用虚拟地址通过页表映射到物理内存的方式…

高仿CSDN编辑器,前端博客模板

高仿CSDN编辑器纯前端模板&#xff0c;使用的js、html、vue、axios等技术&#xff0c;网络请求库已进行封装&#xff0c;可以按需调整界面,需要源码联系(4k左右)。 1.支持代码高亮 2.支持目录点击定位 3.支持文件上传、图片上传&#xff08;需要自己写后端接口&#xff09; 4.M…

国产低代码框架zdppy开发笔记002 标准的接口响应

前言 通过前面的学习, 我们已经知道了zdppy_api和zdppy_req的基本用法, 接下来我们会在学习中多次用到这两个框架. 我们已经知道了该如何响应一个字符串,但是我们该如何响应json数据呢? 在zdppy_api中,我们定义了一组规范的API响应, 我们慢慢来看看. 规范的响应 首先来看…

实用技巧:关于 AD修改原理图库如何同步更新到有原理图 的解决方法

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/144738332 长沙红胖子Qt&#xff08;长沙创微智科&#xff09;博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV…

牛客周赛 Round 74

D. 预知 题目链接 题意有点绕&#xff0c;简单来说是其中一堆牌&#xff0c;问最少预知几张才能保证任取两张都不会导致种类重复。一开始对每张牌种类不是已知的&#xff0c;已知的是每种牌的牌数。 思路就是相当于把其中一种明牌&#xff0c;保证任取两张都不会导致种类重复…

【linux学习指南】SIGCHLD信号

文章目录 &#x1f4dd;SIGCHLD信号&#x1f6a9;总结 &#x1f4dd;SIGCHLD信号 进程⼀章讲过⽤wait和waitpid函数清理僵⼫进程,⽗进程可以阻塞等待⼦进程结束,也可以⾮阻塞地查询是否有⼦进程结束等待清理(也就是轮询的⽅式)。采⽤第⼀种⽅式,⽗进程阻塞了就不能处理⾃⼰的⼯…

AI助力SEO优化的关键词策略解析

内容概要 在数字营销的快速发展中&#xff0c;人工智能&#xff08;AI&#xff09;正逐步成为提升搜索引擎优化&#xff08;SEO&#xff09;效果的重要工具。关键词策略是SEO成功的关键要素之一&#xff0c;而AI技术的应用使得这一过程更加高效和精准。在关键词研究中&#xf…

PHP-Casbin v4.0.0 发布,支持 ACL、RBAC、ABAC 等模型的访问控制框架

PHP-Casbin 是一个用 PHP 语言打造的轻量级开源访问控制框架&#xff0c;支持 ACL、RBAC、ABAC 多种模型。它采用了元模型的设计思想&#xff0c;支持多种经典的访问控制方案&#xff0c;如基于角色的访问控制 RBAC、基于属性的访问控制 ABAC 等。 更新内容&#xff1a; http…

解决Git中没有小绿勾与红叉叉的问题

一、检查自己的软件 必须安装Git和Tortoisegit&#xff08;也就是俗称的小乌龟&#xff09;这两个软件。 Git的下载地址&#xff1a; CNPM Binaries Mirrorhttps://registry.npmmirror.com/binary.html?pathgit-for-windows/ 寻找与自己电脑相配的软件版本就可以了。 Tor…

搭建跨境电商企业博客的指南

在跨境电商领域&#xff0c;企业博客不仅是展示品牌形象的窗口&#xff0c;也是连接全球客户的重要桥梁。一个精心搭建的企业博客能够提升品牌知名度、增强客户信任&#xff0c;并促进销售。 搭建企业博客的必要性 1. 建立品牌权威&#xff1a;通过高质量的内容&#xff0c;企…