Vue2 基础面试题

v-show 和 v-if 区别

  • v-show 通过 CSS display 控制显示和隐藏
  • v-if 通过判断组件真实渲染和销毁,而不是显示和隐藏
  • 频繁切换显示状态用 v-show,否则用 v-if

v-if

  • v-ifv-for 一起使用时,v-for 具有比 v-if 更高的优先级,意味着:v-if 将分别重复运行于每个 v-for 循环中,会造成性能问题。所以,不推荐 v-ifv-for 同时使用
const compiler = require('vue-template-compiler')

const res = compiler.compile(`<div v-if="true" v-for="i in 3">{{message}}</div>`)

with (this) {
  return renderList(3, function(i) {
    return true ? createElement('div', [createTextVNode(toString(message))]) : createEmptyVNode()
  })
}


v-show

const compiler = require('vue-template-compiler')

const res = compiler.compile(`<p v-show="flag === 'a'">A</p>`)

with (this) {
  return createElement(
    'p',
    {
      directives: [
        { name: 'show', rawName: 'v-show', value: flag === 'a', expression: "flag === 'a'" },
      ],
    },
    [createTextVNode('A')]
  )
}

// v-show 操作的是样式 https://github.com/vuejs/vue/blob/dev/src/platforms/web/runtime/directives/show.js
bind (el: any, { value }: VNodeDirective, vnode: VNodeWithData) {
  vnode = locateNode(vnode)
  const transition = vnode.data && vnode.data.transition
  const originalDisplay = el.__vOriginalDisplay =
    el.style.display === 'none' ? '' : el.style.display
  if (value && transition) {
    vnode.data.show = true
    enter(vnode, () => {
      el.style.display = originalDisplay
    })
  } else {
    el.style.display = value ? originalDisplay : 'none'
  }
}


为何在 v-for 中用 key

  • 必须用 key,且不能是 index 和 random
  • diff 算法中通过 tag 和 key 来判断,是否是 sameNode
  • 减少渲染次数,提升渲染性能

描述 Vue 组件生命周期(父子组件)

  • beforeCreate 在初始化事件生命周期之后,数据被观测(observer)之前调用
  • created 实例已经创建完成之后被调用
  • 可以进行一些数据、资源请求。在这个阶段无法与 DOM 进行交互,如果非想要,可以通过 $nextTick 访问
  • beforeMount 在 DOM 挂载之前被调用,相关的 render 函数首次被调用(如果有 template 会转换成 render 函数)
  • 在此时也可以对数据进行更改,不会触发 updated
  • mounted 创建 vm.$el 并替换 el,并在挂载之后调用该钩子
  • 可以访问到 DOM 节点,使用 $refs 属性对 DOM 进行操作,也可以像后台发送请求,拿到返回数据
  • beforeUpdate 数据更新时调用,发生在虚拟 DOM 重新渲染和和打补丁之前
  • 可以在这个钩子中进一步地更改状态,这不会触发附加的重新渲染
  • updated 由于数据更改导致虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子
  • 避免在此期间更改状态,可能会导致更新无限循环
  • beforeDestroy 实例销毁之前调用
  • destroyed Vue 实例销毁后调用,调用后,Vue 实例所有东西都会解绑定,所有事件监听会被移除,所有子实例也会被销毁可以执行一些优化操作,清除定时器,解除绑定事件

注意:除了 beforeCreate 和 created 钩子之外,其他钩子均在服务器端渲染期间不调用

Vue.prototype._init = function (options?: Object) {
  // ...
  initLifecycle(vm)
  initEvents(vm) // 初始化事件相关的属性
  initRender(vm) // vm 添加了一些虚拟 dom、slot 等相关的属性和方法
  callHook(vm, 'beforeCreate')
  initInjections(vm)
  initState(vm) // props、methods、data、watch、computed等数据初始化
  initProvide(vm)
  callHook(vm, 'created')
}


mounted (渲染完成)执行顺序是先子后父

