【学习vue 3.x】(五)VueRouter路由与Vuex状态管理

news2024/12/23 12:44:08

在这里插入图片描述

文章目录

  • 章节介绍
    • 本章学习目标
  • 路由的基本搭建与嵌套路由模式
    • vue路由的搭建
    • 嵌套路由模式
  • 动态路由模式与编程式路由模式
    • 动态路由模式
    • 编程式路由
  • 命名路由与命名视图与路由元信息
    • 命名路由
    • 命名视图
    • 路由元信息
  • 路由传递参数的多种方式及应用场景
    • 路由传参
  • 详解route对象与router对象
    • route对象与router对象
  • 路由守卫详解及应用场景
    • 路由守卫分类
    • 完整的导航解析流程
  • Vuex共享状态的基本开发流程
  • Vuex处理异步状态及应用场景
  • Vuex计算属性和辅助函数的使用
    • getters计算属性
    • 辅助函数
  • Vuex-persist对数据进行持久化处理
  • Vuex分割模块及多状态管理
  • 组合式API中使用Router和Vuex注意事项
  • Router_Vuex的任务列表综合案例
  • 搭建 Vite3 + Pinia2 组合模式
    • 总结内容

章节介绍

小伙伴大家好,本章将学习VueRouter路由与Vuex状态管理 - 组织与架构应用。

本章学习目标

本章将学习Vue3中的路由与状态管理,随着前后端分离式开发的兴起,单页面应用开发(即SPA页面)也越来越流行,所以前端路由与共享状态也越来越重要!

路由的基本搭建与嵌套路由模式

在前面的小节中,已经介绍了什么是前端路由以及前端路由所具备的特点。本小节就来对路由进行实际搭建吧。

vue路由的搭建

路由在vue中属于第三方插件,需要下载安装后进行使用。版本说明一下,Vue3搭配的是Vue Router4,目前正常安装的话,就是路由4的版本。如下:

npm install vue-router

安装好后,需要对路由进行配置,并且与Vue进行结合,让路由插件生效。在/src/router/index.js创建配置文件。

在这里插入图片描述

可以通过 createWebHistory()来创建history模式的路由,也可以通过createWebHashHistory()来创建hash模式的路由。那么在浏览器中输入的URL该如何展示对应的组件呢?可以通过这个组件来实现。

除了进行展示外,还可以通过方式进行声明式的路由跳转,代码如下:

<template>
  <div>
    <router-link to="/">首页</router-link> | 
    <router-link to="/about">关于</router-link>
    <router-view></router-view>
  </div>
</template>

嵌套路由模式

往往我们的路由是比较复杂的,需要的层级也比较多,那么就会产生嵌套路由的模式,比如:localhost:8080/about/foolocalhost:8080/about/bar

import Foo from '@/views/Foo.vue'
import Bar from '@/views/Bar.vue'
const routes = [
    {
        path: '/about',
        component: About,
        children: [
            {
                path: 'foo',
                component: Foo
            },
            {
                path: 'bar',
                component: Bar
            }
        ]
    }
]

可以看到嵌套路由是通过children属性来完成的,那么对于这种嵌套路由写法,我们对应的也要在一级路由对应页面中添加一个,这样才能切换显示二级路由所对应的页面。

动态路由模式与编程式路由模式

动态路由模式

所谓的动态路由其实就是不同的URL可以对应同一个页面,这种动态路由一般URL还是有规律可循的,所以非常适合做类似于详情页的功能。

在这里插入图片描述

// router/index.js,定义动态路由

const routes = [
  {
  	path: 'foo/:id',
    component: Foo
  }
]

// views/Foo.vue,获取动态路由的id
export default {
  mounted(){
      console.log( this.$route.params.id );
  }
}

编程式路由

前面介绍过如何在页面中对路由进行切换,可以采用声明式写法来完成,但是往往这种方式不够灵活,首先不能更灵活的控制结构和样式,其次不能自动进行路由的跳转,必须点击操作才行。

那么编程式路由就会在JavaScript中通过逻辑的方式进行路由跳转,我们把这种写在JS中进行跳转路由的方式叫做编程式路由,这样方式会更加的灵活。

