快速打通 Vue 3(五):详解 Vue 中的路由

08. 路由

很激动进入了 Vue 3 的学习,作为一个已经上线了三年多的框架,很多项目都开始使用 Vue 3 来编写了
这一组文章主要聚焦于 Vue 3 的新技术和新特性
如果想要学习基础的 Vue 语法可以看我专栏中的其他博客
Vue(一):Vue 入门与 Vue 指令
Vue(二):计算属性与 watch 监听器
Vue(三):Vue 生命周期与工程化开发
一篇文章快速通关 Vuex(适合小白学习)
Vue 框架前导:详解 Ajax
快速打通 Vue 3(一):基本介绍与组合式 API
快速打通 Vue 3(二):响应式对象基础
快速打通 Vue 3(三):Vue3 中的 watch 监听器与新特性
快速打通 Vue 3(四):标签的 ref 属性与 Vue3 生命周期
上一篇 Vue3 博客:快速打通 Vue 3(四):标签的 ref 属性与 Vue3 生命周期
后续还会继续更新,期待大家的关注!

这篇博客真的写了好久,期间我尝试了新的整理的方式,因为路由在开发中是十分重要的模块,所以我在博客中插入了实战的案例,希望能帮助大家更好的理解和学习路由。

8.1 路由的理解

提到路由器大家一定都非常熟悉,但是如果问起路由器的功能,或许很多人都有疑问

路由器(Router)是连接两个或多个网络的硬件设备,在网络间起 网关 的作用,是读取每一个 数据包 中的地址然后决定如何传送的专用智能性的 网络设备

比如我们手机和电脑同时去接收网络数据的时候,这两个设备需要的信息肯定是不同的,传输过来的数据包会带有地址,路由器会根据传输过来的数据中的地址去决定选择哪个设备。

vue 中的路由和上面路由器的作用是相同的,路由会根据我们的地址不同去 局部的 更新我们页面的内容。

这么说可能很抽象,我们来看一个具体的例子:网易云音乐网页端

通过上方的导航栏实现跳转,点击导航栏之后,我们发现只是变化了导航栏下面的区域,而导航栏区域是没有变化的,做过网页的朋友应该都知道当我们点击一个超链接后,整个页面都会刷新,没法做到这种局部的更新,对于这种页面,我们称之为 单页应用[^4],这就需要来借助路由去实现了。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在来回想一下我们的需求:我们想要做一个网页,网页上部有导航栏,通过单击导航栏来实现下面部分的改变但不想要刷新整个界面,这就有了一下的几个问题:

  1. 我们如何在不触发刷新的情况下改变地址呢?
  2. 程序是怎么知道我们想让内容变化的呢,并且找到响应的界面的呢?
  3. 我们更新的内容放置在哪里呢?

下面我们带着这两个问题继续学习。

8.2 基本使用

上面的一切内容都是路由实现的,在开始之前,我们先来导入 vue-router

Vue Router 官网

vue3 的项目中,我们直接引入最新的路由,新建一个 vue3 的项目

$npm create vue@latest

$yarn create vue

$pnpm create vue

其实很容易的发现,上面的网易云跳转的时候,网址是在我们的点击中变化的,所以不难得出,路由是 监听网址的变化 来得知我们想要去更新界面,而不同的网址就对应不同的界面,上面提到的第二个问题就很好解决了:

路由根据我们的网址的变化去得知我们要更新界面;而根据网址的内容去匹配不同的组件[^5]。

那我们对路由的配置就需要这些内容,下面我们来看看路由的基本写法:

import { RouteRecordRaw } from "vue-router";
import HomeView from "@/views/HomeView.vue";
import AdminView from "@/views/admin/AdminView.vue";
import UserLayout from "@/layouts/UserLayout.vue";
import UserLoginView from "@/views/user/UserLoginView.vue";
import UserRegisterView from "@/views/user/UserRegisterView.vue";
import AboutView from "@/views/user/AboutView.vue";
import CreateView from "@/views/admin/CreateView.vue";
export const routes: Array<RouteRecordRaw> = [
  {
    path: "/user",
    name: "用户",
    component: UserLayout,
    children: [
      {
        path: "/user/login",
        component: UserLoginView,
      },
      {
        path: "/user/register",
        component: UserRegisterView,
      },
    ],
  },
  {
    path: "/",
    name: "浏览题目",
    component: HomeView,
  },
  {
    path: "/create",
    name: "答题界面",
    component: CreateView,
  },
  {
    path: "/admin",
    name: "创建题目",
    component: AdminView,
  },
  {
    path: "/about",
    name: "关于我的",
    component: AboutView,
  },
];