function patch(oldVnode, vnode, hydrating, removeOnly) {
   // 定义收集所有组件的insert hook方法的数组
  const insertedVnodeQueue = []
  if (isUndef(oldVnode)) {
    createElm(vnode, insertedVnodeQueue)
  }
}
function createElm(vnode, insertedVnodeQueue, ...) {
  // createChildren会递归创建子组件(递归createElm)
  createChildren(vnode, children, insertedVnodeQueue)
  if (isDef(data)) {
    // 执行所有的create钩子
    invokeCreateHooks(vnode, insertedVnodeQueue)
  }
}
function invokeCreateHooks (vnode, insertedVnodeQueue) {
  // 把vnode push到insertedVnodeQueue
  if (isDef(i.insert)) insertedVnodeQueue.push(vnode)
}

// 调用insert方法把DOM插入到父节点,因为是递归调用,子元素会优先调用insert
insert(parentElm, vnode.elm, refElm)
function invokeInsertHook(vnode, queue, initial) {
  // 依次调用insert方法
  queue[i].data.hook.insert(queue[i])
}
const componentVNodeHooks = {
  // 依次执行 mounted 方法
  insert(vnode: MountedComponentVNode) {
    callHook(componentInstance, 'mounted')
  },
}


$destroy (销毁完成)执行顺序是先子后父

Vue.prototype.$destroy = function() {
  callHook(vm, 'beforeDestroy')
   // 递归触发子组件销毁钩子函数
  vm.__patch__(vm._vnode, null)
  callHook(vm, 'destroyed')
}


Vue 组件如何通讯

  • 父 -> 子通过 props,子 -> 父通过 $on $emit
  • 在父组件中提供数据子组件进行消费 provide、inject
  • ref 获取实例的方式调用组件的属性或方法
  • 自定义事件 event.$on、event.$off、event.$emit
  • vuex 状态管理实现通信

描述组件渲染和更新过程

  • 生成 render 函数,其生成一个 vnode,它会 touch 触发 getter 进行收集依赖
  • 在模板中哪个被引用了就会将其用 Watcher 观察起来,发生了 setter 也会将其 Watcher 起来
  • 如果之前已经被 Watcher 观察起来,发生更新进行重新渲染

双向数据绑定 v-model 的实现原理

v-model本质上是语法糖,v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件

  • text 和 textarea 元素使用 value 属性和 input 事件
  • checkbox 和 radio 使用 checked 属性和 change 事件
  • select 字段将 value 作为 prop 并将 change 作为事件
const compiler = require('vue-template-compiler')

const res = compiler.compile(`<input v-model="name" type="text" />`)

with (this) {
  return createElement('input', {
    directives: [{ name: 'model', rawName: 'v-model', value: name, expression: 'name' }],
    attrs: { type: 'text' },
    domProps: { value: name },
    on: {
      input: function($event) {
        if ($event.target.composing) return
        name = $event.target.value
      },
    },
  })
}


对 MVVM 的理解

  • Model:代表数据模型,也可以在 Model 中定义数据修改和操作的业务逻辑。我们可以把 Model 称为数据层,因为它仅仅关注数据本身,不关心任何行为
  • View:用户操作界面。当 ViewModel Model 进行更新的时候,会通过数据绑定更新到 View
  • ViewModel:业务逻辑层,View 需要什么数据,ViewModel 要提供这个数据;View 有某些操作,ViewModel 就要响应这些操作

总结: MVVM模式简化了界面与业务的依赖,解决了数据频繁更新。MVVM 在使用当中,利用双向绑定技术,使得 Model 变化时,ViewModel 会自动更新,而 ViewModel 变化时,View 也会自动变化

computed 和 watch 的区别

computed

  • computed 具有缓存性,computed 的值在 getter 执行后是会缓存的,只有它依赖的属性值改变之后,下一次获取 computed 的值时才会重新调用对应的 getter 来计算
  • computed 适用于比较消耗性能的计算场景,可以提高性能