<template>
  <button @click="handleToBar">编程式路由跳转</button>
</template>
<script>
  export default {
    methods: {
      handleToBar(){
        this.$router.push('/about/bar');
      }
    }
  }
</script>

可以看到在动态路由中使用到了一个route对象,而在编程式路由中使用了一个router对象,那么这两个比较重要的路由对象,会在后面的小节中给大家进行详细的讲解。

命名路由与命名视图与路由元信息

命名路由

在路由跳转中,除了path 之外,你还可以为任何路由提供 name 的形式进行路由跳转。那么name方式的好处如下:

  • 没有硬编码的 URL
  • params 的自动编码/解码
  • 防止你在 url 中出现打字错误
  • 绕过路径排序(如显示一个)
// router/index.js,定义命名路由
const routes = [
    {
        path: '/about/bar',
        name: 'bar',
        component: Bar
    },
    {
        path: '/about/foo/:id',
        name: 'foo',
        component: Foo
    }
];
<!-- About.vue,使用命名路由跳转 -->
<template>
 	<div>
        <router-link :to="{ name: 'bar' }">bar</router-link>
        <router-link :to="{ name: 'foo', params: {id: 123} }">foo 123</router-link>
    </div>
</template>

name的方式也支持动态路由形式。

命名视图

有时候想同时 (同级) 展示多个视图,而不是嵌套展示,这个时候就非常适合使用命名视图。
在这里插入图片描述

通过components字段配置多个组件,根据不同的router-view去渲染不同的组件。

路由元信息

有时,你可能希望将任意信息附加到路由上,如过渡名称、谁可以访问路由等。这些事情可以通过接收属性对象的meta属性来实现。

const routes = [
    {
        path: '/about/bar',
        name: 'bar',
        component: Bar,
        meta: { auth: false }
    },
    {
        path: '/about/foo/:id',
        name: 'foo',
        component: Foo,
        meta: { auth: true }
    }
];

定义好meta元信息后,可通过route对象去访问meta属性。

<!-- Foo.vue -->
<script>
export default {
    mounted(){
        this.$route.meta.auth   // true
    }
}
</script>

路由传递参数的多种方式及应用场景

路由传参

我们经常要在路由跳转的时候传递一些参数,这些参数可以帮助我们完成后续的一些开发和一些处理。路由的传递参数主要有以下三种方式:

  • query方式(显示) -> $route.query
  • params方式(显示) -> $route.params

两种显示传递数据的差异点主要为,query是携带辅助信息,而params是界面的差异化。

<!-- About.vue -->
<template>
  <div>
    <router-link :to="{ name: 'bar', query: { username: 'xiaobai' } }">bar</router-link>
    <router-link :to="{ name: 'foo', params: { username: 'xiaoqiang' } }">foo</router-link>
  </div>
</template>

<!-- Bar.vue -->
<script>
    export default {
        mounted(){
            console.log(this.$route.query);
        }
    }
</script>
<!-- foo.vue -->
<script>
    export default {
        mounted(){
            console.log(this.$route.params);
        }
    }
</script>

前两种都是显示传递数据,那么第三种是隐式传递数据,这种方式并不会把数据暴露出来。

<!-- About.vue -->
<template>
  <div>
    <router-link :to="{ name: 'bar', params: { username: 'xiaoqiang' } }">bar</router-link>
  </div>
</template>

<!-- Bar.vue -->
<script>
    export default {
        mounted(){
            console.log(this.$route.params);
        }
    }
</script>

但是这里需要注意以下,隐式发送过来的数据,只是临时性获取的,一旦刷新页面,隐藏的数据就会消失,所以在使用的时候要额外注意以一下。

详解route对象与router对象

在前面小节中,我们频繁的使用过route对象和router对象,这两个对象在路由中非常的重要,下面我们来详细的学习一下。

route对象与router对象

首先route对象用来获取路由信息,而router对象用来调用路由方法的。具体区别在于,route对象是针对获取操作的,主要是操作当前路由的,而router对象是针对设置操作的,主要是操作整个路由系统对应的功能。

