微前端——无界wujie

B站课程视频
课程视频

课程课件笔记:
1.微前端

2.无界

现有的微前端框架:iframe、qiankun、Micro-app(京东)、EMP(百度)、无届

前置

初始化

新建一个文件夹
1.通过npm i typescript -g安装ts
2.然后可以使用tsc --init初始化项目,这样项目目录下会有tsconfig.json配置文件
3.再新建index.ts
4.使用tsc -w命令可以实时的编译index.ts出一个index.js文件
5.通过index.html引入index.js即可

<!DOCTYPE html>
<html lang="en">
<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>Document</title>
  <script src="./index.js"></script>
</head>
<body>
</body>
</html>

webComponents初使用

主要是为了样式隔离

wu-jie初体验

index.ts文件中书写

// webComponents 的写法
window.onload = () => {
  // 初始化
  class Wujie extends HTMLElement {
    // 类的基本用法
    constructor() {
      super()

      // this.attachShadow创建shadowdom并打开就具有样式隔离的性质,不会影响外层的样式
      let dom = this.attachShadow({mode: 'open'})
      // 获取template
      let template = document.querySelector('#wujie') as HTMLTemplateElement
      // 并绑定,这里是把template的内容深度克隆一份给dom,而不是直接给,true表示深度克隆
      dom.appendChild(template.content.cloneNode(true))
      // 这样就把template的内容渲染到了<wu-jie></wu-jie>的组件里面
      
      console.log(this.getAttr('url'), this.getAttr('age'))
    }

    // 获取传参this.getAttribute 传入属性名即可
    private getAttr(attr: string) {
      return this.getAttribute(attr)
    }
  }
  // webComponents挂载,注意名字不能启成驼峰的但是-横线连接可以,第二个参数是上面类的名字
  // 类似vue组件  原生js写的一个组件 可以在html中使用了<wu-jie></wu-jie>
  window.customElements.define('wu-jie', Wujie)
}

在上述建立的index.html中书写

<body>
  <!-- 相当于组件,也可以传参 -->
  <wu-jie url='xxxxx' age='18'></wu-jie>
  <div>我是外层的div</div>

  <template id="wujie">
    <div>我是 template 里面的div</div>
    <style>
      div{
        background: red;
      }
    </style>
  </template>
</body>

无届的三个生命周期

//生命周期自动触发有东西插入
connectedCallback () {
  console.log('类似于vue 的mounted');
}
//生命周期卸载
disconnectedCallback () {
      console.log('类似于vue 的destory');
}
//跟watch类似
attributeChangedCallback (name:any, oldVal:any, newVal:any) {
    console.log('跟vue 的watch类似,有属性发生变化自动触发');
}

pnpm介绍

1.全局安装npm i pnpm -g
2.使用 pnpm -v可以查看版本号
3.pnpmnpm的优势,在pnpm中文网的动机这样写pnpm官网
在这里插入图片描述
简单来说就是,但有100个vue项目,每个项目都会去安装相应的依赖包,这样导致磁盘的缩小和安装速度慢(每次都会重新下载依赖包),很麻烦。
但是pnpm使用软链接硬链接仓库解决

硬链接

1.使用cmd查看提示,表示 /H就是硬链接
在这里插入图片描述

2.创建命令含义 mklink /H 硬链接的名字 通过谁创建
例如:在pnpm文件目录下建立index.js文件,并通过mklink /H ying.js index.js创建了硬链接
在这里插入图片描述
3.并且目录下多出了一个ying.js
在这里插入图片描述

4.然后打开文件发现ying.js中内容和index.js中一样
在这里插入图片描述
5.而且当修改index.js中的内容时,ying.js中的内容会跟着修改,因为他们共享的同一个磁盘地址

软链接(符号链接)

1.创建软链接需要管理员权限,所以管理员打开cmd后进入目录可以使用cd ../../等回退到根目录下,然后直接 D: 进入相应盘,再cd命令
2.默认就是软链接 mklink ruan.js index.js 即可,不用加任何修饰符
在这里插入图片描述
3.成功创建后VScode中会有一个标志
在这里插入图片描述
4.且文件管理器中查看也是一个0字节的,因为他只记录一个路径(快捷方式,并不会占用资源),点击会跳转,指向的还是index.js
在这里插入图片描述

pnpm如何利用硬链接、软链接解决上述问题

