H5嵌入小程序适配方案

时间过去了两个多月,2024已经到来,又老了一岁。头发也掉了好多。在这两个月时间里都忙着写页面,感觉时间过去得很快。没有以前那么轻松了。也不是遇到了什么难点技术,而是接手了一个很烂得项目。能有多烂,一个页面发起六次同一个请求得存在,不得已又要重构页面。最近呢,在做webapp,h5,小程序,钉钉得适配,都是用一套代码。可以说都是h5链接得形式引入。无非显示东西不一样,这个不一样得东西,一般都是头部,跟下面得导航栏显示,功能得适配。不同手机机型得适配,也无非两种机型,安卓,IOS,线上问题得调试,还有屏幕尺寸得适配。不得不说这些真的掉头发。这篇主要是h5嵌入小程序,以及app适配方案。

说明

本文是针对是把h5应用嵌入其它平台得流程。不是单独taro发布一个小程序,单独打包成app得流程,是从一个主平台直接进入一个子系统得嵌入适配方案。所以描述得时候需要注意理解,我们是做了单点登录得。直接是使用一套 “build:h5”: “taro build --type h5”,进行得方案。当然不同得单独做登录得时候无法就是taro去获取当前得环境是weapp还是h5。我们得单点登录采用得方案是凭借在url里面得环境判断也是通过url方式。不是cooike跨域共享。这是因为平台很早就有的了。所以需要注意理解。不过这篇主要讲得是h5嵌入小程序

一、h5嵌入小程序适配流程

1、H5项目编译。基于自己的app项目,仍编译成h5环境的代码,就不存在启动weapp的情况了。换句话说,就是都用h5页面了。

2、照文档进行适配。根据本文第二点和第三点所述,代码层面做评估适配开发。

3、选择性使用sdk。如项目中不涉及文件类(上传下载)操作,适配工作可至本文第三点第4点即可;如涉及,请按照三.5描述进行sdk引入适配。

4、发布更新测试调试。同app,项目正常部署后,生成的h5地址就是最终通过平台小程序嵌入的h5地址,更新完成后,进行集成联调;但有一点和app不同,h5地址必须是映射过的,否则小程序集成环境无法正常访问。

二、 页面结构适配

1.导航栏:

思想上,app是需要导航栏得,小程序是自带固定得导航栏得。当是小程序时去除头部导航栏,顶部栏不能有任何东西,小程序的webview固定了导航栏,只允许修改基础配置,背景色,标题等。记得每个页面都要改,建议添加全局的判断方法.。所以这时候封装导航栏时,这时候就要考虑环境了。

2.页面内容得适配:

总体思想,采用媒体查询为基准,大得调整(有些页面在一些尺寸得屏幕需要另外得展示),页面区间采用flex布局。

因为我们使用得是taro,在 Taro 中尺寸单位建议使用 px、 百分比 %,Taro 默认会对所有
单位进行转换。在 Taro 中书写尺寸按照 1:1 的关系来进行书写,即从设计稿上量的长度 100px,那么尺寸书写就是 100px,当转成微信小程序的时候,尺寸将默认转换为 100rpx,当转成 H5 时将默认转换为以 rem 为单位的值。

3.路由切换:

尽量采用路由跳转,为什么内,如果采用tabs进行切换时候,如果时app返回操作还能进行处理,如果是微信小程序,上面返回就直接让你退出了。为此我们还进行了重构了首页页面。同时也要考虑手机物理按键得返回。所以尽量采用路由跳转方式。

4.js操作像素时:

当我们用js进行像素操作时,对此我们需要封装一个方法进行转化,特殊处理只用关心px。