watch

  • 更多的是观察作用,类似于数据监听的回调函数,用于观察 props$emit 或本组件的值,当数据变化时来执行回调进行后续操作
  • 无缓存性,页面重新渲染时值不变化也会执行

computed watch 都支持对象的写法

vm.$watch('obj', {
  deep: true, // 深度遍历
  immediate: true, // 立即触发
  handler: function(val, oldVal) {}, // 执行的函数
})
var vm = new Vue({
  data: { a: 1 },
  computed: {
    aPlus: {
      // this.aPlus 时触发
      get: function() {
        return this.a + 1
      },
      // this.aPlus = 1 时触发
      set: function(v) {
        this.a = v - 1
      },
    },
  },
})

为何组件 data 必须是一个函数

  • 一个组件被复用多次的话,也就是创建多个实例。本质上,这些实例用的都是同一个构造函数,如果 data 是对象的话(引用数据类型),会影响到所有实例
  • 为了组件不同实例 data 不冲突,data 必须是一个函数

自定义 v-model

v-model 可以看成是 value + input 方法的语法糖

  • 自定义:自己写 model 属性,里面放上 prop event
<template>
  <input type="text" :value="text" @input="$emit('change', $event.target.value)" />
</template>

<script>
export default {
  model: {
    prop: 'text',
    event: 'change',
  },
  props: {
    text: String,
  },
}
</script>


相同逻辑如何抽离

  • Vue.mixin ,给组件每个生命周期、函数都混入一些公共逻辑
  • mixin 混入的钩子函数会先于组件内的钩子函数执行,并且在遇到同名选项时也会有选择性进行合并

何时使用异步组件

核心就是把组件变成一个函数,依赖 import() 语法,可以实现文件的分割加载

  • 加载大组件
  • 路由异步加载

何时使用 keep-alive

常用的两个属性:includeexclude,允许组件有条件的进行缓存

两个生命周期:activateddeactivated,用来得知当前组件是否处于活跃状态

  • 缓存组件实例,用于保留组件状态或避免重复渲染
  • 多个静态 Tab 页的切换时,来优化性能

何时需要使用 beforeDestory

  • 解绑自定义事件 event.$off
  • 清除定时器
  • 解绑自定义的 DOM 事件,如:windowscroll

action 和 mutation 有何区别

  • action 中可以处理异步,mutation 中不可以
  • mutation 做的是原子操作,action 可以整合多个 mutation

vue-router 常用的路由模式

hash 路由

  • hash 变化会触发网页跳转,即浏览器的前进、后退
  • hash 变化不会刷新页面,SPA 必需的特点
  • hash 永远不会提交到 server 端(前端自生自灭)

history 路由

  • url 规范的路由,但跳转时不刷新页面
  • 需要 server 端配合,可参考:后端配置例子
  • pushState 不会触发 hashchange 事件,popstate 事件只会在浏览器某些行为下触发,比如点击后退、前进按钮

vnode 描述一个 DOM 结构

  • Vue 中的真实 DOM
<div id="div1" class="container">
  <p>vdom</p>
  <ul style="font-size: 20px;">
    <li>a</li>
  </ul>
</div>

  • Vue 中的虚拟 DOM
{
  tag: 'div',
  props: {
    className: 'container',
    id: 'div1',
  },
  children: [
    {
      tag: 'p',
      children: 'dom',
    },
    {
      tag: 'ul',
      props: { style: 'font-size: 20px' },
      children: [{ tag: 'li', children: 'a' }],
    },
  ],
}


数据响应式原理

核心 API:Object.defineProperty

  • 存在一些问题,Vue 3.0 启动 Proxy
  • Proxy 可以原生支持监听数组变化
  • 但是 Proxy 兼容性不好,且无法 polyfill

