Vue3+Vite+Pinia+Naive后台管理系统搭建之九:layout 动态路由布局

前言

如果对 vue3 的语法不熟悉的,可以移步Vue3.0 基础入门,快速入门。

1. 系统页面结构

由 menu,面包屑,用户信息,页面标签,页面内容构建

 2. 创建页面

创建 src/pages/layout.vue 布局页

创建 src/pages/components/layout-menu.vue menu 组件

创建 src/pages/components/layout-crumbs.vue 面包屑 组件

创建 src/pages/components/layout-user.vue 用户信息 组件

创建 src/pages/components/layout-tag.vue 页面标签 组件

创建 src/pages/components/layout-content.vue 页面内容 组件

 3. 构建 src/pages/layout.vue 布局页

<script setup>
  import { ref } from "vue";
  import {
    NLayout,
    NLayoutSider,
    NLayoutHeader,
    NLayoutContent,
  } from "naive-ui";
  // menu
  import layoutMenu from "./components/layout-menu.vue";
  // 面包屑
  import layoutCrumbs from "./components/layout-crumbs.vue";
  // 用户信息
  import layoutUser from "./components/layout-user.vue";
  // 页面标签
  import layoutTag from "./components/layout-tag.vue";
  // 页面内容
  import layoutContent from "./components/layout-content.vue";

  // 是否展开menu
  let isOpen = ref(true);
  // n-layout-sider 折叠状态发生改变时的回调函数
  function handleChangeSider(isHide) {
    if (isHide) {
      isOpen.value = !isHide;
    }
  }
  // n-layout-sider 完成展开后的回调
  function handleEnter() {
    isOpen.value = true;
  }

  // n-layout-sider 是否显示边框
  let bordered = ref(true);
  // n-layout-sider 是否反转背景色
  let inverted = ref(false);
  // n-layout-sider 是否在自身使用原生滚动条。如果设定为 false,Sider 将会对内容使用 naive-ui 风格的滚动条
  let scrollbar = ref(false);
  // n-layout-sider 折叠宽度
  let colWidth = ref(50);
  // n-layout-sider 展开宽度
  let siderWidth = ref(155);
</script>

<template>
  <!-- layout 盒子 -->
  <n-layout has-sider class="layout-box">
    <!-- 左侧导航 -->
    <n-layout-sider
      collapse-mode="width"
      show-trigger="arrow-circle"
      :bordered="bordered"
      :inverted="inverted"
      :native-scrollbar="scrollbar"
      :collapsed-width="colWidth"
      :width="siderWidth"
      @update:collapsed="handleChangeSider"
      @after-enter="handleEnter"
    >
      <layout-menu :isOpen="isOpen" :inverted="inverted"></layout-menu>
    </n-layout-sider>
    <!-- 右侧内容 -->
    <n-layout>
      <n-layout-header :bordered="bordered">
        <div class="layout-header__box">
          <layout-crumbs></layout-crumbs>
          <layout-user></layout-user>
        </div>
        <!--  -->
        <layout-tag></layout-tag>
        <div class="layout-header__shadow"></div>
      </n-layout-header>
      <n-layout-content>
        <layout-content></layout-content>
      </n-layout-content>
    </n-layout>
  </n-layout>
</template>

<style lang="scss" scoped>
  .layout-box {
    width: 100vw;
    height: 100vh;
    box-sizing: border-box;
  }
  .layout-header__box {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 20px;
    box-sizing: border-box;
    height: 50px;
    border-bottom: 1px solid rgb(239, 239, 245);
  }
  .layout-header__shadow {
    width: 100%;
    height: 2px;
    background: #d9d9d9;
  }
</style>

4. 构建 src/pages/components/layout-menu.vue menu 组件