export const transformToRemOrRpx = function(size: number): Promise<string> {
    return new Promise((resolve, reject) => {
        Taro.getSystemInfo({
            success: res => {
                const width = res.windowWidth;
                const pixelRatio = 750 / width;
                let transSize = "0";
                if (process.env.TARO_ENV === 'weapp') {
                    transSize = size * pixelRatio + "rpx";
                } else { 
                    let baseSize = width >= 640 ? 40 : width <= 320 ? 20 : width / 320 * 20;
                    transSize = size / baseSize + "rem";
                }
                resolve(transSize);
            },
            fail: err => {
                reject(err);
            }
        })
    })
}

三、功能实现:

1. 编译

当前就不存在编译成weapp的情况了,都是h5,所以需要从跳转的地址栏上区分是小程序的h5还是app的h5,需要通过环境进行判断。以及根据这个判断来做适配。

注意:获取地址栏参数需要用原生location方式取,taro自带的api有可能会取不到,如果你想偷懒,本文也提供了获取地址栏参数的办法。

//解析url参数
export function parseUrlSearch<T>(): T {
    if (!window.location) { return {} as any }
    let href = window.location.href;
    if (href.includes('#') && href.includes('?')) {
        let queryIndex = href.indexOf('?')
        let symbolIndex = href.indexOf('#')
        let symbolList = href.split('#')
        symbolList = symbolList.filter(o => o.includes('?') ? o : false)
        let moreQuery = symbolList[1] && symbolList[1].slice(symbolList[1].indexOf('?')) || '';
        if (queryIndex < symbolIndex) {
            let hrefString = href.slice(0, href.indexOf('#'))
            href = hrefString + moreQuery.replace('?', '&')
        }
    }
    let qindex = href.indexOf("?");
    let queryParams = href.substr(qindex + 1);
    let queryParamsArr = queryParams.split("&");
    let queryParamsObj = {};
    queryParamsArr.map((v) => {
        let tmp = v.split("=");
        let value: string = tmp.length === 2 ? decodeURIComponent(tmp[1]) : '';
        if (value.includes("[") && value.includes("]")) {
            queryParamsObj[tmp[0]] = JSON.parse(decodeURIComponent(value));
        } else {
            queryParamsObj[tmp[0]] = decodeURIComponent(tmp[1])
        }
    });

    return queryParamsObj as any;
}

2. 数据获取(缓存)

小程序的h5,即webview场景下微信不允许使用缓存,需要适配;另外taro提供的存储api无法支持跨页面存储。小程序的h5所需全局数据,必须全部采用从地址栏传参方式获取,拿不到。

3. Token校验

微信嵌h5环境下,系统要求去除token校验,或者采用调组件库内app.ts中提供的token更新接口方式进行token校验更新。因为小程序的webview里头注入基础平台的js文件会有很多问题,最主要的是域名校验和资源路径问题,当前解决起来成本比较高,所以先去除。

4. taro全局路径配置(接口根路径、打包静态资源路径)

const path = require("path");
const config = {
   projectName: 'myApp',
   date: '2024-1-20',
   designWidth: 750,
   deviceRatio: {
      640: 2.34 / 2,
      750: 1,
      828: 1.81 / 2
   },
   sourceRoot: 'src',
   outputRoot: `dist/${process.env.TARO_ENV}`,//多端开发时必须使用******important*******
   plugins: [],
   defineConstants: {},
   copy: {
      patterns: [
         {
            from: '',
            to: ''
         },
      ],
      options: {}
   },
   framework: 'react',
   mini: {
      postcss: {
         pxtransform: {
            enable: true,
            config: {}
         },
         url: {
            enable: true,
            config: {
               limit: 1024 // 设定转换尺寸上限
            }
         },
         cssModules: {
            enable: true, // 默认为 false,如需使用 css modules 功能,则设为 true
            config: {
               namingPattern: 'module', // 转换模式,取值为 global/module
               generateScopedName: '[name]__[local]___[hash:base64:5]'
            }
         }
      }
   },
   h5: {
      publicPath: '/',
      staticDirectory: 'static',
      esnextModules: ['taro-ui'],//应用taroUI的时候必须设置******important*******
      postcss: {
         autoprefixer: {
            enable: true,
            config: {}
         },
         cssModules: {
            enable: true, // 默认为 false,如需使用 css modules 功能,则设为 true
            config: {
               namingPattern: 'module', // 转换模式,取值为 global/module
               generateScopedName: '[name]__[local]___[hash:base64:5]'
            }
         }
      }
   },
   alias: {
      '@/pages': path.resolve(__dirname, '..', 'src/pages'),
   }
}