route对象具体功能如下:

  • fullPath
  • hash
  • href
  • matched
  • meta
  • name
  • params
  • path
  • query

主要就是一些路由信息,像常见的动态路由参数,query数据,meta元信息,url路径等等。

router对象具体功能如下:

  • addRoute
  • afterEach
  • back
  • beforeEach
  • beforeResolve
  • currentRoute
  • forward
  • getRoutes
  • go
  • hasRoute
  • push
  • removeRoute

主要就是一些方法,动态改变路由表,路由守卫, 历史记录的前进后退,编程式路由等等。

路由守卫详解及应用场景

正如其名,vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。这里有很多方式植入路由导航中:全局的,单个路由独享的,或者组件级的。

守卫主要的作用就是在进入到指定路由前做一个拦截,看一下我们是否具备权限,如果有权限就直接进入,如果没权限就跳转到其他页面。

路由守卫分类

一般可以分为三种路由守卫使用的方式:

  • 全局环境的守卫
  • 路由独享的守卫
  • 组件内的守卫

先来看一下如何设置全局的路由守卫,一般在路由配置文件中进行设置。

router.beforeEach((to, from, next)=>{
  if(to.meta.auth){
    next('/');
  }
  else{
    next();
  }
})

其中to表示需要进入到哪个路由,from表示从哪个路由离开的,那么next表示跳转到指定的页面。

有时候我们只是想给某一个指定的路由添加守卫,那么可以选择设置路由独享的守卫方式。

const routes = [
    {
        name: 'bar',
        component: Bar,
        beforeEnter(to, from, next){
            if(to.meta.auth){
                next('/');
            }
            else{
                next();
            }
        }
    }
];

还可以通过在.vue文件中进行路由守卫的设置,代码如下:

<script>
  export default {
    name: 'FooView',
    beforeRouteEnter(to, from, next){
      if(to.meta.auth){
        next('/');
      }
      else{
        next();
      }
    }
  }
</script>

完整的导航解析流程

  1. 导航被触发。
  2. 在失活的组件里调用 beforeRouteLeave 守卫。
  3. 调用全局的 beforeEach 守卫。
  4. 在重用的组件里调用 beforeRouteUpdate 守卫(2.2+)。
  5. 在路由配置里调用 beforeEnter
  6. 解析异步路由组件。
  7. 在被激活的组件里调用 beforeRouteEnter
  8. 调用全局的 beforeResolve 守卫(2.5+)。
  9. 导航被确认。
  10. 调用全局的 afterEach 钩子。
  11. 触发 DOM 更新。
  12. 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。

Vuex共享状态的基本开发流程

在上一个小节中,我们介绍了什么是Vuex,本小节我们一起来看一下Vuex共享状态的基本开发流程。首先我们来看一下Vuex的经典流程图。
在这里插入图片描述

我们可以看到,基本上就是先准备好一个共享数据state,然后渲染我组件中,通过组件调用dispatch -> actions -> commit -> mutations的方式来进行state修改。

那么这里我们先不考虑dispatch -> actions,因为这两个环节是处理异步程序的,那么我们直接组件去调用commit就可以触发mutations中定义的方法,这样在这个方法中进行state的修改。

首先在/src/store/index.js创建一个状态管理的配置文件,然后在main.js中让vuex于vue进行结合,就像我们路由的使用一样。

//  store/index.js
const store = createStore({
  state: {
    count: 0
  },
  mutations: {
    change(state, payload){
      state.count += payload;
    }
  }
});

//  main.js
import store from './store'
app.use(store)

下面看一下如何在页面中显示state数据和如何通过commit修改我们的共享数据,代码如下:

<template>
  <div>
    <button @click="change(5)">点击</button>
    hello home, {{ $store.state.count }}
  </div>
</template>
<script>
    export default {
        name: 'HomeView',
        methods: {
            handleClick(){
                this.$store.commit('change', 5);
            }
        }
    }
</script>

Vuex处理异步状态及应用场景

本小节中将讲解一下Vuex中如何处理异步程序,因为在上一个小节中提到过,mutations中只能处理同步,不能处理异步,所以异步的工作就交给了 actions 来完成。