问题

  • 深度监听,需要递归到底,一次性计算量大
  • 无法监听新增属性/删除属性(Vue.setVue.delete
  • 不能监听数组变化(重新定义原型,重写 pushpop 等方法)

简单实现 Vue 中的 defineReactive

// 触发更新视图
function updateView() {
  console.log('视图更新')
}

// 重新定义数组原型
const arrayProto = Array.prototype
// 创建新对象,原型指向 arrayProto ,再扩展新的方法不会影响原型
const arrayMethods = Object.create(arrayProto)
;['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(method => {
  arrayMethods[method] = function() {
    arrayProto[method].call(this, ...arguments) // 原始操作
    updateView() // 触发视图更新
  }
})

// 重新定义属性,监听起来
function defineReactive(target, key, value) {
  observer(value) // 进行监听

  // 不可枚举的不用监听
  const property = Object.getOwnPropertyDescriptor(target, key)
  if (property && property.configurable === false) return
  Object.defineProperty(target, key, {
    get() {
      return value
    },
    set(newValue) {
      if (newValue !== value) {
        observer(newValue) // 值修改后进行监听

        // value 一直在闭包中,此处设置完之后,再 get 时也是会获取最新的值
        value = newValue
        updateView() // 触发更新视图
      }
    },
  })
}

// 监测数据的变化
function observer(target) {
  // 不是对象或数组(vue 是判断是否是数组、纯粹对象、可扩展对象)
  if (typeof target !== 'object' || target === null) {
    return target
  }
  // 不要这样写,污染全局的 Array 原型
  /* Array.prototype.push = function () {
      updateView()
  } */
  if (Array.isArray(target)) {
    target.__proto__ = arrayMethods
  }
  // 重新定义各个属性(for in 也可以遍历数组)
  for (let key in target) {
    if (!Object.hasOwnProperty.call(target, key)) return
    defineReactive(target, key, target[key])
  }
}

const data = {
  name: 'zhangsan',
  age: 20,
  info: {
    address: '北京', // 需要深度监听
  },
  nums: [10, 20, 30],
}

observer(data)

data.name = 'lisi'
data.age = 21
data.info.address = '上海' // 深度监听
// data.x = '100' // 新增属性,监听不到 —— 所以有 Vue.set
// delete data.name // 删除属性,监听不到 —— 所有已 Vue.delete
data.nums.push(4) // 监听数组


diff 算法

diff 算法过程:

  • 同级元素进行比较,再比较子节点
  • 先判断一方有子节点,一方没有子节点情况(如果新的 children 没有子节点,将旧的子节点移除)
  • 之后比较都有子节点的情况(核心 diff),递归比较子节点

正常 diff 两个树的时间复杂度是 O(n^3),但实际情况我们很少会跨级移动 DOM。所以,只有当新旧 children 都为多个子节点时才需要核心的 diff 算法进行同层级比较

  • Vue2 核心 diff 算法采用了双端比较的算法,同时从新旧 children 的两端开始比较,借助 key 值找到可复用的节点,再进行相关操作。相比 React 的 diff 算法,同样情况可以减少移动节点次数,减少不必要的性能损耗
  • Vue3 核心 diff 算法采用了最长递增子序列


双端比较算法

  • 使用 旧列表 的头一个节点 oldStartNode 与 新列表 的头一个节点 newStartNode 对比
  • 使用 旧列表 的最后一个节点 oldEndNode 与 新列表 的最后一个节点 newEndNode 对比
  • 使用 旧列表 的头一个节点 oldStartNode 与 新列表 的最后一个节点 newEndNode 对比
  • 使用 旧列表 的最后一个节点 oldEndNode 与 新列表 的头一个节点 newStartNode 对比

树 diff 的时间复杂度 O(n^3)

  • 对于旧树上的点 E 来说,它要和新树上的所有点比较,复杂度为 O(n)
  • 点 E 在新树上没有找到,点 E 会被删除,然后遍历新树上的所有点找到对应点(X)去填空,复杂度增加到 O(n^2)
  • 这样的操作会在旧树的每个点进行,最终复杂度为 O(n^3),1000 个节点,要计算 1 亿次,算法不可用