1.使用pnpm init命令创建package.json
2.以安装vue包为例,使用pnpm i vue 安装vue依赖,可以看到node_modules下面有vue的软链接(快捷方式,地址指向)
在这里插入图片描述
3.实际上上述软链接指向在.pnpm包下找到真正的vue@3.3.13的包下面的vue文件夹,这个vue硬链接指向.pnpm store
在这里插入图片描述
4.实际上就对应了pnpm官网的这张图,非扁平化的方式(可能嵌入,因为这个库可能还依赖其他库,这样依次来)
在这里插入图片描述

绿色黄色实线为软链接、红色虚线为硬链接
在这里插入图片描述

pnpm的CLI命令管理

假设你之前使用的npm 安装包,会生成一个package-lock.json,或者使用yarn安装过,会生成一个yarn.lock

但是你再通过pnpm import命令 他会把你的上述的软件包管理器的 lockfile 生成 pnpm-lock.yaml文件

monorepo项目

创建monorepo项目目录

1.使用命令npm init vue创建vue项目,并创建项目名为main
2.创建web文件目录存放子应用
3.创建vue子应用,使用npm init vite选择vue+typescript
4.创建react子应用,使用npm init vite选择react+typescript
5.在web文件夹下有多个子应用,分别安装有点繁琐,所以在monorepo文件夹下使用命令pnpm init生成文件,并手动创建pnpm-workspace.yaml文件和配置。配置

官网是:
packages:
  # all packages in direct subdirs of packages/
  - 'packages/*'
  # all packages in subdirs of components/
  - 'components/**'
  # exclude packages that are inside test directories
  - '!**/test/**'

替换为自己的目录
packages:
  # all packages in direct subdirs of packages/
  - 'main/*'
  # all packages in subdirs of components/
  - 'web/**'

此时目录如下:
在这里插入图片描述
6.替换好pnpm-workspace.yaml之后可以在根目录直接pnpm i即可自动为所有的项目安装包
最外层根目录下的node_modules是所有项目公共的包,而vue项目或者react项目里面的node_modules是他们单独所需要的,这样结构更加清晰。
在这里插入图片描述

子项目启动:

假设这时候我们要跨级执行命令,想要执行react-demo项目中package.jsondev命令,可以使用pnpm -F react-demo dev,其中F是过滤filter

子模块复用:

1.新建目录common下,并进入,想要common目录下的东西其余子项目(vue、react等都可以使用)
2.使用pnpm init初始化生成package.json文件。在pnpm-workspace.yaml中写

packages:
  # all packages in direct subdirs of packages/
  - 'main/*'
  # all packages in subdirs of components/
  - 'web/**'
  - 'common'

3.安装axios包了pnpm i axios
在这里插入图片描述
3.新建index.ts,编写一些公共代码

import axios from 'axios'

// 公共的提取出来
export const a = axios.get('xxx')

4.进入main目录使用命令pnpm -F main add common则把common添加进main项目的依赖中,查看main/package.json文件里面有
在这里插入图片描述
5.然后就可以在main/src/main.ts中引入

import { a } from 'common'

6.同理,也可以去给react-demo项目添加或者vue-demo添加:pnpm -F vue-demo add common,一样查看那个package.json有common包,然后可以导入进行使用

无届

安装

1.使用pnpm i wujie,在main.ts中引入wujie并配置启动的参数

import { startApp } from 'node_modules/wujie/esm/index'
// 启动的参数
startApp({name, url, el})

2.如果是vue项目,可以直接安装npm i wujie-vue3进行安装

import Wujie from 'wujie-vue3'
app.use(router).use(Wujie)

3.然后分别启动好子应用,记录端口就可以在App.vue中使用了

<template>
  <div>
    <h1>这是主应用</h1>
    <!-- 分别是子应用,子应用启动之后各自的端口 -->
    <WujieVue url="http://127.0.0.1:5174" name="vue3"></WujieVue>
    <WujieVue url="http://127.0.0.1:5175" name="react"></WujieVue>
  </div>
</template>

在main.ts中,全部代码如下:

import './assets/main.css'

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import Wujie from 'wujie-vue3' // 引入一下对应的框架
import { preloadApp } from 'wujie'

const app = createApp(App)

app.use(router).use(Wujie) // 注册无界
app.mount('#app')

// exac预加载为true即可,那么components/react.vue和vue3.vue就会有url
preloadApp({ name: "vue3", url: "http://127.0.0.1:5173", exec: true})
preloadApp({ name: "react", url: "http://127.0.0.1:5174", exec: true})