上面是我在我的 OJ 系统中写的路由配置,最基本的三个配置就是

  • 路径的 地址
  • 路径的 名字
  • 路径对应的 组件

这就做好了匹配的关系:根据网址的变化去找路由,路由去根据配置去变化内容。

但是我们写的路由是没有作用的,我们既没有注册路由也没有去使用路由,下面我们来看路由的注册与使用:

注册:

import { createRouter, createWebHistory } from "vue-router";
import { routes } from "@/router/routes";

const router = createRouter({
    // 这条语句的作用在后面去解答
  history: createWebHistory(),
  routes,
});

export default router;

使用:

import { createApp } from "vue";
import ArcoVue from "@arco-design/web-vue";
import App from "./App.vue";
import "@arco-design/web-vue/dist/arco.css";
import router from "./router";
import store from "./store";
import "@/access";
import "bytemd/dist/index.css";
import { Message } from "@arco-design/web-vue";

const app = createApp(App);
app.use(store).use(router).use(ArcoVue).mount("#app");
Message._context = app._context;

使用只需要引入注册的 router 然后在 app 后面加上一个 use 即可,这样我们 全局的跳转逻辑就全部由路由去接管了

地址变化会改变下面的内容,这时候就需要有东西可以改变地址担又不刷新界面,这就是我们导航栏的作用,可以理解为一种特殊的超链接。

而这种效果需要用到一种特殊的组件 <RouterLink>

 <RouterLink to="/home"> 首页 </RouterLink>

其中最重要的属性就是 to 表示要变化到什么内容。

那只剩下最后一个问题了,我们更新的内容,也就是新的组件要放在哪里,vue 也提供了我们一个组件 RouterView 直接将这个放在我们所需要的区域即可。

<template>
  <div class="app">
    <h2 class="title">Vue路由测试</h2>
    <!-- 导航区 -->
    <div class="navigate">
      <RouterLink to="/home">首页</RouterLink>
      <RouterLink to="/news">新闻</RouterLink>
      <RouterLink to="/about">关于</RouterLink>
    </div>
    <!-- 展示区 -->
    <div class="main-content">
      <RouterView></RouterView>
    </div>
  </div>
</template>

这个区域就是放现在的组件和更新的组件放置的位置。

那我们理解之前网易云音乐网页端就很容易了:

在这里插入图片描述

上方的导航栏就类似 RouterLink,下面展示的内容就是 RouterView

通过上面的例子,路由组件是一块相当大的区域,甚至在一整个界面中,而且路由组件不是只用导入然后在通过尖括号的方式直接添加到网页中,而是要借助 RouterView 。但是,这两种的组件的后缀居然都是 .vue 这里就需要区分开:

  1. 将路由的组件存放在 pages 或者 views 文件夹中
  2. 一般的组件存放在 components 文件夹中
  3. 路由组件一般取名叫 xxxView.vue 比如 UserLoginView.vue,我们一般将路由组件视作一个视图。

8.3 路由的两种工作模式

这一段主要是解释上面创建路由的时候加了一条语句

const router = createRouter({
    // 这条语句的作用在后面去解答
  history: createWebHistory(),
  routes,
});

就是这个 history ,这里就需要提到路由的两种工作模式

  • 基于哈希(Hash-based)
  • 基于浏览器历史记录(History-based)