<script setup>
  import { ref, watch, computed } from "vue";
  import { useRoute } from "vue-router";
  import { NMenu } from "naive-ui";
  import { usePermissionStore } from "@/store/permission.js";
  import { useTagStore } from "@/store/tag.js";
  import router from "@/router/index.js";

  defineProps({
    isOpen: Boolean,
    inverted: Boolean,
  });

  let route = useRoute();
  let permissionStore = usePermissionStore();
  let tagStore = useTagStore();

  let menuOptions = computed(() => {
    return permissionStore.siderMenu;
  });

  let activeMenuValue = ref("");
  watch(
    () => route.name,
    () => {
      activeMenuValue.value = route.name;
      permissionStore.activeMenuValue = route.name;
    },
    { immediate: true, deep: true }
  );

  // 新增 tag
  let obj = { title: route.meta.title, key: route.name };
  tagStore.addTag(obj);

  let handleUpdateMenu = (value, item) => {
    // 新增 tag
    let { title, key } = item;
    let obj = { title, key };
    tagStore.addTag(obj);

    router.push(`/${value}`);
    activeMenuValue.value = value;
  };
</script>

<template>
  <!-- logo -->
  <div
    class="layout-sider__logo c-center"
    :class="{ isHide: !isOpen }"
    @click="$router.push('/home')"
  >
    <svg-icon name="vite"></svg-icon>
    <!-- <img src="@/assets/images/logo.png" /> -->
    <h1 v-show="isOpen">后台管理系统</h1>
  </div>
  <!-- menu组件 -->
  <n-menu
    :inverted="inverted"
    :indent="15"
    :root-indent="15"
    :options="menuOptions"
    :value="activeMenuValue"
    @update:value="handleUpdateMenu"
  ></n-menu>
</template>

<style lang="scss" scoped>
  .layout-sider__logo {
    height: 50px;
    font-size: 14px;
    font-weight: bold;
    cursor: pointer;
    img {
      margin-right: 5px;
      width: 25px;
      object-fit: contain;
    }
    svg {
      margin-right: 5px;
    }
  }
  .isHide {
    img {
      width: 30px;
    }
  }
</style>

4.1 构建 src/store/permission.js 权限状态管理

根据后端返回动态路由数据,构建导航 menu 和动态路由。

import { defineStore } from "pinia";
import { h } from "vue";
import { RouterLink } from "vue-router";
// 接口获取路由 自己对接口
// import { getRouters } from "@/api/menu.js";
import SvgIcon from "@/components/SvgIcon.vue";
import { routerData } from "@/mock/datas.js";

const modules = import.meta.glob("../pages/*.vue");

//  icon 标签
let renderIcon = (name) => {
  return () => h(SvgIcon, { name }, null);
};

// 单个路由
let getRouterItem = (item) => {
  let { name, path, meta, component } = item;
  let obj = {
    path,
    name,
    meta,
    component: modules[`../pages/${component}`],
  };
  return obj;
};

// 获取异步路由
// 所有异步路由都是layout的子路由,并且routers只有一层children,没有考虑很复杂的情况。
// 将所有异步路由都存放在rmenu数组中,返回。
let getAayncRouter = (routers) => {
  let rmenu = [];
  routers.forEach((item) => {
    if (item.children && item.children.length) {
      item.children.map((_item) => {
        let obj = getRouterItem(_item);
        obj.meta.parentTitle = item.meta.title;
        rmenu.push(obj);
      });
    } else {
      rmenu.push(getRouterItem(item));
    }
  });
  return rmenu;
};

// 获取侧边栏导航
let getSiderMenu = (routers) => {
  let smenu = [];

  routers.forEach((item) => {
    let children = [];
    let obj = {};

    if (item.children && item.children.length) {
      // 二级 menu
      item.children.map((_item) => {
        if (!_item.hidden) {
          children.push({
            label: () =>
              h(
                RouterLink,
                { to: _item.path },
                { default: () => _item.meta.title }
              ),
            title: _item.meta.title,
            key: _item.name,
            icon: renderIcon(_item.meta.icon),
          });
        }
      });

      obj = {
        label: item.meta.title,
        title: item.meta.title,
        key: item.name,
        icon: renderIcon(item.meta.icon),
        children,
      };
    } else {
      // 一级 menu
      obj = {
        label: () =>
          h(RouterLink, { to: item.path }, { default: () => item.meta.title }),
        title: item.meta.title,
        key: item.name,
        icon: renderIcon(item.meta.icon),
      };
    }

    smenu.push(obj);
  });
  return smenu;
};