优化时间复杂度到 O(n)

  • 只比较同一层级,不跨级比较
  • tag 不相同,则直接删掉重建,不再深度比较
  • tag key,两者都相同,则认为是相同节点,不再深度比较

简述 diff 算法过程

在 Vue 中,主要是 patch()patchVnode() updateChildren 这三个方法来实现 Diff 的

  • 当 Vue 中的响应式数据发生变化时,就会触发 updateCompoent()
  • updateComponent() 会调用 patch() 方法,在该方法中进行比较,调用 sameVnode 判断是否为相同节点(判断 key、tag 等静态属性),如果是相同节点的话执行 patchVnode 方法,开始比较节点差异,如果不是相同节点的话,则进行替换操作                                            patch() 接收新旧虚拟 DOM,即 oldVnodevnode
  1. 首先判断 vnode 是否存在,如果不存在,删除旧节点
  2. 如果 vnode 存在,再判断 oldVnode,如果不存在,只需新增整个 vnode 即可
  3. 如果 vnode oldVnode 都存在,判断两者是不是相同节点,如果是,调用 patchVnode() ,对两个节点进行详细比较
  4. 如果两者不是相同节点,只需将 vnode 转换为真实 DOM 替换 oldVnode
  • patchVnode 同样接收新旧虚拟 DOM,即 oldVnodevnode
  1. 首先判断两个虚拟 DOM 是不是全等,即没有任何变动,是的话直接结束函数,否者继续执行
  2. 其次更新节点的属性,接着判断 vnode.text 是否存在,存在的话只需更新节点文本即可,否则继续执行
  3. 判断 vnode oldVnode 是否有孩子节点
    1. 如果两者都有孩子节点,执行 updateChildren() ,进行比较更新
    2. 如果 vnode 有孩子,oldVnode 没有,则直接删除所有孩子节点,并将该文本属性设为空
    3. 如果 oldVnode 有孩子,vnode 没有,则直接删除所有孩子节点
    4. 如果两者都没有孩子节点,就判断 oldVnode.text 是否有内容,有的话情况内容即可
  • updateChildren 接收三个参数:parentElm 父级真实节点、oldCh 为 oldVnode 的孩子节点、newCh 为 Vnode 的孩子节点oldCh 和 newCh 都是一个数组。正常我们想到的方法就是对这两个数组一一比较,时间复杂度为 O(NM)。Vue 中是通过四个指针实现的
  1. 首先是 oldStartVnode newStartVnode 进行比较(两头比较),如果比较相同的话,就可以执行 patchVnode
  2. -如果 oldStartVnode newStartVnode 匹配不上的话,接下来就是 oldEndVnode newEndVnode 做比较了(两尾比较)
  3. 如果两头和两尾比较都不是相同节点的话,就开始交叉比较,首先是 oldStartVnode newEndVnode 做比较(头尾比较)
  4. 如果 oldStartVnode 和 newEndVnode 匹配不上的话,就 oldEndVnode newStartVnode 进行比较(尾头比较)如果这四种比较方法都匹配不到相同节点,才是用暴力解法,针对 newStartVnode 去遍历 oldCh 中剩余的节点,一一匹配

图片来源:图文并茂地来详细讲讲Vue Diff算法

 

Vue 为何是异步渲染,$nextTick 何用

  • 因为如果不采用异步更新,那么每次更新数据都会对当前组件进行重新渲染。异步渲染(合并 data 修改),再更新视图,可以提高渲染性能
class Watcher {
  update() {
    if (this.computed) {
      // ...
    } else if (this.sync) {
      // ...
    } else {
      // 当数据发生变化时会将watcher放到一个队列中批量更新
      queueWatcher(this)
    }
  }
}