那么如何触发actions中定义的方法呢,就需要通过dispatch进行触发,具体代码如下:

const store = createStore({
  state: {
    count: 0
  },
  actions: {
    change(context, payload){
      setTimeout(()=>{
        context.commit('change', payload)
      }, 1000)
    }
  },
  mutations: {
    change(state, payload){
      state.count += payload;
    }
  }
});
<script>
    export default {
        name: 'HomeView',
        methods: {
            handleClick(){
               this.$store.dispatch('change', 5);
            }
        }
    }
</script>

这样在vue devtools插件中就可以更好的观察到异步数据的变化。那么异步处理的应用场景有哪些呢?异步的获取后端的数据,这样可以利用状态管理来充当MVC架构中的C层,不仅衔接前后端,还能对数据进行共享,可以在切换路由的时候做到减少请求次数,而且状态管理配合本地存储进行数据持久化也是非常的方便。

Vuex计算属性和辅助函数的使用

Vuex中除了提供常见的异步处理和同步处理外,还提供了一些辅助的操作方式,比如:状态管理下的计算属性和简化操作的辅助函数。

getters计算属性

在Vuex中通过定义getters字段来实现计算属性,代码如下:

const store = createStore({
  state: {
    count: 0
  }
  getters: {
    doubleCount(state){
      return state.count * 2;
    }
  }
});
<template>
  <div>
    {{ count }}, {{ doubleCount }}
  </div>
</template>

当count数据发生改变的手,对应的计算属性doubleCount也会跟着发生改变。

辅助函数

在Vuex中为了让我们使用共享数据或调用方法的时候,更加简单易用,提供了对应的辅助函数,分别为:mapState、mapGetters、mapMutations、mapActions。

<template>
  <div>
    <button @click="change(5)">点击</button>
    hello home, {{ count }}, {{ doubleCount }}
  </div>
</template>

<script>
  import { mapState, mapGetters, mapActions } from 'vuex';
  export default {
    name: 'HomeView',
    methods: {
      ...mapActions(['change'])
    },
    computed: {
      ...mapState(['count']),
      ...mapGetters(['doubleCount'])
    }
  }
</script>

辅助函数最大的优点就是可以处理大量共享数据的需求,这样写起来会非常的简便,因为只需要往数组里添加子项即可。

Vuex-persist对数据进行持久化处理

默认情况下Vuex状态管理是不会对数据进行持久化存储的,也就是说当我们刷新浏览器后,共享状态就会被还原。那么我们想要在刷新的时候能够保持成修改后的数据就需要进行持久化存储,比较常见的持久化存储方案就是利用本地存储来完成,不过自己去实现还是比较不方便的,下面我们通过第三方模块来实现其功能。

模块github地址:https://github.com/championswimmer/vuex-persist。根据地址要求的配置操作如下:

// npm install vuex-persist
	
import VuexPersistence from 'vuex-persist';
const vuexLocal = new VuexPersistence({
  storage: window.localStorage,
  reducer: (state) => ({count: state.count})
})

const store = createStore({
  state: {
    count: 0,
    msg: 'hello'
  }
  plugins: [vuexLocal.plugin]
});

默认情况下,vuex-persist会对所有共享状态进行持久化,那么如果我们只需要对指定的属性进行持久化就需要配置 reducer字段,这个字段可以指定需要持久化的状态。

这样当我们修改了state下的count,那么刷新的时候会不会还原了,并且通过chrome浏览器中Application下的Local Storage进行查看。

Vuex分割模块及多状态管理

由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。

那么这个时候,所有共享状态的值都在一起,所有的方法也都放在了一起,维护起来非常的不方便。那么Vuex中可利用modules属性来配置模块化的共享状态,那么对于后期维护起来是非常方便的,也利于大型项目的架构。

在/store下创建一个modules文件夹,然后编写一个message.js,代码如下:

const state = {
  msg: 'hello'
};
const getters = {
  upperMsg(state){
    return state.msg.toUpperCase()
  }
};
const actions = {};
const mutations = {
  change(state, payload){
    state.msg = payload;
  }
};
export default {
  namespaced: true,
  state,
  getters,
  actions,
  mutations
}