export const usePermissionStore = defineStore({
  id: "permissionStore",
  state: () => {
    return {
      siderMenu: [],
      activeMenuValue: "",
    };
  },
  actions: {
    getRouters() {
      return new Promise((resolve, reject) => {
        this.siderMenu = getSiderMenu(routerData);
        resolve(getAayncRouter(routerData));
        // getRouters()
        //   .then(({ data }) => {
        //     this.siderMenu = getSiderMenu(data);
        //     resolve(data);
        //   })
        //   .catch((err) => {
        //     reject(err);
        //   });
      });
    },
  },
});

4.1.1 构建 src/mock/datas.js 虚拟路由数据

模仿后端返回动态路由数据结构

export const routerData = [
  {
    name: "home",
    path: "/home",
    hidden: false,
    component: "home.vue",
    meta: {
      title: "首页",
      icon: "home",
    },
    children: null,
  },
  {
    name: "system",
    path: "/system",
    hidden: false,
    component: null,
    meta: {
      title: "系统管理",
      icon: "system",
    },
    children: [
      {
        name: "system-menu",
        path: "/system-menu",
        hidden: false,
        component: "system-menu.vue",
        meta: {
          title: "系统菜单",
          icon: "system-menu",
        },
        children: null,
      },
      {
        name: "system-dict",
        path: "/system-dict",
        hidden: false,
        component: "system-dict.vue",
        meta: {
          title: "系统字典",
          icon: "system-dict",
        },
        children: null,
      },
    ],
  },
  {
    name: "user",
    path: "/user",
    hidden: false,
    component: null,
    meta: {
      title: "用户管理",
      icon: "user",
    },
    children: [
      {
        name: "user-user",
        path: "/user-user",
        hidden: false,
        component: "user-user.vue",
        meta: {
          title: "用户管理",
          icon: "user-user",
        },
        children: null,
      },
      {
        name: "user-role",
        path: "/user-role",
        hidden: false,
        component: "user-role.vue",
        meta: {
          title: "角色管理",
          icon: "user-role",
        },
        children: null,
      },
    ],
  },
];


4.1.2 新增 src/assets/svg 路由图标

 

4.2 构建 src/store/tag.js 页面标签状态管理

点击左侧导航路由,页面标签变化

import { defineStore } from "pinia";

export const useTagStore = defineStore({
  id: "tag",
  state: () => {
    return {
      tags: [{ title: "首页", key: "home" }],
      activeTagIndex: 0,
    };
  },
  getters: {
    tagsKey(state) {
      let arr = [];
      state.tags.map((tag) => {
        arr.push(tag.key);
      });
      return arr;
    },
  },
  actions: {
    addTag(tag) {
      if (!this.tagsKey.includes(tag.key)) {
        this.tags.push(tag);
      }
    },
    removeTag(key) {
      let index = this.tagsKey.indexOf(key);
      this.tags.splice(index, 1);
      this.activeTagIndex = index - 1;
    },
  },
});

4.3 完善 src/router/index.js 路由

路由监听动态加载路由

import { createRouter, createWebHistory } from "vue-router";
import NProgress from "nprogress";
import "nprogress/nprogress.css";
import baseRouters from "./baseRouter.js";
import { getToken } from "@/utils/cookie.js";
import { useUserStore } from "@/store/user.js";
import { usePermissionStore } from "@/store/permission.js";

const whiteList = ["/", "/login"];

const routes = [...baseRouters];
const _createRouter = () =>
  createRouter({
    history: createWebHistory(),
    routes,
    scrollBehavior() {
      return {
        el: "#app",
        top: 0,
        behavior: "smooth",
      };
    },
  });

export function resetRouter() {
  const newRouter = _createRouter();
  router.matcher = newRouter.matcher;
}

const router = _createRouter();

// 路由监听
router.beforeEach((to, from, next) => {
  NProgress.start();
  let userStore = useUserStore();
  let permissionStore = usePermissionStore();

  // 判断是否登录
  if (!!getToken()) {
    // 已登录,跳转登录页,转跳首页
    if (to.path === "/login") {
      next("");
      NProgress.done();
    } else {
      if (userStore.roles.length === 0) {
        userStore
          .getInfo()
          .then((res) => {
            // 获取动态路由
            permissionStore.getRouters().then((_res) => {
              let resetRouters = {
                path: "/layout",
                name: "layout",
                component: () => import("@/pages/layout.vue"),
                children: _res,
              };
              router.addRoute(resetRouters);

              // 这句代码,重要!重要!重要!
              // 来确保addRoute()时动态添加的路由已经被完全加载上去。没有这句,动态路由加载后无效
              next({ ...to, replace: true });
            });
          })
          .catch((err) => {
            window.$msg.error(err);
            userStore.logout().then(() => {
              next({ name: "login" });
            });
          });
      } else {
        next();
      }
    }
    NProgress.done();
  } else {
    // 判断路由是否在白名单,是直接跳转
    if (whiteList.indexOf(to.path) !== -1) {
      next();
      // 未登录页面跳转,直接跳转到登录页
    } else {
      next(`/login?redirect=${to.fullPath}`);
    }
    NProgress.done();
  }
});