封装无届

1.创建的目录

封装无届

1.创建的目录文件如下:
其中使用pnpm init创建package.json
使用tsc --init创建 tsconfig.json
在这里插入图片描述
2.使用pnpm i wujie安装无届
3.使用pnpm i vue -D把vue装在开发环境中
4.安装webpack,使用pnpm i webpack webpack-cli -D
5.安装typescript,使用 pnpm i typescript -D
6.安装typescript解析器,使用pnpm i ts-loader -D

书写相关配置代码

配置代码部分可以看源码参照下面的代码

写完后使用 npm run lib 打包

1.在env.d.ts中书写

import { defineComponent, h, getCurrentInstance, onMounted, watch, onBeforeUnmount } from 'vue'
import type { App, PropType } from 'vue'
import { Props } from './type'
import { startApp, bus } from 'wujie'

// 函数式定义组件
const wujie = defineComponent({
  props: {
    width: { type: String, default: "" },
    height: { type: String, default: "" },
    name: { type: String, default: "", required: true },
    loading: { type: HTMLElement, default: undefined },
    url: { type: String, default: "", required: true },
    sync: { type: Boolean, default: undefined },
    prefix: { type: Object, default: undefined },
    alive: { type: Boolean, default: undefined },
    props: { type: Object, default: undefined },
    attrs: { type: Object, default: undefined },
    replace: { type: Function as PropType<Props['replace']>, default: undefined },
    fetch: { type: Function as PropType<Props['fetch']>, default: undefined },
    fiber: { type: Boolean, default: undefined },
    degrade: { type: Boolean, default: undefined },
    plugins: { type: Array as PropType<Props['plugins']>, default: null },
    beforeLoad: { type: Function as PropType<Props['beforeLoad']>, default: null },
    beforeMount: { type: Function as PropType<Props['beforeMount']>, default: null },
    afterMount: { type: Function as PropType<Props['afterMount']>, default: null },
    beforeUnmount: { type: Function as PropType<Props['beforeUnmount']>, default: null },
    afterUnmount: { type: Function as PropType<Props['afterUnmount']>, default: null },
    activated: { type: Function as PropType<Props['activated']>, default: null },
    deactivated: { type: Function as PropType<Props['deactivated']>, default: null },
  },
  setup(props, { emit }) {
    // 读取当前组件实例
    // this.$refs.wujie // 在vue2中可以通过this获取当前组件实例
    const instance = getCurrentInstance() // vue3中通过getCurrentInstance获取组件实例

    // 封装启动函数
    const init = () => {
      // startApp({name, url, el})
      //初始化无界
      startApp({
        name: props.name,
        url: props.url,
        el: instance?.refs.wujie as HTMLElement,
        loading: props.loading,
        alive: props.alive,
        fetch: props.fetch,
        props: props.props,
        attrs: props.attrs,
        replace: props.replace,
        sync: props.sync,
        prefix: props.prefix,
        fiber: props.fiber,
        degrade: props.degrade,
        plugins: props.plugins,
        beforeLoad: props.beforeLoad,
        beforeMount: props.beforeMount,
        afterMount: props.afterMount,
        beforeUnmount: props.beforeUnmount,
        afterUnmount: props.afterUnmount,
        activated: props.activated,
        deactivated: props.deactivated,
      })
    }
    watch([props.name, props.url], () => {
      init() // 如果发生变化就重新执行startApp
    })

    const handlerEmit = (event:string, ...args:any[]) => {
      emit(event, ...args)
    }

    onMounted(() => {
      // 发布订阅模式
      bus.$onAll(handlerEmit) 
      init()
    })

    onBeforeUnmount(() => {
      bus.$offAll(handlerEmit)
    })

    // 定义渲染函数
    return ()=> h('div', {
      style: {
        width: props.width,
        height: props.height
      },
      ref: "wujie" // 方便之后读取
    })
  }
})
// install 方法给vue使用的,app.use(router).use(wujie)会调用install
wujie.install = function(app: App) {
  app.component('WujieVue', wujie)
}

export default wujie

2.type.ts中写