模块中的选项跟index.js中的选项是一样的,对外提供接口的时候,可以看到一个namespaced字段,这表示当前模块的一个命名空间,主要是为了防止跟其他模块之间产生冲突,在调用的时候需要携带对应的命名空间标识符才行。

再来看一下index.js如何去收集我们的模块,并如何去使用我们的模块。

// store/index.js
import message from '@/store/modules/message'
const store = createStore({
  modules: {
    message
  }
});
<!-- About.vue -->
<template>
  <div>
    <button @click="change('hi')">点击</button>
    hello about, {{ msg }}, {{ upperMsg }}
  </div>
</template>

<script>
import { mapState, mapGetters, mapMutations } from 'vuex';
  export default {
    name: 'AboutView',
    methods: {
      // handleClick(){
      //   this.$store.commit('message/change', 'hi');
      // }
      ...mapMutations('message', ['change'])
    },
    computed: {
      //  msg(){
      //   return this.$store.message.msg;
      //  },
      //  upperMsg(){
      //   return this.$store.getters['message/upperMsg']
      //  }
      ...mapState('message', ['msg']),
      ...mapGetters('message', ['upperMsg'])
    }
  }
</script>

在辅助函数的情况下,也可以进行很好的调用,辅助函数的第一个参数就是命名空间的名字。

组合式API中使用Router和Vuex注意事项

前面介绍的路由和状态管理都是在选项式API中进行使用的,那么路由和状态管理在组合式API中使用的时候,需要注意哪些问题呢?

主要就是路由会提供两个use函数,分别为:useRoute和useRouter;同理状态管理页提供了一个use函数,useStore来操作的。

先来看一下路由相关use函数的使用情况:

<script setup>
import { useRoute, useRouter } from 'vue-router'
const route = useRoute();
const router = useRouter();
console.log( route.meta );
console.log( router.getRoutes() );
</script>

基本上跟选项式API中的用法是一样的,并没有太大的区别。

再来看一下状态管理相关use函数的使用情况:

<script setup>
import { useStore } from 'vuex'
const store = useStore();
console.log( store.state.count );
console.log( store.state.message.msg );
</script>

得到store对象,接下来的操作也是跟选项式API中使用的是一样的。

Router_Vuex的任务列表综合案例

本小节将对本章学习的路由加状态管理做一个综合案例,通过案例来巩固本章所学知识点。

在这里插入图片描述

首先先来配置案例中的路由,主要有三个页面,分别对应所有任务,已完成任务,未完成任务。

import { createRouter, createWebHistory } from 'vue-router'
import Todo from '@/views/Todo.vue'
import Complete from '@/views/Complete.vue'
import Incomplete from '@/views/Incomplete.vue'
const routes = [
  {
    path: '/',
    redirect: '/todo'
  },
  {
    path: '/todo',
    component: Todo
  },
  {
    path: '/complete',
    component: Complete
  },
  {
    path: '/incomplete',
    component: Incomplete,
  }
];
const router = createRouter({
  history: createWebHistory(),
  routes
})
export default router;

在来配置一下Vuex状态管理,主要对任务列表进行共享状态处理:

import { createStore } from "vuex";
const store = createStore({
  state: {
    todoList: [
      {
        isChecked: true, id: 1, task: '第一个任务'
      },
      {
        isChecked: false, id: 2, task: '第二个任务'
      }
    ]
  },
  actions: {
    
  },
  mutations: {
    add(state, payload){
      state.todoList.unshift({ isChecked: false, id: state.todoList.length, task: payload });
    }
  },
  getters: {
    complete(state){
      return state.todoList.filter((v)=> v.isChecked)
    },
    incomplete(state){
      return state.todoList.filter((v)=> !v.isChecked)
    }
  }
});
export default store;

最后看一下三个页面的基本逻辑处理:

<!-- Todo.vue -->
<template>
  <div>
    <ul>
      <li v-for="item in todoList" :key="item.id" :class="{ through: item.isChecked }">
        <input type="checkbox" v-model="item.isChecked"> {{ item.task }}
      </li>
    </ul>
  </div>