module.exports = function (merge) {
   if (process.env.NODE_ENV === 'development') {
      return merge({}, config, require('./dev'))
   }
   return merge({}, config, require('./prod'))
}

5. 复杂业务(预览/选择图片等)sdk引入

由于微信环境下的h5需要使用微信提供的weixin-sdk,才能使用微信允许的功能,微信提供的接口如下图(附网址):

在这里插入图片描述

附网站:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html

四、常见的问题:

1. 子系统具体的页面标题怎么确定?

跳转过去默认是模块名称作为标题。如果需要自定义导航栏标题,建议使用document.title设置就行。

2. 涉及到sdk的功能如何进行调试?

真机调试。
1.调式接口,查看接口。点击小虫子就可以查看子应用得一个请求情况。
在这里插入图片描述

在这里插入图片描述
2.真机调试查看功能是否适配,采用局域网得方式直接连接本地跑的应用。

在这里插入图片描述

3. sdk不支持预览文件操作?

封装一个preiewFile这个函数的主要目的是在微信小程序内预览特定路径的文件。
这是它如何工作的:

1.首先,函数接受一个路径作为参数,并从该路径中提取出文件的类型。

2.如果文件类型是图片(png,jpeg,jpg),那么使用wx.previewImage预览该图片。

3.如果不是图片,那么函数会调用wx.downloadFile来下载该文件。在下载过程中,会显示一个加载提示。下载成功后,如果文件类型是文本文件(txt),那么就使用 wx.getFileSystemManager().readFile 读取文件内容,并通过模态对话框显示出来。

4.如果文件类型不是文本文件,那么就尝试使用 wx.openDocument 打开该文件。如果打开过程中出现错误,错误详细信息将被打印到控制台。

整个函数的主要功能就是为了提供一个预览文件的方案,包括图片预览,文本内容阅读以及开启文档。这样的功能在某些需要预览文件内容的场景中会非常有用。

const wx = require('weixin-js-sdk')
   function previewFile(path) {
      // const path = files[index][this.data.downLoadAttr]
      const fileNameArr = name.split('.')
      const fileType = fileNameArr[fileNameArr.length-1]
      if(fileType == 'png' || fileType == 'jpeg' || fileType == 'jpg'){
         wx.previewImage({
            current: path, // 当前显示图片的http链接
            urls: [path] // 需要预览的图片http链接列表
         })
         return
      }
      let fs = wx.getFileSystemManager();
      wx.showLoading({ title : '文件加载中' });
      wx.downloadFile({
         url: path,//文件路径
',      //文件路径
         header: {},
         success: function (res) {
            wx.hideLoading();
            var filePath = res.tempFilePath;
            if(fileType == 'txt'){
               fs.readFile({
                  filePath:filePath,
                  encoding:'utf8',
                  complete(res){
                     // console.log(res.data);
                     wx.showModal({
                        title: '文件内容',
                        content: res.data,
                        showCancel: false,
                        confirmText: '确定',
                        success: (result) => {
                           if(result.confirm){

                           }
                        },
                        fail: ()=>{},
                        complete: ()=>{}
                     });
                  }
               })
            }else{
               wx.openDocument({
                  filePath: filePath,
                  showMenu : true,
                  // fileType: type,   //文件类型
                  success: function (res) {
                  },
                  fail: function (res) {
                     // wx.showToast({ title: '文件打开失败', icon : 'none' })
                     console.table(res);
                  },
                  complete: function (res) {
                  }
               })
            }
         },
         fail: function (res) {
            wx.hideLoading();
            console.log('文件下载失败:',path)
            wx.showToast({ title: '文件加载失败', icon : 'none' })
            console.table(res)
         },
         complete: function (res) {
         },

      })
   }