import type { plugin } from 'wujie'
type lifecycle = (appWindow: Window) => any;
interface Props {
    /** 唯一性用户必须保证 */
    name: string;
    /** 需要渲染的url */
    url: string;
    /** 需要渲染的html, 如果用户已有则无需从url请求 */
    html?: string;
    /** 渲染的容器 */
    loading?: HTMLElement;
    /** 路由同步开关, false刷新无效,但是前进后退依然有效 */
    sync?: boolean;
    /** 子应用短路径替换,路由同步时生效 */
    prefix?: { [key: string]: string };
    /** 子应用保活模式,state不会丢失 */
    alive?: boolean;
    /** 注入给子应用的数据 */
    props?: { [key: string]: any };
    /** js采用fiber模式执行 */
    fiber?: boolean;
    /** 子应用采用降级iframe方案 */
    degrade?: boolean;
    /** 自定义运行iframe的属性 */
    attrs?: { [key: string]: any };
    /** 自定义降级渲染iframe的属性 */
    degradeAttrs?: { [key: string]: any };
    /** 代码替换钩子 */
    replace?: (codeText: string) => string;
    /** 自定义fetch,资源和接口 */
    fetch?: (input: RequestInfo, init?: RequestInit) => Promise<Response>;
    /** 子应插件 */
    plugins: Array<plugin>;
    /** 子应用生命周期 */
    beforeLoad?: lifecycle;
    /** 没有做生命周期改造的子应用不会调用 */
    beforeMount?: lifecycle;
    afterMount?: lifecycle;
    beforeUnmount?: lifecycle;
    afterUnmount?: lifecycle;
    /** 非保活应用不会调用 */
    activated?: lifecycle;
    deactivated?: lifecycle;
};

export { Props } 

3.webpack.config.js中写

const { Configuration } = require('webpack')
const path = require('path')

/**
 * @type {Configuration} //配置智能提示
 */

const config = {
  entry: "./src/index.ts", // 入口文件
  mode: "none",
  output: {
    filename: "index.js",
    path: path.resolve(__dirname, 'lib')
  },
  externals: { // 防止打包后的代码包含wujie和vue代码显得过多
    vue: "vue",
    wujie: "wujie"
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: "ts-loader"
      }
    ]
  }

}

module.exports = config

SWC和babel

SWC官网
1.swc比babel快20倍,如果是4核情况下,快70倍
使用pnpm add -D @swc/score swc-loader安装命令

2.然后替换webpack.config.js中的use

module: {
    rules: [
      {
        test: /\.ts$/,
        use: "ts-loader" // babel的ts-loader,换成swc-loader
      }
    ]
  }

3.因为swc底层是rust写的,rust性能是js的好几倍所很快

4.然后再打包npm run lib打包后还不能直接使用,
因为前端有很多代码规范,AMD, CMD,CommonJS,ESModule,所以统一配置一个UMD,
5.安装pnpm i -D @swc/cli @swc/core以便使用swc-cli
6.新建配置文件.swcrc

{
  "$schema": "https://json.schemastore.org/swcrc",
  "jsc": {
  "parser": {
  "syntax": "typescript", // js是ecmascript
  // "jsx": false,
  // "dynamicImport": false,
  // "privateMethod": false,
  // "functionBind": false,
  // "exportDefaultFrom": false,
  // "exportNamespaceFrom": false,
  // "decorators": false,
  // "decoratorsBeforeExport": false,
  // "topLevelAwait": false,
  // "importMeta": false
  },
  // "transform": null,
  "target": "es5",
  "loose": false,
  "externalHelpers": false,
  // Requires v1.2.50 or upper and requires target to be es2016 or upper.
  "keepClassNames": false
  },
  "minify": false
 }

7.在根目录的package.json的 scripts中编写打包命令写"esm": "swc src/index.ts -d esm",
8.控制台执行 npm run swc即可打包在esm文件中
9.修改增添package.json中
设定一些版本号和启动的入口

"name": "vuejie-setup",
"version": "0.0.1",
 "main": "lib/index.js", 
"module": "esm/index.js",

添加files

"files": [
    "lib",
    "esm",
    "index.d.ts"
  ],

10.在根目录下的index.d.ts声明文件中写

// import { bus, preloadApp, destroyApp, setupApp } from "wujie";
import type { App } from 'vue';

declare const WujieVue: {
    // bus: typeof bus;
    // setupApp: typeof setupApp;
    // preloadApp: typeof preloadApp;
    // destroyApp: typeof destroyApp;
    install: (app: App) => void
};

export default WujieVue;

发布包

1.切换镜像 mmp use,输入 npm
2.使用 npm adduser命令,然后输入npm的用户名
在这里插入图片描述
3.使用npm login
4.使用 npm publish发布