const queue: Array<Watcher> = []
let has: { [key: number]: ?true } = {}
let waiting = false
let flushing = false
// 在派发更新时并不会每次修改都触发watcher的回调
export function queueWatcher(watcher: Watcher) {
  const id = watcher.id
  // has对象保证同一个watcher只添加一次
  if (has[id] == null) {
    has[id] = true
    if (!flushing) {
      queue.push(watcher)
    } else {
      let i = queue.length - 1
      while (i > index && queue[i].id > watcher.id) {
        i--
      }
      queue.splice(i + 1, 0, watcher)
    }
    // 通过waiting保证nextTick的调用逻辑只有一次
    if (!waiting) {
      waiting = true
      // 调用nextTick方法 批量的进行更新
      nextTick(flushSchedulerQueue)
    }
  }
}

function flushSchedulerQueue () {
  // 1.因为父组件的创建过程是先于子的,所以watcher的创建也是先父后子,执行顺序也是先父后子
  // 2.用户自定义watcher要优先于渲染watcher执行
  // 3.如果一个组件在父组件watcher执行期间被销毁,那么它对应的watcher执行都可以被跳过
  queue.sort((a, b) => a.id - b.id) // 由小到大
}

  • $nextTick 在 DOM 更新完之后,触发回调,用于获得更新后的 DOM
  • $nextTick 方法主要是使用了 宏任务 和 微任务,定义一个异步方法,多次调用 nextTick 会将方法存入队列中,通过这个异步方法清空当前队列

Vue 2.4 之前都是使用微任务,但是微任务的优先级过高,有些情况下可能会出现比事件冒泡更快的情况,但如果都是用宏任务,有可能会出现渲染的性能问题

新版,默认使用微任务,但在特殊情况下会使用宏任务,比如:v-on

  • 对于实现宏任务,会先判断是否能用 setImmediate,不能的话降级为 MessageChannel ,以上都不行的话就是用 setTimeout
if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
  macroTimerFunc = () => {
    setImmediate(flushCallbacks)
  }
} else if (
  typeof MessageChannel !== 'undefined' &&
  (isNative(MessageChannel) ||
    // PhantomJS
    MessageChannel.toString() === '[object MessageChannelConstructor]')
) {
  const channel = new MessageChannel()
  const port = channel.port2
  channel.port1.onmessage = flushCallbacks
  macroTimerFunc = () => {
    port.postMessage(1)
  }
} else {
  macroTimerFunc = () => {
    setTimeout(flushCallbacks, 0)
  }
}