export default router;

5. 构建 src/pages/components/layout-crumbs.vue 面包屑组件

<script setup>
  import { watch, ref } from "vue";
  import { NBreadcrumb, NBreadcrumbItem } from "naive-ui";
  import { useRoute } from "vue-router";

  let route = useRoute();

  // 判断是二级目录
  let getCrumList = (nowRoute) => {
    let arr = [nowRoute.meta.title];
    !!nowRoute.meta.parentTitle && arr.unshift(nowRoute.meta.parentTitle);
    return arr;
  };

  let crumbList = ref([]);
  // 监听路由,获取crumlist
  watch(
    () => route,
    (newRoute) => {
      crumbList.value = getCrumList(newRoute);
    },
    { immediate: true, deep: true }
  );
</script>

<template>
  <n-breadcrumb>
    <n-breadcrumb-item
      class="layout-crumbs-item"
      v-for="(item, index) in crumbList"
      :key="index"
      >{{ item }}</n-breadcrumb-item
    >
  </n-breadcrumb>
</template>

<style lang="scss" scoped>
  .layout-crumbs-item {
    font-size: 16px;
  }
</style>

6. 构建 src/pages/components/layout-user.vue 用户信息 组件

<script setup>
  import { reactive, h, computed } from "vue";
  import { useDialog, NDropdown, NButton } from "naive-ui";
  import { useUserStore } from "@/store/user.js";
  import { useTagStore } from "@/store/tag.js";
  import router from "@/router/index.js";

  let userStore = useUserStore();
  let tagStore = useTagStore();

  // 登录才获取用户信息
  userStore.getInfo();
  // 获取 用户信息
  let avatar = computed(() => {
    if (!!userStore.user?.avatar) {
      return userStore.user.avatar;
    } else {
      return "";
    }
  });
  let userName = computed(() => {
    if (!!userStore.user?.userName) {
      return userStore.user.userName;
    } else {
      return "";
    }
  });

  // 下拉选项
  let baseOptions = reactive([
    {
      label: "个人信息",
      key: "userinfo",
    },
    {
      label: "修改密码",
      key: "editpassword",
    },
    {
      label: "退出系统",
      key: "logout",
    },
  ]);

  // 选择操作
  let dialog = useDialog();
  // 确认登出
  let submitLogout = () => {
    userStore.logout().then(() => {
      router.push("/home");
      dialog.destroyAll();
      window.location.reload();
    });
  };
  // 取消登出
  let cancelLogOut = () => {
    dialog.destroyAll();
  };
  let handleSelect = (key, item) => {
    if (["userinfo", "editpassword"].includes(key)) {
      // 新增 tag
      let obj = { title: item.label, key };
      tagStore.addTag(obj);

      router.push(`/${key}`);
    } else {
      dialog.warning({
        closable: false,
        showIcon: false,
        style: {
          width: "20%",
        },
        title: () => {
          return h(
            "div",
            {
              style: {
                position: "absolute",
                top: 0,
                left: 0,
                right: 0,
                textAlign: "center",
                height: "40px",
                lineHeight: "40px",
                background: "#cee6f0",
                color: "#1d69a3",
                fontWeight: "bold",
                fontSize: "16px",
              },
            },
            "退出登录"
          );
        },
        content: () => {
          return h(
            "p",
            {
              style: {
                textAlign: "center",
                height: "80px",
                lineHeight: "108px",
                color: "#000",
                fontSize: "14px",
                fontWeight: "bolder",
                userSelect: "none",
              },
            },
            "是否退出当前账号?"
          );
        },
        action: () => {
          return h(
            "div",
            {
              style: {
                width: "100%",
                display: "flex",
                justifyContent: "space-around",
              },
            },
            [
              h(
                NButton,
                {
                  onClick: cancelLogOut,
                  style: {
                    width: "40%",
                  },
                },
                {
                  default: () => "取消",
                }
              ),
              h(
                NButton,
                {
                  onClick: submitLogout,
                  type: "info",
                  style: {
                    width: "40%",
                  },
                },
                {
                  default: () => "退出",
                }
              ),
            ]
          );
        },
      });
    }
  };