对于下载

简单粗暴的解决方式是:复制链接让用户自行去浏览器下载。可以借助clipboard插件。

4. sdk不支持文件选择操作?

当然,也不能使用taro提供的chooseMessageFile,因为微信的webview没开放给你用。我封装了原生input的实现封装方法chooseFIle,可以直接copy使用。

1.这函数,它用于在Web和非Web环境(如微信小程序)中选择文件。它以函数形式暴露,可以从外部调用,并传入一个对象参数,这个参数包括count(选择文件的数量),success(成功的回调函数),fail(失败的回调函数)和complete(完成的回调函数)。

2.函数首先进行参数校验,例如检查传入的 count 是否为数字。如果校验失败,它将调用失败回调函数并返回一个Rejected Promise。如果一切正常,我们会进行环境判断。

3.如果环境是Taro的WEB环境,那么将在页面上创建一个input元素,并设置它为file类型,以供用户选择文件。选择的文件信息会被添加到返回的结果对象中,然后调用成功回调和完成回调。

4.对于非Web环境,它使用Taro的 chooseMessageFile 方法来选择文件,这个函数通常被用于在微信小程序中选择聊天文件。

这个函数的主要目的是提供一个通用的文件选择方案,无论在Web环境还是非Web环境,都可以以相同的方式来选择文件。

import Taro from '@tarojs/taro';
//选择文件
export const chooseFile = function (option) {
    const {count = 1, success,url, fail, complete} = option
    const res: any = {
        errMsg: 'chooseFile:ok',
        tempFilePaths: [],
        tempFiles: []
    }
    if (count && typeof count !== 'number') {
        res.errMsg = 'error,typeof count is error',
            console.error(res.errMsg)
        typeof fail === 'function' && fail(res)
        typeof complete === 'function' && complete(res)
        return Promise.reject(res)
    }

    if (Taro.getEnv() === Taro.ENV_TYPE.WEB) {
        const fileId = "MyUtilsChooseFile"
        let taroChooseImageId: any = document.getElementById(fileId)
        if (!taroChooseImageId) {
            let htmlInputElement: any = document.createElement("input");
            htmlInputElement.type = "file"
            htmlInputElement.setAttribute('id', fileId)
            htmlInputElement.setAttribute('style', 'position: fixed; top: -4000px; left: -3000px; z-index: -300;')
            if (count > 1) {
                htmlInputElement.setAttribute('multiple', 'multiple')
            }
            document.body.appendChild(htmlInputElement)
            taroChooseImageId = document.getElementById(fileId)
        } else {
            if (count > 1) {
                taroChooseImageId.setAttribute('multiple', 'multiple')
            } else {
                taroChooseImageId.removeAttribute("multiple")
            }
        }

        taroChooseImageId.onchange = (e) => {
            // console.log("onchange",e)
            let arr = [...e.target.files]
            arr = arr.splice(0, count)
            arr && arr.forEach(item => {
                let blob = new Blob([item], {
                    type: e.target.files[0].type
                });
                let url = URL.createObjectURL(blob);
                res.tempFilePaths.push(url)
                // res.tempFiles.push({path: url, size: item.size, type: item.type, originalFileObj: item})
                console.log("选择item", item)
                res.tempFiles.push({
                    path: url,
                    size: item.size,
                    type: item.type,
                    name: item.name,
                    lastModified: item.lastModified,
                    lastModifiedDate: item.lastModifiedDate,
                    webkitRelativePath: item.webkitRelativePath
                })
            })
            typeof success === "function" && success(res)
            typeof complete === "function" && complete(res)

            e.target.value = ''
            // document.body.removeChild(taroChooseImageId)
        }
        //触发选择
        taroChooseImageId.click()

    } else {
        Taro.chooseMessageFile({
            count: count,
            type: 'file',
            success: function (res) {
                // console.log("选择文件",res)
                success ? success(res) : ""
            }
        })
    }
}