来看看他们具体的解释:

  1. 基于哈希(Hash-based):
    • 在这种模式下,路由信息被存储在URL的片段标识符中,即URL的哈希部分(通常是#后面的部分)。
    • 哈希模式的优势在于它不会导致完整的页面刷新,因为哈希的变化不会触发浏览器向服务器请求新页面。
    • 这种模式的一个示例是:http://example.com/#/page1。在这里,#/page1 是路由信息。
  2. 基于浏览器历史记录(History-based):
    • 在这种模式下,路由信息直接集成在URL的路径中,而不是依赖于哈希。
    • 使用 HTML5 的 History API,开发者可以通过添加、修改和删除浏览器历史记录条目来实现前端路由。
    • 这种模式的一个示例是:http://example.com/page1。在这里,/page1 是路由信息。

这两种模式带给我们最直观的效果就是带不带 #,这两种模式各有优势:

  1. history模式

    优点:URL更加美观,不带有#,更接近传统的网站URL

    缺点:后期项目上线,需要服务端配合处理路径问题,否则刷新会有404错误。

  2. hash模式

    优点:兼容性更好,因为不需要服务器端处理路径。

    缺点:URL带有#不太美观,且在SEO优化方面相对较差。

所以如果是内部的管理系统的话,用哈希模式其实方便我们的部署,而且内部应用也不需要 SEO,但像网易云这种开放给外部使用的还是建议使用第一种,虽然在部署的时候有一点麻烦(确实是只有一点),但 SEO 优化很好而且地址也比较美观。

8.4 to 的两种写法

让我们继续回到主线上来,RouterLink 中最重要的属性就是 to ,它可以指定我们选择的组件,并且可以 传参,之所以选择这种复杂的传参方式是因为路由组件并不像普通的组件那么方便,可以通过写自定义属性的方式来实现直接传参。

路由组件没有位置去写自定义属性,所以采取这种较为曲折的方式来传递参数,下面提供的 to 的第二种对象写法就是方便后面进行传参去使用的,具体的语法后面再提及。

<!-- 第一种:to的字符串写法 -->
<router-link active-class="active" to="/home">主页</router-link>

<!-- 第二种:to的对象写法 -->
<router-link active-class="active" :to="{path:'/home'}">Home</router-link>

8.5 嵌套路由

继续打开我们的网易云

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在发现音乐的下面还有几个标题,这些
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

点击之后我们发现路径是这样的

https://music.163.com/#/discover/toplist

https://music.163.com/#/discover/playlist

如果我们在一个路由组件内还想嵌套另一个路由组件,就需要地址去嵌套另一个地址,这就是我们说的嵌套路由

下面我们来看具体的写法:

嵌套路由写法:

{
	name: '推荐',
	path: '/discover',
	component: DiscoverView,
	children:[
            {
                name: '排行榜',
                path: '/toplist',
                component: ToplistView
            }
		]
},

跳转写法:

<router-link to="/discover/toplist"> xxxx </router-link>

<!---->

<router-link :to="{path:'/discover/toplist'}"> xxxx </router-link>

最后记得在组件中再去预留一个 RouterView

<template>
  <div class="news">
    <nav class="news-list">
      <RouterLink v-for="title in titleList" :key="title.id" 
      :to="{path:/discover/toplist}">
        {{title.name}}
      </RouterLink>
    </nav>
    <div class="title-detail">
      <RouterView/>
    </div>
  </div>
</template>

8.6 路由传参

因为和路由组件的特殊性(不能在父组件写自定义属性),所以我们需要新的方式来实现传参

8.6.1 query 参数

我们上面已经得知 to 参数的两种写法,但还是没有体会到第二种写法到底好在哪里,下面贴出一段代码:

不用对象写法

<!-- 跳转并携带query参数(to的字符串写法) -->

<router-link to="/news/detail?a=1&b=2&content=欢迎你">
	跳转
</router-link>

使用对象写法

<RouterLink 
  :to="{
    //name:'xiang', //用name也可以跳转
    path:'/news/detail',
    query:{
      id:news.id,
      title:news.title,
      content:news.content
    }
  }"
>
  {{news.title}}
</RouterLink>

这样一对比第二种写法的优势就很明显了,如果我们传递的参数变多后面就要嵌套一大堆 / ,而且我们需要传递 不写死的内容,还需要写好多 ${},所以以后在开发中最好使用第二种写法。

接收参数

import {useRoute} from 'vue-router'
const route = useRoute()
// 打印query参数
console.log(route.query)

我们可以直接使用 route 中的 query 参数来取得传递的参数。

8.6.2 params 参数

用在传递的参数和路径紧密结合的情况,路径符合 RestFul 风格

定义路由

与前面不同的是,params 参数需要我们提前指定参数,当然也可以通过 ? 修饰符来作为选择传递的内容。

// 路由配置
const routes = [
  {
      // path: '/book/:id?', 可以选择是否传入
    path: '/book/:id',
    component: BookDetails,
    name: 'book-details',
  },
];