</script>

<template>
  <n-dropdown
    trigger="click"
    :options="baseOptions"
    @select="handleSelect"
    size="small"
  >
    <div class="header-right_user-box">
      <div class="header-right_user-avatar">
        <img v-if="avatar" class="header-right_avatar" :src="avatar" />
        <svg-icon v-else name="avatar" width="35" height="35"></svg-icon>
      </div>
      <div class="header-right_user-name">
        <span>{{ userName }}</span>
        <svg-icon name="down" width="10"></svg-icon>
      </div>
    </div>
  </n-dropdown>
</template>

<style lang="scss" scoped>
  .header-right_user-box {
    display: flex;
    align-items: center;
    cursor: pointer;
    user-select: none;
  }
  .header-right_user-avatar {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: 10px;
    overflow: hidden;

    img {
      width: 100%;
      height: 100%;
      object-fit: contain;
    }
  }
  .header-right_user-name {
    span {
      margin: 0 5px;
    }
  }
</style>

7. 构建 src/pages/components/layout-tag.vue 页面标签 组件

<script setup>
  import { computed } from "vue";
  import { NTag } from "naive-ui";
  import { useTagStore } from "@/store/tag.js";
  import { usePermissionStore } from "@/store/permission.js";
  import router from "@/router/index.js";

  let tagStore = useTagStore();
  let permissionStore = usePermissionStore();

  let tags = computed(() => {
    return tagStore.tags;
  });

  function handleClose(key) {
    tagStore.removeTag(key);

    if (permissionStore.activeMenuValue == key) {
      permissionStore.activeMenuValue = tags.value[tagStore.activeTagIndex].key;
      router.push(`/${permissionStore.activeMenuValue}`);
    }
  }
  function handleCheck(item) {
    let { key } = item;
    permissionStore.activeMenuValue = key;
    router.push(`/${key}`);
  }
</script>

<template>
  <div class="layout-header__tag">
    <n-tag
      v-for="item in tags"
      :key="item.key"
      class="tag-item"
      :closable="item.key !== 'home'"
      :type="item.key == permissionStore.activeMenuValue ? 'success' : ''"
      size="small"
      @close="handleClose(item.key)"
      @click="handleCheck(item)"
      >{{ item.title }}</n-tag
    >
  </div>
</template>

<style lang="scss" scoped>
  .layout-header__tag {
    padding-left: 10px;
    display: flex;
    align-items: center;
    height: 30px;
  }
  .tag-item {
    margin-right: 5px;
    cursor: pointer;
  }
</style>

8. 构建 src/pages/components/layout-content.vue 页面内容 组件

<script setup></script>

<template>
  <div class="layout-content">
    <router-view v-slot="{ Component, route }">
      <transition name="mainFade" mode="out-in">
        <component :is="Component" :key="route.path"></component>
      </transition>
    </router-view>
  </div>
</template>

<style lang="scss" scoped>
  .layout-content {
    padding: 20px;
    margin: 20px;
    // height: auto;
    height: calc(100vh - 170px);
    border: 1px solid #e9e9e9;
    border-radius: 5px;
    -webkit-box-shadow: rgba(0, 0, 0, 0.047) 0 0 5px;
    box-shadow: 0 0 5px rgba(0, 0, 0, 0.047);
  }
  .mainFade-enter-from {
    transform: translate(-80px);
    opacity: 0;
  }

  .mainFade-leave-to {
    transform: translate(80px);
    opacity: 0;
  }

  .mainFade-leave-from,
  .mainFade-enter-to {
    transform: translate(0px);
    opacity: 1;
  }

  .mainFade-enter-active {
    transition: all 0.1s ease;
  }

  .mainFade-leave-active {
    transition: all 0.1s cubic-bezier(1, 0.6, 0.6, 1);
  }