使用

chooseFile({
  count:2,
  success(res){
    console.log(res)
  }
})

5. sdk不支持文件上传操作?

用Taro自带的Taro.uploadFile(option)实现,示例如下:

chooseFile({
  count:2,
  success(res){
    console.log(res)
    Taro.uploadFile({
      url:url
      filePath:res.tempFiles[0].path,
      name:res.tempFiles[0].name,
      formData: {},
      success (res){
        const data = res.data
        //do something
      }
    })
  } 	
})

6. sdk不支持小程序跳转?如何实现

先进行环境的判断

// 判断当前环境是否为小程序
const ua = navigator.userAgent.toLowerCase();
if (ua.match(/MicroMessenger/i) == 'micromessenger') {
    wx.miniProgram.getEnv((res) => {
        if (res.miniprogram) {
            console.log('在小程序内');
        } else {
            console.log('不在小程序内');
        }
    });
} else {
    console.log('不在微信浏览器内');
}

// 小程序跳转方法
wx.miniProgram.navigateTo({
   url:'/pages/index/index',        // 指定跳转至小程序页面的路径
   success: (res) => {
	  console.log(res);   // 页面跳转成功的回调函数
   },
   fail: (err) => {
	  console.log(err);   // 页面跳转失败的回调函数
   }
});

// 通过链接与小程序通讯传参
// 静态参数传输
wx.miniProgram.navigateTo({
   url:'/pages/index/index?id=1', // id:所需参数
   success: (res) => {
	  console.log(res);   // 页面跳转成功的回调函数
   },
   fail: (err) => {
	  console.log(err);   // 页面跳转失败的回调函数
   }
});

// 动态参数传输
let id = 1;
wx.miniProgram.navigateTo({
   url:'/pages/index/index?id=' + id, // id:所需参数(动态参数需放在引号外小程序才可识别)
   success: (res) => {
	  console.log(res);   // 页面跳转成功的回调函数
   },
   fail: (err) => {
	  console.log(err);   // 页面跳转失败的回调函数
   }
});

如果不再小程序内跳转会报错。

解决思想:
首先,webview内嵌h5,从h5页面是不可以直接使用wx.miniProgram.navigateTo 方法跳转到其他小程序,所以具体思路应该是小程序A => webview内嵌 h5 => 从h5调回到小程序A的中转页面 => 在小程序A中 使用wx.navigateToMiniProgram 方法跳转到 小程序B

1.我们采用自定义的navigateToMiniProgramForWebview函数来触发从当前小程序跳转到另一个小程序。这个函数接收两个参数,wx对象和包含跳转信息的params对象。
2.wx对象是由微信API提供的一个核心对象,带有微信小程序的接口。params对象包含了必须的跳转信息,比如目标小程序的appId,路径(path),额外的数据(extraData),以及小程序的版本.

3.函数体中的第一步是创建一个新的对象 passParams,它复制了params的所有属性,然后把extraData属性转换成 JSON 字符串,并且添加了一个新的属性:type,在这个例子中其值为:‘navigateToMiniProgram’。

4.接下来,将这个passParams对象通过一个叫formatParams的函数转换成一个URL查询字符串,和路径组合成一个完整的URL。在这个例子中,这个URL指向小程序的一个特定页面:webviewMiddlePage,并带有跳转信息作为查询参数。

5.最后一步是通过 wx.miniProgram.navigateTo 接口, 使用这个URL进行导航。这将触发在当前小程序中打开webviewMiddlePage 页面,然后这个页面会解析URL中的参数,并根据跳转信息完成从当前小程序到目标小程序的跳转。