传递参数

    <div>
      <RouterLink :to="{ name: 'book-details', params: { id: 1 }}">Book 1</router-link>
      <RouterLink :to="{ name: 'book-details', params: { id: 2 }}">Book 2</router-link>
      <RouterView />
    </div>

接收参数

import {useRoute} from 'vue-router'
const route = useRoute()
// 打印params参数
console.log(route.params)

注意:如果使用 params 写法的时候,必须要使用 name 来指定路由,而不是使用前面经常使用的的 path

8.6.3 props 传参

props 传参可以将路由参数作为 props 传递给子组件,这是最简洁的一种方式

params 参数作为 props 传递

{
    name:'xiang',
    path:'detail/:id/:title/:content',
    component:Detail,
    // props的布尔值写法,作用:把收到了每一组params参数,作为props传给Detail组件
    props:true
}

query 参数作为 props 传递

{
    name:'xiang',
    path:'detail',
    component:Detail,
    // props的函数写法,作用:把返回的对象中每一组key-value作为props传给Detail组件
    props(route){
    	return route.query
    }
}

接收参数并且使用

const props = withDefaults(defineProps<Props>(), {
	// 定义需要接收的属性和初始值
});

8.7 replace 与 push

我们可以把路由器的历史记录视作一个栈,我们前面使用的所有跳转逻辑都是 push 的方式,即在栈顶部插入一个数据

这样的排布方式可以让浏览器实现前进和后退

但如果用户进入一个界面后,我们不希望用户可以通过回退来返回上一个页面就要使用到 replace 配置

要实现也非常容易

<RouterLink to="/page1" replace>Page 1</RouterLink>

只需要在后面加上一个 replace 即可

8.7 编程式路由

这是路由非常重要的一部分,因为我们开发中不可能总是使用 RouteLink 去实现跳转,因为 RouterLink 最多算是一个特殊的超链接,超链接就需要用户去点击,当我们想做一些不点击就跳转的逻辑,就需要在 script 部分去编写跳转逻辑,而不能去使用 RouterLink

编程式路由学习起来非常简单,因为它和上面的 RouterLink 几乎是一模一样的,RouterLink 中的 to 属性中传递的内容就是我们使用编程式路由的时候传递的参数。

const route = useRoute();
const router = useRouter();
console.log("route", route);
console.log("router", router);

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

编程式最重要的两个内容就是 routerouter

  • route 是路径,封装这我们传递的属性
  • router 是路由器,负责跳转逻辑

我们的编程式就是通过 router 中的 pushreplace 来实现的,分别对应着上面的两种方式,而传递的参数就是 RouterLink 中的 to 属性的参数。

下面给出一个案例,是我项目中代码的一部分,实现了登录的逻辑和登录之后的跳转:

页面结构部分

<template>
  <div class="userLogin">
    <a-layout style="height: 400px">
      <a-layout-content class="content">
        <div class="showImg">
          <div class="loginForm">
            <div class="title">登录</div>
            <a-form
              :model="form"
              :style="{ width: '400px' }"
              @submit="handleSubmit"
              :size="'large'"
              class="form"
            >
              <a-form-item
                field="name"
                style="margin-bottom: 25px"
                arco-theme="dark"
              >
                <a-input
                  v-model="form.userAccount"
                  placeholder="请输入你的用户名"
                />
              </a-form-item>
              <a-form-item field="post" style="margin-bottom: 30px">
                <a-input-password
                  v-model="form.userPassword"
                  placeholder="密码"
                />
              </a-form-item>
              <a-form-item>
                <a-button html-type="submit">登录</a-button>
              </a-form-item>
            </a-form>
          </div>
        </div>
      </a-layout-content>
      <a-layout-footer></a-layout-footer>
    </a-layout>
  </div>
</template>

我这里使用的是 Arco Design 中的登录表单组件用户输入账号和密码

在这里插入图片描述

<script setup lang="ts">
import { reactive } from "vue";
import { useRouter } from "vue-router";
import store from "@/store";
import AccessEnum from "@/access/accessEnum";
import { UserControllerService, UserLoginDTO } from "../../../../generated";
import { Message } from "@arco-design/web-vue";

    // 绑定表单属性
const form = reactive({
  name: "",
  password: "",
} as UserLoginDTO);
const router = useRouter();
    // 向后端去请求检查