</style>

9. 创建如下内容页

src/pages/404.vue

src/pages/demo.vue

src/pages/eidtpassword.vue

src/pages/userinfo.vue

src/pages/system-dict.vue

src/pages/system-menu.vue

src/pages/user-user.vue

src/pages/user-role.vue

 页面基础构建如 demo.vue

<script setup></script>

<template>
  <div class="demo">demo</div>
</template>

<style lang="scss" scoped></style>

 综上

layout 动态路由布局构建完成。下一章:基础框架搭建完了,后续完善到哪更新哪

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

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

相关文章

python 封装sql 增删改查连接MySQL

select * from Teacher limit 10 连接字符串配置MysqlConfig.py class MysqlConfig:HOST 192.168.56.210PORT 3306USER rootPASSWORD 1qaz0987654321DBStudentDBCHARSET utf8封装增删改查MysqlConnection.py Author: tkhywang 2810248865qq.com Date: 2023-06-19 15:44:48 Las…

VMware Workstation及CentOS-7虚机安装

创建新的虚机&#xff1a; 选择安装软件&#xff08;这里选的是桌面版&#xff0c;也可以根据实际情况进行选择&#xff09; 等待检查软件依赖关系 选择安装位置&#xff0c;自主配置分区 ​​​​​​​ 创建一个普通用户 安装完成后重启 点击完成配置&#xff0c;进入登陆界面…

Vue3 列表渲染简单应用

去官网学习→列表渲染 | Vue.js 运行示例&#xff1a; 代码&#xff1a;HelloWorld.vue <template><div class"hello"><h1>Vue 列表渲染</h1><p v-for"item in dataList">{{item}}</p><p v-for"(item,index)…

ros tf

欢迎访问我的博客首页。 tf 1. tf 命令行工具1.1 发布 tf1.2 查看 tf 2.参考 1. tf 命令行工具 1.1 发布 tf 我们根据 cartographer_ros 的 launch 文件 backpack_2d.launch 写一个 tf.launch&#xff0c;并使用命令 roslaunch cartographer_ros tf.launch 启动。该 launch 文件…

认识所有权

专栏简介&#xff1a;本专栏作为Rust语言的入门级的文章&#xff0c;目的是为了分享关于Rust语言的编程技巧和知识。对于Rust语言&#xff0c;虽然历史没有C、和python历史悠远&#xff0c;但是它的优点可以说是非常的多&#xff0c;既继承了C运行速度&#xff0c;还拥有了Java…

zookeeper的部署

一 先下载zookeeper 二 解压包 三 修改配置文件 四 把配好文件传到其他的节点上面 五 在每个节点的dataDir指定的目录下创建一个 myid 的文件 六 配置zook的启动脚本 七 设置开机自启 八 分别启动 九查看当前状态service zookeeper status 十 总结 一 先下载zookeeper …

Vue常见的事件修饰符

1.prevent:阻止默认事件(常用) 2. stop:阻止事件冒泡(常用) 3. once:事件只触发一次(常用) 4.captrue:使用事件的捕捉模式(不常用) 5.self:只有event.target是当前操作的元素时才触发事件(不常用) 6.passive:事件的默认行为立即执行&#xff0c;无需等待事件回调执行完毕(不常用…

网关 GateWay 的使用详解、路由、过滤器、跨域配置

一、网关的基本概念 SpringCloudGateway网关是所有微服务的统一入口。 1.1 它的主要作用是&#xff1a; 反向代理&#xff08;请求的转发&#xff09; 路由和负载均衡 身份认证和权限控制 对请求限流 1.2 相比于Zuul的优势&#xff1a; SpringCloudGateway基于Spring5中…

Go微服务实践 - Rpc核心概念理解

概述 从0研究一下Golang已经Golang的微服务生态体系&#xff0c;Golang的微服务首先要从Rpc开始&#xff0c;在升级到Grpc&#xff0c;详细介绍这些技术点都在解决什么技术问题。 Rpc Rpc (Remote Procedure Call) 远程过程调用&#xff0c;简单的理解是一个节点请求另一个节…

集成学习算法是什么?如何理解集成学习?