使用

1.在MONOREPO项目中切换进主应用cd main
2.命令安装pnpm i vuejie-setup
3.在main.ts中引入import Wujie from 'vuejie-setup'
4.使用npm run dev启动各种主应用或者子应用查看效果

无届的预加载和FPS

1.requestldleCallback函数
MDN的解释
在这里插入图片描述

2.FPS扩展
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

无届的传参

总共三种方法

第一种方法

无届的架构是把JS单独存放在了iframe中,那么iframe可以通过window和父级进行通讯,所以第一种传参就是通过
window.parent.变量名 进行读取。

1.在vue-demo/App.vue中添加按钮,绑定函数获取a

<script setup lang="ts">
const send = () => {
  alert(window.parent.a) //
}
</script>
<button @click="send">点击</button>

2.在控制台输入变量 var a = '控制台的输入'
3.点击按钮,发现可以弹出
在这里插入图片描述

在这里插入图片描述

第二种方法

通过props 传参,子应用不需要绑定无界,主应用接进来之后会自动捕获vue实例,所以子应用可以访问到无界实例对象获取参数

1.例如在主应用的components/App.vue组件中挂载数据,通过props传参

<template>
  <WujieVue :props="{name: '张三', age: '18'}" url="http://127.0.0.1:5173" name="vue3"></WujieVue>
</template>

2.然后在vue-demo子项目中的App.vue中写JS代码

const send = () => {
  // alert(window.parent.a) // 第一种方法
  console.log(window.$wujie) // 第二种方式
}

3.为了防止上述$wujie报错,可以在main.ts中添加

declare global {
  interface Window {
    $wujie: {
      props:  Record<string, any>
      bus: {
        $emit: any
      }
    }
  }
}

4.打印的结果如下(可以看到还有bus,第三种方法获取)
在这里插入图片描述
4.上述可以访问props console.log(window.$wujie)进行打印

d第三种方案eventBus发布订阅

可以双向数据传递,直接使用wujie的bus.$on
1.在 主应用的App.vue中通过bus.$on绑定数据

<script lang="ts">
import { bus } from 'wujie'
bus.$on('vue3', (data: any) => {
  console.log(data, '我是主应用的bus.$on')
})
</script>

2.在子应用vue-demo的App.vue中通过实例直接使用

const send = () => {
  // alert(window.parent.a)
  // console.log(window.$wujie.props) // 获取到App.vue下的props
  window.$wujie.bus.$emit('vue3', '我是子应用vuedemo')
}

模块联邦

1.创建文件如下,目录
在这里插入图片描述

2.安装下面四个依赖包
npm i webpack webpack-cli webpack-server html-webpack-plugin -D
在这里插入图片描述
3.书写代码,略,结果如下,总之host里面没有的List数据却通过引入到了remote的数据进行展示
在这里插入图片描述
在这里插入图片描述
4.pnpm run build进行打包host项目下
点开dist/bundle.js,可以看到使用CDN的方式进行引入的
在这里插入图片描述
之前:10个项目引用同一个模块,通过把这个项目发布到npm上面,然后这是个项目可以install这个模块,但是当这个模块发生改变的时候,例如从1.0.0 -> 1.0.1,那么这十个项目得重新下载install一遍
现在的CDN,当你的模块修改了,直接就是最新的版本,通过这个链接,远程调用联邦的技术正是用的这种

报错

1.在tsconfig.app.json中报错:没有 “node” 模块解析策略的情况下,无法指定选项 “-resolveJsonModule”。

修改tsconfig.app.json 文件中 compilerOptions 选项配置 “moduleResolution”: “node”