注意,这个函数中使用了两次跳转。
第一次是在当前小程序内部,跳转到 webviewMiddlePage页面。
第二次跳转是在 webviewMiddlePage 页面中,完成从当前小程序到目标小程序的跳转。通过这种方式设计,使得跳转过程可以携带更复杂的数据,同时绕过微信小程序navigateToMiniProgram 方法对传递数据量的限制。

  const navigateToMiniProgramForWebview =(wx, params:any = {})=> {
    const passParams = {
      ...params,
      extraData:JSON.stringify(params.extraData || {}),
      type: 'navigateToMiniProgram'
    }
    const url = `/pages/webviewMiddlePage/index?${formatParams(passParams)}`//跳回我们小程序自定义得页面请求打开另外一个小程序
    wx?.miniProgram?.navigateTo({url})
  }
  navigateToMiniProgramForWebview(wx, {
     appId: '',//必传 跳转小程序唯一标识
     path: ``,//必传 跳转后初始页面路径
          //develop(开发版),trial(体验版),release(正式版 )
    envVersion: 'release',//必传 跳转小程序的版本
  })
    
 function formatParams(obj: any){
  let arr: string[] = []
  Object.keys(obj).forEach(key => {
    if(obj[key] && typeof obj[key] === 'string') {
      arr.push(`${key}=${encodeURIComponent(obj[key])}`)
    }
  })
  return arr.join('&')
}

如果是app或者h5直接window.open

在这里插入图片描述

7.IOS日期显示Invalid date

注意:iso 这样 new Date(‘2021-02-11’) 返回的就是Invaild Date。
new Date(‘2021/02/11’) '/'才是正常的

在这里插入图片描述

五、让人哭笑不得得代码

1.发起了六次请求。我挺搞不懂他是怎么写得。然后我就重构了页面。

在这里插入图片描述
在这里插入图片描述

2.人生无语,查看订单后,不能保存id嘛,又进行一次查询。然后在删除。然后我又要重构头就是怎么秃得

请添加图片描述
是不是很有意思

六、对于多端开发

小程序得每年认证,对于企业来说将会采用更多得h5页面去嵌入一个总的小程序平台,而不是采用单独得开发发布,因为如果认证几个小程序或者十几个小程序,企业觉得这样得费用不是很值得,更青睐于h5一套嵌入,webapp也是如此,钉钉也是如此,其它得也是。、taro也可以适配鸿蒙系统得开发。uniapp 是一种基于 Vue.js 的跨平台开发框架。而Taro 是一种基于 React 的多端开发框架。taro跟uniapp,taro跟react框架搭配,uniapp跟Vue搭配。两个框架我都学习使用。感受就是语法不一样,解决思路还是一样得。做多了项目后,会发现,其实框架只是实现需求得一种工具,更重要得是解决问题得思想跟经验。就像我搭档一样,他工作三年多了,他说他之前是使用vue开发得,对小程序,跟webapp也不是很熟。虽然我之前做过,但是跟他一起工作给我得一种感觉是他上手快。解决思路很清晰,只是语法切换而已,能搞快速得定位问题,并参考学习。

uniapp搭建学习

项目基于 uniapp + Vue3 + vite + pinia + ts + axios 项目模板快速开发,适用于小程序开发 h5。

项目使用了 vite 作为开发工具,支持 esm、cjs、iife 三种打包方式,支持按需加载,支持热更新。

github:https://github.com/wskang12138/aniapp-learn

声明:这个框架不是我搭建得,我也只是demo下来学习,改改就成我得了,哈哈哈哈哈哈。

七、总结

对于多端得适配,四种情况:顶部导航栏得适配,页面样式得适配,功能得适配,其它。
对于顶部导航栏得适配,这个简单,判断环境做好封装显示就好了。页面样式得适配,媒体查询为基准,flex为区间布局。功能得适配:得翻阅文档学习了。