什么是集成学习&#xff1f; 集成学习通过建立几个模型来解决单一预测问题。它的工作原理是生成多个分类器/模型&#xff0c;各自独立地学习和作出预测。这些预测最后结合成组合预测&#xff0c;因此优于任何一个单分类的做出预测。 机器学习的两个核心任务 任务一&#xff1…

【JavaEE】Spring Boot - 日志文件

【JavaEE】Spring Boot 开发要点总结&#xff08;3&#xff09; 文章目录 【JavaEE】Spring Boot 开发要点总结&#xff08;3&#xff09;1. 日志有什么作用2. 日志格式2.1 日志框架原理 3. 日志的打印3.1 System.out.println3.2 使用日志框架3.3 日志级别3.3.1 设置默认日志显…

自监督去噪:Noise2Self原理分析及实现 (Pytorch)

文章地址:https://arxiv.org/abs/1901.11365 代码地址: https://github.com/czbiohub-sf/noise2self 要点   Noise2Self方法不需要信号先验信息、噪声估计信息和干净的训练数据。唯一的假设就是噪声在测量的不同维度上表现出的统计独立性&#xff0c;而真实信号表现出一定的…

Vue Router 的query和params的区别?

区别一&#xff1a; &#xff08;1&#xff09;query相当于get请求&#xff0c;页面跳转的时候可以在地址栏看到请求参数 &#xff08;2&#xff09;params相当于post请求&#xff0c;参数不会在地址栏中显示&#xff0c;所以用params传值相对安全 &#xff08;简记&#xff1…

C++ | C++11新特性(上)

目录 前言 一、列表初始化 二、声明 1、auto 2、decltype 3、nullptr 三、STL容器的变化 四、右值引用与移动语义 1、左值与左值引用 2、右值与右值引用 3、右值引用与左值引用的比较 4、右值引用的场景及意义 &#xff08;1&#xff09;做参数 &#xff08;2&a…

Python连接Hive实例教程

一 Python连接hive环境实例 经在网络查询相关的教程&#xff0c;发现有好多的例子&#xff0c;发现连接底层用的的驱动基本都是pyhive和pyhs2两种第三方库的来连接的 hive,下面将简介windows 10 python 3.10 连接hive的驱动程序方式&#xff0c;开发工具&#xff1a;pycharm …

layui之layer弹出层的icon数字及效果展示

layer的icon样式 icon如果在信息提示弹出层值(type为0)可以传入0-6&#xff0c;icon与图标对应关系如下&#xff1a; 如果是加载层&#xff08;type为3&#xff09;可以传入0-2&#xff0c;icon与图标对应关系如下&#xff1a;

基于fpga的电子时钟

文章目录 前言实验手册一、实验目的二、实验原理1&#xff0e;理论原理2&#xff0e;硬件原理 三、系统架构设计四、模块说明1&#xff0e;模块端口信号列表按键消抖模块&#xff08;key&#xff09;计数器模块&#xff08;counter&#xff09;蜂鸣器乐谱模块(music)蜂鸣器发声…

有没有好用的在线画图工具推荐?

绘画是设计师最常见的工作之一&#xff0c;设计师对在线绘画工具的要求越来越高&#xff0c;市场上也出现了各种在线绘画工具&#xff0c;让设计师不知道如何选择高质量的在线绘画工具&#xff0c;一个好的在线绘画工具不仅可以让你轻松绘画&#xff0c;而且可以让你的工作效率…

可视化高级绘图技巧100篇-总论

前言 优秀的数据可视化作品可以用三个关键词概括&#xff1a;准确、清晰、优雅。 准确&#xff1a;精准地反馈数据的特征信息&#xff08;既不遗漏也不冗余&#xff0c;不造成读者疏漏&误读细节&#xff09; 清晰&#xff1a;获取图表特征信息的时间越短越好 优雅&…

【ARM64 常见汇编指令学习 13 -- ARM 汇编 ORG 伪指令学习】

文章目录 ARM ORG 指令介绍UEFI 中对 ORG 指令的使用 ARM ORG 指令介绍 在ARM汇编中&#xff0c;"org"是一个汇编器伪指令&#xff0c;用于设置下一条指令的装入地址。"org"后面跟着的是一个表达式&#xff0c;这个表达式的值就是下一条指令的装入地址。如…