{
  "extends": "@vue/tsconfig/tsconfig.dom.json",
  "include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
  "exclude": ["src/**/__tests__/*"],
  "compilerOptions": {
    "composite": true,
    /*
     * 模块解析策略,ts默认用node的解析策略,即相对的方式导入, 可选值:node、classic
     * 如果未指定,则 --module commonjs 默认为 node,否则默认为 classic(包括 --module 设置为 amd、system、umd、es2015、esnext 等)
     * Node 模块解析是 TypeScript 社区中最常用的,推荐用于大多数项目。 
     * 如果您在 TypeScript 中遇到导入和导出的解析问题,请尝试设置 moduleResolution: “node” 以查看它是否解决了问题。
     */
    "moduleResolution": "node",    
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}

参考自

一些文件爆红

1.找不到模块“./App.vue”或其相应的类型声明
2.ts.config.app.json找不到文件vue tsconfig tsconfig dom json

如果报错vite找不到之类的,以及奇怪的错误请删除两个子应用重新建立和安装和初始化最外层的包pnpm init

ERR_PNPM_RECURSIVE_RUN_FIRST_FAIL vue-demo@0.0.0 dev: `vite` Exit status 1

一些常用的命令

pnpm i 和 pnpm init

pnpm i是 pnpm install的简写,表示安装包,会根据package.json的包版本进行安装,
pnpm init是初始化一个项目,一般只会在空项目文件下创建package.json一些必要的包

pnpm run dev 和 pnpm run start

前者是开发环境,后者是打包之后的生产环境运行项目

使用脚手架建立项目

因为涉及诸多配置,建议按照vite、webpack官网来看

使用vite脚手架建立vue、react项目

使用webpack脚手架建立vue、react项目

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

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

相关文章

软件测试工程师简历项目经验怎么写?--9999个已成功入职的软件测试工程师真实简历

简历是我们求职的第一步&#xff0c;也是非常重要的一步。 青云叔叔看过太多简历&#xff0c;最快3秒就淘汰一份简历&#xff0c;因为其实我们每天要收到很多简历进行筛选&#xff0c;那么面试官其实也是会很快进行对简历进行判断的&#xff0c;如果你对简历写的一塌糊涂&…

8、SpringCloud高频面试题-版本1

1、SpringCloud组件有哪些 SpringCloud 是一系列框架的有序集合。它利用 SpringBoot 的开发便利性巧妙地简化了分布式系统基础设施的开发&#xff0c;如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等&#xff0c;都可以用 SpringBoot 的开发风格做到一键启…

第十三节TypeScript 元组

1、简介 我们知道数组中元素的数据类型一般都是相同的&#xff08;any[]类型的数组可以不同&#xff09;&#xff0c;如果存储的元素类型不同&#xff0c;则需要使用元组。 元组中允许存储不同类型的元素&#xff0c;元组可以作为参数传递给函数。2、创建元组的语法格式&#x…

MATLAB Mobile - 使用预训练网络对手机拍摄的图像进行分类

系列文章目录 前言 此示例说明如何使用深度学习对移动设备摄像头采集的图像进行分类。 在您的移动设备上安装和设置 MATLAB Mobile™。然后&#xff0c;从 MATLAB Mobile 的“设置”登录 MathWorks Cloud。 在您的设备上启动 MATLAB Mobile。 一、在您的设备上安装 MATLAB M…

IDEA控制台乱码

报错情况&#xff1a; 报错原因&#xff1a;Idea的vm用的编码格式不一致&#xff1a;需要修改为UTF-8 你看Tomcat我之前下在后修改果&#xff0c;就没有报错&#xff0c;新人刚下载也有乱码问题 问题解决&#xff1a; 按我步骤来一定对 下面这俩文件打开输入&#xff1a; -D…

医疗机构远程视频监控集中管理,贝锐蒲公英提供一站式解决方案

上海某企业专业致力于医疗软件、家居智能化研发、设计、销售、集成及实施&#xff0c;企业主营业务之一为医疗软件&#xff0c;涉及PACS/RIS/WEB/HIS、示教系统等方面的医院信息化建设。 在实际应用、部署过程中&#xff0c;需要实现各地区分院与总院间的数据库互相访问、视频数…

Portainer.io:让容器管理变得更加直观

在现代软件开发和部署中&#xff0c;容器化技术已经变得越来越流行。Docker 是其中一种领先的容器化平台&#xff0c;而 Portainer.io 则是一个优秀的管理工具&#xff0c;使得 Docker 的使用变得更加简单和可视化。本文将介绍 Portainer.io 的基本功能和如何在 Docker 上安装和…

jQuery: 整理4---创建元素和添加元素

1.创建元素&#xff1a;$("内容") const p "<p>这是一个p标签</p>" console.log(p)console.log($(p)) 2. 添加元素 2.1 前追加子元素 1. 指定元素.prepend(内容) -> 在指定元素的内部的最前面追加内容&#xff0c;内容可以是字符串、…

1-GAN

一、GAN简介 人脸检测、图像识别、语音识别&#xff0c;机器总是在现有事物的基础上做出描述或判断[参考] 能不能创造这个世界不存在的东西&#xff1f;GAN GAN&#xff0c;全称Generative Adversarial Networks&#xff0c;中文叫生成式对抗网络。GAN它包含三个部分&#xf…

【随想】每日两题Day.22

题目&#xff1a;102. 二叉树的层序遍历 给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;[[3],[…

基于 Editor.js 开发富文本编辑器库

开始 Editor.js 提供了简单而直观的用户界面&#xff0c;根据需求可以灵活添加自定义的编辑工具&#xff0c;通过插件扩展功能 Editorjs 使用 js 开发&#xff0c;脱离框架依赖&#xff0c;因此可以基于它封装富文本编辑器&#xff0c;用于 Vue 和 React 项目 editor-js-com…

C语言、c++实现超好玩植物大战僵尸(完整版附源码)

实现这个游戏需要Easy_X main.cpp //开发日志 //1导入素材 //2实现最开始的游戏场景 //3实现游戏顶部的工具栏 //4实现工具栏里面的游戏卡牌 #define WIN_WIDTH 900 #define WIN_HEIGHT 600 //定义植物类型 enum { WAN_DOU, XIANG_RI_KUI, ZHI_WU_COUNT }; #include<stdio.…

linux系统和网络(三):IO,信号,信号量,线程

本文主要探讨linux的IO,信号,信号量,线程相关知识,详细知识可参考本博客其他文章。 信号&#xff08;可参考本博客其他文章&#xff09; 信号是内容受限的异步通信机制,硬件异常后统内核发出信号 alarm产生SIGALARM信号,读端关闭后管道write产生SIGPIPE信号 常见信号…

2024年起重机司机(限门式起重机)证考试题库及起重机司机(限门式起重机)试题解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年起重机司机(限门式起重机)证考试题库及起重机司机(限门式起重机)试题解析是安全生产模拟考试一点通结合&#xff08;安监局&#xff09;特种作业人员操作证考试大纲和&#xff08;质检局&#xff09;特种设备作…

基于模型驱动的可解释性全色、多光谱、高光谱融合网络

摘要 摘要:同时融合高光谱(HS)、多光谱(MS)和全色(PAN)图像为生成高分辨率HS (HRHS)图像提供了一种新的范式。在这项研究中&#xff0c;我们提出了一个可解释的模型驱动的深度网络&#xff0c;用于HS, MS和PAN图像融合&#xff0c;称为HMPNet。我们首先提出了一种新的融合模型…

编译原理--递归下降分析实验C++

一、实验项目要求 1.实验目的 根据某一文法编制调试递归下降分析程序&#xff0c;以便对任意输入的符号串进行分析。本次实验的目的主要是加深对递归下降分析法的理解。 2.实验要求 对下列文法&#xff0c;用递归下降分析法对任意输入的符号串进行分析&#xff1a; &#…

【并发编程篇】定义最大线程的方法

文章目录 &#x1f354;省流&#x1f3f3;️‍&#x1f308;前言&#x1f6f8;CPU密集型&#x1f339;代码实现 &#x1f6f8;IO密集型 &#x1f354;省流 池的最大大小如何去设置 使用CPU密集型和IO密集型这2种方法 &#x1f3f3;️‍&#x1f308;前言 上一篇文章我们讲解…

音视频的编码格式与封装格式

音视频的编码格式与封装格式是两个不同的概念&#xff0c;视频封装格式常见的有&#xff1a;mp4&#xff0c;rmvb&#xff0c;avi&#xff0c;mkv&#xff0c;mov&#xff0c;mpg&#xff0c;vob&#xff0c;3gp&#xff0c;asf&#xff0c;rmvb&#xff0c;wmv&#xff0c;div…

ARM GIC (五)gicv3架构-LPI

在gicv3中,引入了一种新的中断类型。message based interrupts,消息中断。 一、消息中断 外设,不在通过专用中断线,向gic发送中断,而是写gic的寄存器,来发送中断。 这样的一个好处是,可以减少中断线的个数。 为了支持消息中断,gicv3,增加了LPI,来支持消息中断。并且…

分布式事务TCC补偿机制

文章目录 概述工作流程优缺点优点&#xff1a;缺点&#xff1a; 总结Java 示例代码 概述 TCC&#xff08;Try-Confirm-Cancel&#xff09;补偿机制是一种事务处理模式&#xff0c;用于确保分布式系统中的操作成功完成或在失败时进行补偿。TCC将一个事务拆分为三个阶段&#xf…