</template>
<script setup>
import { computed, defineComponent } from 'vue';
import { useStore } from 'vuex';
defineComponent({
  name: 'TodoView'
});
const store = useStore();
const todoList = computed(()=> store.state.todoList)
</script>
<!-- Complete.vue -->
<template>
  <div>
    <ul>
      <li v-for="item in todoList" :key="item.id" :class="{ through: item.isChecked }">
        <input type="checkbox" v-model="item.isChecked"> {{ item.task }}
      </li>
    </ul>
  </div>
</template>
<script setup>
import { computed, defineComponent } from 'vue';
import { useStore } from 'vuex';
defineComponent({
  name: 'CompleteView'
});
const store = useStore();
const todoList = computed(()=> store.getters.complete)
</script>
<!-- Incomplete.vue -->
<template>
  <div>
    <ul>
      <li v-for="item in todoList" :key="item.id" :class="{ through: item.isChecked }">
        <input type="checkbox" v-model="item.isChecked"> {{ item.task }}
      </li>
    </ul>
  </div>
</template>
<script setup>
import { computed, defineComponent } from 'vue';
import { useStore } from 'vuex';
defineComponent({
  name: 'IncompleteView'
});
const store = useStore();
const todoList = computed(()=> store.getters.incomplete)
</script>

搭建 Vite3 + Pinia2 组合模式

前面我们介绍过Vite和Pinia,其中Vite是最新的脚手架,基于原生ESM方式;而Pinia则是最新的状态管理,比Vuex使用起来更加简单。

本小节我们将演示Vite如何去搭配Pinia来完成项目的开发。

首先对Vite3脚手架进行初始化的安装。

  1. 安装脚手架

    # npm 6.x
    npm create vite@latest vite-study
    # yarn
    yarn create vite vite-study
    # pnpm
    pnpm create vite vite-study
    
  2. 选择框架:因为Vite可以和很多框架配合使用,所以这里我们选择:Vite + Vue

    ? Select a framework: » - Use arrow-keys. Return to submit.
        Vanilla
    >   Vue
        React
        Preact
        Lit
        Svelte
    
  3. 选择变体:这里先选择自定义形式

    ? Select a variant: » - Use arrow-keys. Return to submit.
        JavaScript
        TypeScript
    >   Customize with create-vue
        Nuxt
    
  4. 选择安装Pinia

    ? Add Pinia for state management? >> No / Yes
    Yes
    
  5. 进入项目:安装第三方模块,并启动项目

    cd vite-study
    npm install
    npm run dev
    
    VITE v3.1.0  ready in 408 ms
    
      ➜  Local:   http://127.0.0.1:5173/
      ➜  Network: use --host to expose
    

在安装好Vite后,打开/src/stores可以看到自动安装好了一个示例模块counter.js,代码如下:

import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  const doubleCount = computed(() => count.value * 2)
  function increment() {
    setTimeout(()=>{
      count.value++
    }, 2000)
  }
  return { count, doubleCount, increment }
})

这里的风格可以是上一个小节中介绍的配置写法,也可以利用组合式API风格来编程Pinia。这里做了一个共享状态count,又做了一个计算属性doubleCount,还有一个方法increment。

在共享方法中是不分同步还是异步的,对于vue devtools都是可以很好的进行监控的,所以比Vuex使用起来要简单一些。下面看一下共享状态是如何进行渲染和方法调用的。

<!-- App.vue -->
<script setup>
    import { useCounterStore } from './stores/counter';
    import { storeToRefs } from 'pinia';
    const counterStore = useCounterStore();
    const { count, doubleCount } = storeToRefs(counterStore);
    const handleClick = () => {
        counterStore.increment();
    };
</script>
<template>
	<header>
    	<button @click="handleClick">点击</button>
    	{{ count }}, {{ doubleCount }}
    </header>
</template>

Pinia对于模块化的操作方式也比Vuex要简单一些,直接在/stores创建下新创建一个模块JS即可,如:message.js。message.js的代码跟counter.js的代码是一样的格式,使用的时候也是一样的操作行为。