Vue 常见性能优化方式

  • 合理使用 v-showv-if
  • 合理使用 computed
  • v-for 时加 key(Vue 会进行复用),以及避免和 v-if 同时使用
  • 自定义事件、DOM 事件及时销毁
  • 合理使用异步组件、路由懒加载
  • 合理使用 keep-alive(SPA 页面)
  • data 层级不要太深,不要讲所有数据都放在 data 中(会增加 getter setter,收集对应 watcher
  • 使用 vue-loader 在开发环境做模板编译(预编译)
  • webpack 层面的优化
  • 前端通用的性能优化,如图片懒加载、防抖、节流
  • 使用 SSR

释义参数 vue-template-compiler

render 中的参数释义

_c = createElement
function installRenderHelpers(target) {
  target._o = markOnce
  target._n = toNumber
  target._s = toString
  target._l = renderList
  target._t = renderSlot
  target._q = looseEqual
  target._i = looseIndexOf
  target._m = renderStatic
  target._f = resolveFilter
  target._k = checkKeyCodes
  target._b = bindObjectProps
  target._v = createTextVNode
  target._e = createEmptyVNode
  target._u = resolveScopedSlots
  target._g = bindObjectListeners
  target._d = bindDynamicKeys
  target._p = prependModifier
}

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

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

相关文章

DT DAY3 信号和槽

作业&#xff1a; 1> 思维导图 2> 使用手动连接&#xff0c;将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函数 btn3 new QPushButton("按钮3",this);btn3->resize(ui->btn2->width(),ui->b…

有名管道的大小

管道&#xff1a;有名管道、无名管道 通信&#xff1a; 单工通信&#xff1a;固定的读端和写端 -- 广播 半双工通信&#xff1a;同一时刻&#xff0c;只有有一方写&#xff0c;另外一方读:对讲机 全双工通信&#xff1a;随时两方都能读写 -- 电话 特点&#xff1a; 管道属…

Cosmos收益协议Hover以800%的超额认购结束公开销售

Hover&#xff0c;建立在Cosmos的Kava EVM上的可持续收益生态系统&#xff0c;在其公开销售中积累了超过800万美元的存款。 Hover&#xff0c;Kava EVM上新推出的收益生态系统&#xff0c;已经在顶级加密货币Launchpad DAO Maker上结束了其公开销售。通证销售旨在筹集100万美元…

Shell 脚本系列 | xsync同步脚本的使用

xsync是一个同步脚本&#xff0c;它实际上是对rsync脚本的二次封装&#xff0c;可以简化在多个节点之间同步文件的过程。以下是使用xsync工具的基本步骤&#xff1a; 1.确保已安装rsync。如果没有安装&#xff0c;可以使用以下命令进行安装&#xff1a; yum -y install rsync…

GB28181 —— Ubuntu20.04下使用ZLMediaKit+WVP搭建GB28181流媒体监控平台(连接带云台摄像机)

最终效果 简介 GB28181协议是视频监控领域的国家标准。该标准规定了公共安全视频监控联网系统的互联结构&#xff0c; 传输、交换、控制的基本要求和安全性要求&#xff0c; 以及控制、传输流程和协议接口等技术要求&#xff0c;是视频监控领域的国家标准。GB28181协议信令层面…

umi - react web端 集成腾讯即时通信IM,实现自定义翻译功能

项目使用umi - react 框架 在集成腾讯的IM的时候需要用到自定义翻译功能,调用自己的翻译服务 , 于是进行更改,发现按照官网提示的集成含UI的IM是直接下载依赖,然后引入组件包直接用,在官网上没看到有哪里配置自定义翻译的文档 , 于是咨询客服 最初的思路是在消息的更多选项中…

【Linux网络】网络编程套接字(TCP)

目录 地址转换函数 字符串IP转整数IP 整数IP转字符串IP 关于inet_ntoa 简单的单执行流TCP网络程序 TCP socket API 详解及封装TCP socket 服务端创建套接字 服务端绑定 服务端监听 服务端获取连接 服务端处理请求 客户端创建套接字 客户端连接服务器 客户端…

ubuntu20配置protobuf 2.5.0

python安装protobuf包 sudo pip2 install protobuf2.5.0github克隆获取安装包 wget https://github.com/protocolbuffers/protobuf/releases/download/v2.5.0/protobuf-2.5.0.tar.gz解压并进入该目录 tar -zxvf Protobuf-2.5.0.tar.gz cd protobuf-2.5.0配置安装环境 sudo …

【Vuforia+Unity】AR03-圆柱体物体识别(Cylinder Targets)

1.创建数据库模型 这个是让我们把生活中类似圆柱体和圆锥体的物体进行AR识别所选择的模型 Bottom Diameter:底部直径 Top Diameter:顶部直径 Side Length:圆柱侧面长度 请注意&#xff0c;您不必上传所有三个部分的图片&#xff0c;但您需要先为侧面曲面关联一个图像&#…

Atcoder ABC340 A-D题解

比赛链接:ABC340 话不多说&#xff0c;看题。 Problem A: 签到。 #include <bits/stdc.h> using namespace std; int main(){int a,b,d;cin>>a>>b>>d;for(int ia;i<b;id)cout<<i<<endl;return 0; } Problem B: 还是签到题。一个v…

张宇2025基础三十讲高等数学笔记(数二)

本次主要是根据书课包视频的进程&#xff0c;第1讲的01和02&#xff0c;分为基础知识和书上的例题加上经典1000题对应的相关的知识点 1.基础知识 1&#xff09;函数 2&#xff09;反函数 3&#xff09;复合函数 2.书上例题1000题 1&#xff09;函数 2&#xff09;反函数 3&a…

【Git】:远程仓库操作

远程仓库操作 一.理解版本控制系统二.远程仓库1.克隆2.Push操作3.fetch操作4. .gitnore文件 一.理解版本控制系统 我们⽬前所说的所有内容&#xff08;⼯作区&#xff0c;暂存区&#xff0c;版本库等等&#xff09;&#xff0c;都是在本地&#xff01;也就是在你的笔记本或者计…

杂题——1097: 蛇行矩阵

题目描述 蛇形矩阵是由1开始的自然数依次排列成的一个矩阵上三角形。 输入格式 本题有多组数据&#xff0c;每组数据由一个正整数N组成。&#xff08;N不大于100&#xff09; 输出格式 对于每一组数据&#xff0c;输出一个N行的蛇形矩阵。两组输出之间不要额外的空行。矩阵三角…

猜字谜|构建生成式 AI 应用实践(一)

在 2023 亚马逊云科技 re:Invent 之后&#xff0c;细心的开发者们也许已经发现有一个很有趣的动手实验&#xff1a;开发一款可部署的基于大语言模型的字谜游戏&#xff1a; 该款游戏使用了文生图模型为玩家提供一个未知的提示词&#xff0c;玩家需要根据模型生成的图像来猜测该…

Covalent Network(CQT)与 Movement Labs 达成合作,重新定义 M2 系统区块链数据可用性与性能

Covalent Network&#xff08;CQT&#xff09;是行业领先的多链索引器&#xff0c;正在与 Movement Labs 的 M2 展开具有突破性意义的合作。M2 是以太坊上的首个 Move-EVM&#xff08;MEVM&#xff09;ZK rollup 。这一战略合作标志着先进的实时数据索引和部署工具&#xff0c;…

如何实现H5和小程序之间相互跳转

嗨&#xff0c;各位小伙伴们&#xff0c;我是你们的好朋友咕噜铁蛋&#xff01;今天&#xff0c;我要和大家分享一下关于如何实现H5和小程序之间相互跳转的话题。随着移动互联网的发展&#xff0c;H5网页和小程序已经成为了我们日常生活中不可或缺的一部分。那么&#xff0c;如…

SD-WAN组网:打造跨国企业无缝网络连接体验

在数字化转型的时代&#xff0c;越来越多的企业迈向国际化&#xff0c;然而&#xff0c;由于自建网络架构的限制和跨域网络的复杂性&#xff0c;企业在不同地理位置的站点之间难以实现高效的数据互通和协作。这就是为什么SD-WAN成为跨国企业组网的理想选择的原因。 跨国企业常见…

vue中使用wangEditor富文本编辑器

jsd-2306-vue-01: 教学项目教学项目教学项目教学项目教学项目 2306-vue-baking-teacher: 教学项目教学项目教学项目教学项目 一、脚手架工程中使用富文本编辑器wangEditor 1.通过以下命令 安装wangEditor npm i wangeditor -S 2.在main.js文件中添加以下配置信息 //引入wa…

python 打包 apk

转换之前python代码需要使用指定的框架才能转换&#xff0c;列如&#xff1a;kivy from kivy.app import App from kivy.uix.boxlayout import BoxLayout from kivy.uix.button import Buttonimport time import pyautogui import threadingstatus False# 这是一个将被线程执…

[ 云计算 | AWS 实践 ] Java 应用中使用 Amazon S3 进行存储桶和对象操作完全指南

本文收录于【#云计算入门与实践 - AWS】专栏中&#xff0c;收录 AWS 入门与实践相关博文。 本文同步于个人公众号&#xff1a;【云计算洞察】 更多关于云计算技术内容敬请关注&#xff1a;CSDN【#云计算入门与实践 - AWS】专栏。 本系列已更新博文&#xff1a; [ 云计算 | …