参考:https://github.com/uileader/touchwx

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

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

相关文章

Linux之进程间通信(管道)

目录 一、进程间通信 1、进程间通信的概念 2、进程间通信的目的 3、进程间通信的分类 二、管道 1、管道基本介绍 2、匿名管道 3、命名管道 一、进程间通信 1、进程间通信的概念 什么是进程间通信&#xff1f; 我们在学习了进程的相关知识后&#xff0c;知道&#xff…

Vue记录

vue2、vue3记录 vue2记录 经典vue2结构 index.vue&#xff1a; <template><div>...</div> </template><script>import method from "xxx.js"import component from "xxx.vue"export default {name: "ComponentName&…

Vue3.0性能提升主要是通过哪几方面体现的?

文章目录 一、编译阶段diff算法优化静态提升事件监听缓存SSR优化 二、源码体积三、响应式系统参考文献 一、编译阶段 回顾Vue2&#xff0c;我们知道每个组件实例都对应一个 watcher 实例&#xff0c;它会在组件渲染的过程中把用到的数据property记录为依赖&#xff0c;当依赖发…

Cloudreve存储策略-通过从机存储来拓展容量

Sham的云服务器是搬瓦工最低低低配的&#xff0c;1H 0.5G不说&#xff0c;硬盘容量也只有10g&#xff0c;说实话&#xff0c;装了宝塔面板和服务器套件后&#xff0c;基本满了&#xff0c;这时又想在云服务器上打个网盘用于下载、存储&#xff0c;这时就需要拓展硬盘&#xff0…

Redis 面试题 | 01.精选Redis高频面试题

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

HCIA——22DNS:DNS层次域名空间、域名服务器、域名解析的原理

学习目标&#xff1a; 计算机网络 1.掌握计算机网络的基本概念、基本原理和基本方法。 2.掌握计算机网络的体系结构和典型网络协议&#xff0c;了解典型网络设备的组成和特点&#xff0c;理解典型网络设备的工作原理。 3.能够运用计算机网络的基本概念、基本原理和基本方法进行…

基于springboot+vue的母婴商城系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目背景…

第二课:BERT

文章目录 第二课&#xff1a;BERT1、学习总结&#xff1a;为什么要学习BERT&#xff1f;预训练模型的发展历程BERT结构BERT 输入BERT EmbeddingBERT 模型构建BERT self-attention 层BERT self-attention 输出层BERT feed-forward 层BERT 最后的Add&NormBERT EncoderBERT 输…

c++ mysql数据库编程(linux系统)

ubuntu下mysql数据库的安装 ubuntu安装mysql&#xff08;图文详解&#xff09;-CSDN博客https://blog.csdn.net/qq_58158950/article/details/135667062?spm1001.2014.3001.5501 项目目录结构 数据库及表结构 public.h //打印错误信息 #ifndef PUBLIC_h #define PUBLIC_H…

Centos使用Docker搭建自己的Gitlab(社区版和设置汉化、修改密码、设置SSH秘钥)

根据我的经验 部署Gitlab&#xff08;社区版&#xff09; 至少需要2核4g的服务器 带宽3~4M 1. 在自己电脑上安装终端&#xff1a;宝塔ssl终端 或者 FinalShell&#xff0c;根据喜好安装即可 http://www.hostbuf.com/t/988.html http://www.hostbuf.com/downloads/finalshell_w…

macOS磁盘管理工具Paragon Hard Disk Manager,轻松且安全的改变磁盘分区

Paragon Hard Disk Manager mac版是Macos上一款磁盘管理工具&#xff0c;可以帮助你轻松而且安全的随意改变磁盘分区的大小和各种分区参数&#xff0c;作为mac磁盘分区工具也是游刃有余&#xff0c;同时在找回数据的时候也非常容易&#xff0c;并且不会损坏原来的数据&#xff…