const handleSubmit = async () => {
  const res = await UserControllerService.userLogin(form);
  console.log(res.data);
  if (res.code == 200) {
    Message.success("登录成功");
    localStorage.setItem(AccessEnum.TOKEN_NAME, res.data.token);
    store.commit("updateUser", res.data);
    console.log("登陆后的结果", store.state.loginUser);
      // 跳转
    router.push({
      path: "/",
    });
  } else {
      // 密码错误执行逻辑
    Message.warning("用户名或密码错误");
    console.error();
  }
};
</script>

8.8 重定向

实现当我们进入一个路径的时候,重定向到已经有的路由:

{
    path:'/',
    redirect:'/about'
}

这就实现了当我们访问 / 的时候,自动重定向到 /about 对应的组件。

如果这篇博客帮助到了你,请留下你的关注和评论叭😊😊😊

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

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

相关文章

蓝桥杯备战——5.动态数码管扫描

1.分析原理图 经查阅说明书得知数码管为共阳极&#xff0c;共阳端口接到了U8,而段码接到了U7。 如果需要选中U8,我们只需要将P250;P261;P271; 如果需要选中U7,我们只需要将P251;P261;P271; 2.代码示例 void Delay1ms() //12.000MHz {unsigned char data i, j;i 12;j 169;…

贪心算法-01:跳跃游戏

关于贪心算法 贪心算法是动态规划的一个特例&#xff0c;相对于动态规划&#xff0c;使用贪心算法需要满足更多条件&#xff0c;但是效率比动态规划要高。 贪心选择的性质就是&#xff1a;每一步都做出一个局部最优解&#xff0c;最终的结果就是全局最优。不过这是一种特殊性…

uniapp组件库中Collapse 折叠面板 的使用方法

目录 #平台差异说明 #基本使用 #控制面板的初始状态&#xff0c;以及是否可以操作 #自定义样式 #1. 如果修改展开后的内容&#xff1f; #2. 如何自定义标题的样式&#xff1f; #3. 如何修改整个Item的样式&#xff1f; #API #Collapse Props #Collapse Item Props #…

ORM-06-jooq 入门介绍

拓展阅读 The jdbc pool for java.(java 手写 jdbc 数据库连接池实现) The simple mybatis.&#xff08;手写简易版 mybatis&#xff09; JOOQ JOOQ 可以通过数据库直接生成 java 代码&#xff0c;通过 flent-api 进行数据库操作。 SQL builder JOOQ 非常的灵活和强大。你可…

深入理解旅游网站开发:Java+SpringBoot+Vue+MySQL的实战经验

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

flink内存管理(三):MemorySegment内存使用场景:托管内存与网络内存

文章目录 一.ManagedMemory&#xff08;算子&#xff09;内存的申请与使用1. tm内存申请与使用大致流程2. 创建MemoryManager实例3. 算子使用通过MemoryManager使用内存4. ManagedMemory内存空间申请流程 二.NetworkBuffer内存申请与使用1. NetworkBuffer构造器 在Flink内存模型…

Windows11 Copilot助手开启教程(免费GPT-4)

Windows11上开启Copilot助手教程踩坑指南 Copilot介绍Copilot开启步骤1、更新系统2、更改语言和区域3、下载 ViVeTool 工具4、开启Copilot 使用 Copilot介绍 Windows Copilot 是 Windows 11 中的一个新功能&#xff0c;它可以让你与一个智能助理进行对话&#xff0c;获取信息&…

树莓派无显示屏连接

终端命令控制树莓派关机 1&#xff1a;用网线连接树莓派 按照正常的步骤 &#xff0c;搜索控制面板&#xff0c;网络和internet&#xff0c;网络和共享中心&#xff0c;更改适配器设置&#xff0c;右键WIFI&#xff0c;点击属性&#xff0c;点击共享&#xff0c;打勾允许即可&…

5G安卓手机定制_基于天玑900的安卓主板方案

5G安卓手机方案是一款采用联发科MT6877(天玑900)平台的高性能、可运行安卓操作系统的5G智能模块。该手机采用台积电6纳米低功耗工艺&#xff0c;主频高达2.4GHz&#xff0c;内存支持LPDDR5&#xff0c;并支持5G Sub-6GHz全频段和5G双载波聚合技术等多种制式。同时&#xff0c;该…

Typora1.7.6安装、激活、图床设置和使用