总结内容

  • 了解什么是前端路由,以及Vue3中如何使用vue-router路由
  • 掌握路由的基本操作,如:编程式路由、动态路由、路由守卫等
  • 了解什么是共享状态,以及Vue3中如何使用vuex共享状态
  • 掌握vuex的基本操作,如:同步异步方法、模块化、持久化等
  • 综合应用以及Vuex下一代版本,Pinia存储库

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java入门-包装类

包装类 Java语言是一个面向对象的语言&#xff0c;但是Java中的基本数据类型却是不面向对象的。基本类型的数据不具备"对象"的特性&#xff08;没有属性和方法可以调用&#xff09;&#xff0c;因此&#xff0c;java为每种数据类型分别设计了对应的类&#xff0c;即*…

生成式AI定义全新座舱体验

生成式AI定义全新座舱体验 随着人工智能技术的飞速发展&#xff0c;生成式AI作为其中的佼佼者&#xff0c;正以其独特的魅力重新定义着我们的座舱体验。本文将深入探讨生成式AI的定义、特点及其在座舱体验中的应用&#xff0c;同时分析全新座舱体验的定义、特点&#xff0c;以及…

【LeetCode刷题记录】101. 对称二叉树

101 对称二叉树 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true 示例 2&#xff1a; 输入&#xff1a;root [1,2,2,null,3,null,3] 输出&#xff1a;false 提示&#xf…

三维SDMTSP:GWO灰狼优化算法求解三维单仓库多旅行商问题,可以更改数据集和起点(MATLAB代码)

一、单仓库多旅行商问题 多旅行商问题&#xff08;Multiple Traveling Salesman Problem, MTSP&#xff09;是著名的旅行商问题&#xff08;Traveling Salesman Problem, TSP&#xff09;的延伸&#xff0c;多旅行商问题定义为&#xff1a;给定一个&#x1d45b;座城市的城市集…

4-b12(汉诺塔),要求给出移动过程中每根柱子上现有的圆盘数量及编号

【要求&#xff1a;】 1、假设圆盘最大数量为10&#xff0c;其余输入格式要求同前 2、要求打印初始状态下&#xff0c;起始圆柱拥有的圆盘数及每个圆盘的编号&#xff0c;在随后的每个移动步骤中&#xff0c;打印移动完成后每个圆柱的现有的圆盘数及编号&#xff08;效果如下…

基于SSM的志愿者管理系统(含源码+sql+视频导入教程+文档+PPT)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 基于SSM的志愿者管理系统3拥有三个角色&#xff1a; 管理员&#xff1a;用户管理、志愿组织管理、注册申请观看、活动管理、报名管理、打卡管理、公告管理等 用户&#xff1a;登录注册、…

C语言----函数

1.函数的概念 函数&#xff1a;founction c语言的程序代码都是函数组成的 c语言中的函数就是一个完成某项特定的任务的一段代码&#xff0c;这段代码有特殊的写法和调用方法 c语言中我们一般见到两种函数&#xff1a; .库函数 .自定义函数 2.库函数 有对应的头文件 #i…

咸鱼之王攻略:2024强阵容搭配

欢迎来到《咸鱼之王》的世界&#xff01;作为一款集合了策略与角色扮演元素的游戏&#xff0c;本攻略将为您提供一系列关于游戏阵容搭配和咸将选择的建议&#xff0c;帮助您在游戏中更好地获得胜利。 1.了解游戏阵营 《咸鱼之王》分为四个阵营&#xff1a;魏、蜀、吴、群。每个…

什么是 Web3 的生成式 AI?

从 Web 1.0 的静态、单向通信到 Web 2.0 的动态、用户驱动的格局&#xff0c;互联网在二十年的时间里经历了一场显着的转变。现在&#xff0c;当我们站在 Web 3.0 时代的边缘时&#xff0c;我们正在见证更具颠覆性的事物的曙光&#xff1a;生成式人工智能 (AI) 融入我们的数字世…

anything-llm的嵌入式聊天小部件