项目解决方案:多地医馆的高清视频监控接入汇聚联网

目 录 一、背景 二、建设目标及需求 1.建设目标 2.现状分析 3.需求分析 三、方案设计 1.设计依据 2.设计原则 3.方案设计 3.1 方案描述 3.2 组网说明 四、产品介绍 1.视频监控综合资源管理平台介绍 2.视频录像服务器和存储 2.1概述 2.2存储设计 …

【工具】使用ssh进行socket5代理

文章目录 shellssh命令详解正向代理&#xff1a;反向代理&#xff1a;本地 socks5 代理 shell ssh -D 3333 root192.168.0.11 #输入密码 #3333端口已经使用远程机进行转发设置Windows全局代理转发 socks127.0.0.1 3333如果远程机为公网ip&#xff0c;可通过搜索引擎查询出网…

软件资源管理下载系统全新带勋章功能 + Uniapp前端

测试环境&#xff1a;php7.1。ng1.2&#xff0c;MySQL 5.6 常见问题&#xff1a; 配置好登录后转圈圈&#xff0c;检查环境及伪静态以及后台创建好应用 上传图片不了&#xff0c;检查php拓展fileinfo 以及public文件权限 App个人主页随机背景图&#xff0c;在前端uitl文件…

【数学笔记】集合及简要逻辑

集合 基础简要逻辑集合间的关系与运算 基础 集合定义&#xff1a;把一些能够确定的不同对象组成的整体叫做一个集合&#xff0c;每个对象叫做元素。集合记法&#xff1a;一般用大写字母 A , B , C . . . . . . A,B,C...... A,B,C......表示集合&#xff0c;小写字母 a , b ,…

GD32E230C8T6《调试篇》之 (软件) IIC通信(主机接收从机) + GN1650驱动芯片 + 按键 + 4位8段数码管显示 (成功)

GD32E230C8T6《调试篇》之 &#xff08;软件&#xff09; IIC通信 GN1650驱动芯片 4位8段数码管显示&#xff08;成功&#xff09; IIC是什么IIC简介1&#xff09;IIC总线物理连接2&#xff09;IIC时序协议 按键扫描代码1&#xff09;DIG2短按只一次&#xff0c;长按超过1s 一…

[晓理紫]每日论文分享(有中文摘要,源码或项目地址)--大模型、扩散模型、视觉导航

专属领域论文订阅 VX 扫嘛关注{晓理紫}&#xff0c;每日更新论文&#xff0c;如感兴趣&#xff0c;请转发给有需要的同学&#xff0c;谢谢支持 分类: 大语言模型LLM视觉模型VLM扩散模型视觉导航具身智能&#xff0c;机器人强化学习开放词汇&#xff0c;检测分割 [晓理紫]每日论…

六、数组(1)一维数组

所谓数组&#xff0c;就是一个集合&#xff0c;里面存放了相同类型的数据元素 特点1&#xff1a;数组中每个数据元素都是相同的数据类型 特点2&#xff1a;数组是由连续的内存位置组成的 一、一维数组的定义方式 1、数据类型 数组名[数组长度]; 2、数据类型 数组名[数组长度…

谷歌浏览器通过network模拟HTTP中的GET/POST请求获取response

1、F12打开network选中需要模拟的方法Copy->Copy as fetch 2、通过AI帮你进行转换一下调用格式 原代码 fetch("https://mp.amap.com/api/forward/aggregate?mtop.alsc.kbt.intergration.toolkit.call.queryCallBlockInfo", {"headers": {"acce…

Latex绘图

排查Latex报错 “Command \csubfigure already defined” 这个可以通过添加如下命令&#xff1a; \usepackage{subfig} \usepackage{subfloat} ..... \begin{figure*}[h] \centering \subfloat[subfloat title]{ \label{fig:subfig:a} \includegraphics[scale0.7]{Figs/.....…