1.安装Typora 双击”typora-setup-x64-1.7.6.exe“安装包。 如果之前安装过先卸载&#xff0c;删除原文件夹。 Typora 1.7.6下载 提取码&#xff1a;ix2b 选择“Install for all users”。 图1-1 选择安装模式 选择安装目录&#xff0c;然后选择“Next”。 图1-2 选择安装路…

23111 C++ day2

思维导图 自己封装一个矩形类(Rect)&#xff0c;拥有私有属性:宽度(width)、高度(height),定义公有成员函数: 初始化函数:void init(int w, int h)更改宽度的函数:set_w(int w)更改高度的函数:set_h(int h) 输出该矩形的周长和面积函数:void show() #include <iostream&g…

web安全学习笔记【10】——数据包分析

基础[1] [2] [3] [4] 入门-HTTP数据包&Postman构造&请求方法&请求头修改&状态码判断[5] [6] [7] #知识点&#xff1a; 1、Web常规-系统&中间件&数据库&源码等 2、Web其他-前后端&软件&Docker&分配站等 3、Web拓展-CDN&WAF&OS…

go语言(十三)-----interface

一、Interface 通用万能类型 空接口int&#xff0c;string&#xff0c;float&#xff0c;struct都实现了interface都可以用interface{}类型,引用任意的数据类型 package mainimport "fmt"//interface()是万能数据类型 func myFunc(arg interface{}) {fmt.Println(&…

pycharm中无法使用anaconda虚拟环境

anaconda里创建了虚拟环境&#xff0c;然后在虚拟环境中明明安装了TensorFlow1.12&#xff0c;但是到pycharm中使用anaconda的虚拟环境时&#xff0c;就是没有TensorFlow1.12&#xff0c;注意下面这幅图 里面有一个选项“use conda package manager”&#xff0c;这个默认是勾…

聊聊 程序员裁员潮:技术变革下的职业危机

前几天一则新闻爆料&#xff1a;一对来自中国的工程师夫妻在美身亡&#xff0c;疑因谷歌裁员致悲剧发生。看到后深感可惜&#xff0c;鲜活的生命就因为裁员殒落了&#xff1b;同时我也深有感触&#xff0c;有幸经历过裁员&#xff0c;体会过那一段低迷不振的日子。 但是回首当下…

Aleo项目详细介绍-一个兼顾隐私和可编程性的隐私公链

Aleo上线在即&#xff0c;整理一篇项目的详细介绍&#xff0c;喜欢的收藏。有计划做aleo节点的可交流。 一、项目简介 Aleo 最初是在 2016 年构思的&#xff0c;旨在研究可编程零知识。公司由 Howard Wu、Michael Beller、Collin Chin 和 Raymond Chu 于 2019 年正式成立。 …

Docker 和 Kubernetes:容器化时代的崛起与演变

在过去的十年间&#xff0c;容器化技术彻底改变了软件开发和部署的面貌。 Docker 的登场无疑是这场变革的催化剂&#xff0c;它将应用和服务的打包、分发、部署流程标准化&#xff0c;让开发者的生活变得更加简单。 紧随其后&#xff0c;Kubernetes 作为容器编排的领军者&#…

文旅AI交互数字人,提升景区数字化导览服务体验

随着数字化的普及&#xff0c;文化旅游逐渐走向数字化&#xff0c;通过数字人技术手段对文化旅游资源进行整合与开发。 AI交互数字人可以部署于交互式终端设备和移动端&#xff0c;可以为游客提供“面对面”的语音交互&#xff0c;提供路径规划、游览路线推荐、景点讲解等服务&…

IP被封怎么办?访问网站时IP被阻止?解决IP禁令全方法

相信很多人遇到过IP禁令&#xff1a;比如你在访问社交媒体、搜索引擎或电子商务网站时会被限制访问&#xff0c;又或者你的的账号莫名被封&#xff0c;这些由于网络上的种种限制我们经常会遭遇IP被封的情况&#xff0c;导致无法使用继续进行网络行动。在本文中&#xff0c;我们…

【Leetcode】2859. 计算 K 置位下标对应元素的和

文章目录 题目思路代码结果 题目 题目链接 给你一个下标从 0 开始的整数数组 nums 和一个整数 k 。 请你用整数形式返回 nums 中的特定元素之和 &#xff0c;这些特定元素满足&#xff1a;其对应下标的二进制表示中恰存在 k 个置位。 整数的二进制表示中的 1 就是这个整数的…