anything-llm 详情移步到官方: https://github.com/Mintplex-Labs/anything-llm anything-llm可以docker启动和本地启动 例如&#xff1a;docker 启动&#xff0c; 自行去安装docker哈 cd 到docker文件夹下&#xff0c; 窗口运行&#xff1a; docker-compose up -d --build运…

数据库基础--MySQL简介以及基础MySQL操作

数据库概述 数据库&#xff08;DATABASE&#xff0c;简称DB&#xff09; 定义:是按照数据结构来组织、存储和管理数据的仓库.保存有组织的数据的容器(通常是一个文件或一组文件) 数据库管理系统(Database Management System,简称DBMS) 专门用于管理数据库的计算机系统软件;…

[1671]jsp教材管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 教材管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0&…

IP-guard WebServer 2024年两个漏洞简单分析

前言 这个漏洞看完索然无味&#xff0c;但是手上又刚好有源码&#xff0c;不看他一下又觉得可惜 权限绕过漏洞(QVD-2024-14103)简单分析 网上冲浪的时候&#xff0c;看到个买不起的CSDN专栏 这里基本上定位到是_mApplyList 出了问题&#xff0c;前面两个是ipguard webserve…

Flutter笔记:Widgets Easier组件库(4)使用按钮组

Flutter笔记 Widgets Easier组件库&#xff08;4&#xff09;&#xff1a;使用按钮组 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress…

2024五一数学建模C题保姆级分析完整思路+代码+数据教学

2024五一数学建模竞赛&#xff08;五一赛&#xff09;C题保姆级分析完整思路代码数据教学 煤炭是中国的主要能源和重要的工业原料。然而&#xff0c;随着开采深度的增加&#xff0c;地应力增大&#xff0c;井下煤岩动力灾害风险越来越大&#xff0c;严重影响着煤矿的安全高效开…

机器学习实战 —— 工业蒸汽量预测(二)

目录 文章描述背景描述数据说明数据来源实战内容2.数据特征工程2.1数据预处理和特征处理2.1.1 异常值分析2.1.2 归一化处理2.1.3 特征相关性 2.2 特征降维2.2.1 相关性初筛2.2.2 多重共线性分析2.2.3 PCA处理降维 文章描述 数据分析&#xff1a;查看变量间相关性以及找出关键变…

2024年第二十六届“华东杯”(A题)大学生数学建模挑战赛|数学建模完整代码+建模过程全解全析

当大家面临着复杂的数学建模问题时&#xff0c;你是否曾经感到茫然无措&#xff1f;作为2022年美国大学生数学建模比赛的O奖得主&#xff0c;我为大家提供了一套优秀的解题思路&#xff0c;让你轻松应对各种难题。 让我们来看看华东杯 (A题&#xff09;&#xff01; 问题一&a…

数组模拟双链表-java

通过数组来模拟双链表&#xff0c;并执行一些插入和删除的功能。 目录 一、问题描述 二、模拟思路 1.变量解释 2.数组初始化 3.在下标是k的结点后面插入一个结点 4.删除下标为k的结点 5.基本功能解释 三、代码如下 1.代码如下&#xff1a; 2.读入数据&#xff1a; 3…

VSCode 配置 CMake

VSCode 配置 C/C 环境的详细过程可参考&#xff1a;VSCode 配置 C/C 环境 1 配置C/C编译环境 方案一 如果是在Windows&#xff0c;需要安装 MingW&#xff0c;可以去官网(https://sourceforge.net/projects/mingw-w64/)下载安装包。 注意安装路径不要出现中文。 打开 windows…

【LocalAI】(10):在autodl上编译embeddings.cpp项目,转换bge-base-zh-v1.5模型成ggml格式,本地运行main成功

1&#xff0c;关于 localai LocalAI 是一个用于本地推理的&#xff0c;与 OpenAI API 规范兼容的 REST API。 它允许您在本地使用消费级硬件运行 LLM&#xff08;不仅如此&#xff09;&#xff0c;支持与 ggml 格式兼容的多个模型系列。支持CPU硬件/GPU硬件。 【LocalAI】&…