vue2源码分析-vue入口文件global-api分析

文章背景

  • vue项目开发过程中,首先会有一个初始化的流程,以及我们会使用到很多全局的api,如 this.$set this.$delete this.$nextTick,以及初始化方法extend,initUse, initMixin , initExtend, initAssetRegisters 等等那它们是怎么实现,让我们一起来探究下吧

源码目录

  • 在这里插入图片描述

global-api代码初始化

  • 代码路径 src\vue-2.6.14\src\core\global-api\index.js

代码分析

vue挂载的全局属性

  • vue.util 公共方法
    • warn 代码警告处理
    • extend 将源数据中的值拷贝到目标数据中
    • mergeOptions 合并选项
    • defineReactive 定义响应式数据
  • set set 方法,修改对象的某个属性,以更新视图
  • del del 方法,删除数组的某个索引下的数据 或者 对象的某个属性
  • nextTick nextTick方法
  • observable 调用observer类的observe方法,将对象变为响应式对象,并且返回该响应式对象
  • options vue的一些选项

初始化方法

  • extend
    • extend函数此处用于扩展,将源数据中的值拷贝到目标数据中,数据类型兼容到了 对象和数组
  • initUse
    • 初始化插件
  • initMixin
    • 初始化混入 逻辑有点多,后期详细补充
  • initExtend
    • 构造一个vue的子类
  • initAssetRegisters(Vue)
    • 注册或者获取全局组件、指令、过滤器
/* @flow */import config from '../config'
import { initUse } from './use'
import { initMixin } from './mixin'
import { initExtend } from './extend'
import { initAssetRegisters } from './assets'
import { set, del } from '../observer/index'
import { ASSET_TYPES } from 'shared/constants'
import builtInComponents from '../components/index'
import { observe } from 'core/observer/index'import {warn,extend,nextTick,mergeOptions,defineReactive
} from '../util/index'
export function initGlobalAPI(Vue: GlobalAPI) {// note 初始化全局api sjf-step2debuggerconst configDef = {}configDef.get = () => config// 初始化vue的全局config配置if (process.env.NODE_ENV !== 'production') {configDef.set = () => {// set在修改对象的字段时触发,此处表示在设置 Vue的config属性时触发warn('Do not replace the Vue.config object, set individual fields instead.')}//在开发环境中,不允许替换整个Vue.config 对象,只允许设置单独的字段}Object.defineProperty(Vue, 'config', configDef)// // exposed util methods.// NOTE: these are not considered part of the public API - avoid relying on// them unless you are aware of the risk.Vue.util = {//将全局方法,挂载到Vue的util方法上warn,extend,mergeOptions,defineReactive}Vue.set = set// set 方法,修改对象的某个属性,以更新视图Vue.delete = del // del 方法,删除数组的某个索引下的数据 或者 对象的某个属性Vue.nextTick = nextTick // nextTick方法// set delete nextTick 除了可以使用 this.$set,this.$delete,this.$nextTick调用,亦可以在Vue实例上直接调用// 2.6 explicit observable APIVue.observable = (obj) => {observe(obj)// 调用observer类的observe方法,将对象变为响应式对象return obj//并且返回该响应式对象}Vue.options = Object.create(null)//调用 Object.create(null) 创建一个没有原型链的空对象ASSET_TYPES.forEach(type => {Vue.options[type + 's'] = Object.create(null)})// ASSET_TYPES = ['component','directive','filter'] // 遍历ASSET_TYPES数组,给Vue.options添加三个属性,分别是components,directives,filters// this is used to identify the "base" constructor to extend all plain-object// components with in Weex's multi-instance scenarios.Vue.options._base = Vue// 将vue赋值给Vue.options._base,用于在weex的多实例场景下,标识“基础”构造函数,以扩展所有纯对象组件extend(Vue.options.components, builtInComponents)// 将builtInComponents对象的属性,复制到Vue.options.components上// extend函数此处用于扩展initUse(Vue)//初始化插件initMixin(Vue)//初始化混入 逻辑有点多,后期详细补充initExtend(Vue)//构造一个vue的子类 initAssetRegisters(Vue) // 注册或者获取全局组件、指令、过滤器
}

extend 扩展数据

  • 代码路径 src\vue-2.6.14\src\shared\util.js
  • extend函数此处用于扩展,将源数据中的值拷贝到目标数据中,数据类型兼容到了 对象和数组
  • 入参说明
    • to 目标值,_from 源数据
  • 核心代码说明
    • const key in _from
    • _from 可以是一个数组 ,也可以是一个对象
    • 如果是数组,则key是数组的索引
    • 如果是对象,则key是对象的键值
export function extend (to: Object, _from: ?Object): Object {// sjf-note-best-code// 将源数据中的值拷贝到目标数据中,数据类型兼容到了 对象和数组for (const key in _from) {// const key in _from // _from 可以是一个数组 ,也可以是一个对象// 如果是数组,则key是数组的索引// 如果是对象,则key是对象的键值to[key] = _from[key]}//当我们还在苦逼地用 Array.isArray 判断数据类型是否是数组来区分代码写两套逻辑时, vue源代码已经实现了,一个代码同时兼容了数组和对象的拷贝,简直不要太优秀啊return to
}
  • 优秀代码设计思想
    • 当我们还在苦逼地用 Array.isArray 判断数据类型是否是数组来区分代码写两套逻辑时, vue源代码已经实现了,一个代码同时兼容了数组和对象的拷贝,简直不要太优秀啊

initUse 初始化插件

  • 代码路径 src\vue-2.6.14\src\core\global-api\use.js
  • 入参说明
  • plugin 参数 有可能是函数也有能是对象
    • 当是对象时需要访问install属性并且使用apply修改this为plugin后调用
    • 当是函数时则直接调用
  • 核心代码说明
  • installedPlugins
    • 定义 installedPlugins 参数,
    • 读取vue实例上的_installedPlugins属性,如果读取不到则赋值为空数组
    • 缓存插件,将插件添加到已安装插件的数组中
  • 防止插件的重复加载
    • 如果插件已经安装,则将插件直接返回
import { toArray } from '../util/index'export function initUse (Vue: GlobalAPI) {Vue.use = function (plugin: Function | Object) {const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))// _installedPlugins 函数内部的变量 用来存储已经注册的插件// _installedPlugins 不存在时,初始化为一个空数组// vue源码中并没有声明 _installedPlugins 并且此处是非箭头函数if (installedPlugins.indexOf(plugin) > -1) {// 防止插件的重复加载return this}const args = toArray(arguments, 1)// toArray 方法将参数转化为数组// arguments 是一个类数组对象,有length属性,但是没有数组的方法// 通过toArray方法将arguments转化为数组,并且去掉第一个参数args.unshift(this)//再将this添加到args数组的头部if (typeof plugin.install === 'function') {// 如果插件有install方法,则调用install方法plugin.install.apply(plugin, args)} else if (typeof plugin === 'function') {// 如果插件是一个函数,则直接调用plugin.apply(null, args)}installedPlugins.push(plugin)//缓存插件,将插件添加到已安装插件的数组中return this}
}

initMixin 初始化混入

  • 初始化混入 逻辑有点多,后期单独出一篇文章详细补充

initExtend 初始化vue组件对象

  • 代码路径 src\vue-2.6.14\src\core\global-api\extend.js
    函数说明
  • 基于构造函数Vue,创建了一个Vue组件对象,并初始化vue选项式api
    核心代码说明
  • 获取父类的cid,也就是组件的id,即组件的标识
  • cachedCtors,定义一个缓存对象
    • 如果缓存对象中已经有了当前类的id,则表明在此操作前已经创建过了
    • 通过id访问到缓存对象中的子类,并直接返回
    • 这样做可以提高性能,避免重复的子类创建
  • 获取到组件的name属性
    • 如果当前传入的组件选项中有name属性则直接读取,否则访问Super(父类的)name属性
    • name是组件的标识,一般确实永不到,但是组件递归的时候必须要写,否则无法调用子组件
  • 调用validateComponentName校验name属性是否合法
  • sub类的处理
    • 通过函数的方式创建一个sub类,并将父类的原型链继承到子类中(原型链继承方式),同时还需要修正constructor的指向
    • 将父类的options字段和传入组件对象选项进行合并,并保存在子类sub的options字段中
    • 将父类保存到子类的 super 字段中,确保子类能拿到父类
  • 初始化 props
    • props 是当前组件的props属性
    • const in props 遍历对象的属性
    • 将 组件传入的props属性代理到组件实例的_props属性上
    • 初始化 computed
    • computed 是当前组件的computed属性
    • const in props 遍历对象的属性
    • defineComputed 逻辑暂时没看,后期单独出一期文章补充
  • extend,mixin,use等api添加到子类中
  • 新增 superOptions,extendOptions,sealedOptions等选项
  • 将子类返回
/* @flow */import { ASSET_TYPES } from 'shared/constants'
import { defineComputed, proxy } from '../instance/state'
import { extend, mergeOptions, validateComponentName } from '../util/index'export function initExtend (Vue: GlobalAPI) {/*** Each instance constructor, including Vue, has a unique* cid. This enables us to create wrapped "child* constructors" for prototypal inheritance and cache them.*/// sjf-note-best-codeVue.cid = 0//初始化cid为0 可以理解为组件的标识let cid = 1 /*** Class inheritance*/Vue.extend = function (extendOptions: Object): Function {// 基于构造函数Vue,创建了一个Vue组件对对象,并初始化vue选项式apiextendOptions = extendOptions || {}// extendOptions是一个对象,如果没有传入,则初始化为空对象// extendOptions 是组件传入的选项const Super = this//将this(vue的实例)赋值给Superconst SuperId = Super.cidconst cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})//定义一个缓存对象,用生成的id作为属性键,如果cachedCtors[SuperId]存在则表明该组件的构造函数已经生成,直接返回即可if (cachedCtors[SuperId]) {return cachedCtors[SuperId]}const name = extendOptions.name || Super.options.name// extendOptions 当前组件的选项 的 // Super 是 Vue的实例 options 是Vue的选项// 如果传入了extendOptions.name 则使用extendOptions.name 否则使用Super.options.nameif (process.env.NODE_ENV !== 'production' && name) {//判断是否是开发环境validateComponentName(name)//校验组件名称是否合法, 如果不合法会抛出异常}const Sub = function VueComponent (options) {this._init(options)//此处的this是vue实例 ,调用了_init方法,初始化组件实例}Sub.prototype = Object.create(Super.prototype)// Super.prototype 是Vue的原型对象// Object.create(Super.prototype) 创建了一个新的对象,该对象的原型是Super.prototype// Object.create() 方法创建一个新对象,不会有原型链上的属性和方法Sub.prototype.constructor = Sub// consturctor指向自身 sjf-todo// 通过函数的方式创建一个sub类,并将父类的原型链继承到子类中(原型链继承方式),同时还需要修正constructor的指向Sub.cid = cid++//组件的cid自增1Sub.options = mergeOptions(//将父类的options字段和传入组件对象选项进行合并,并保存在子类sub的options字段中Super.options,//Vue的选项extendOptions//当前组件的选项)Sub['super'] = Super//将Super(根组件的实例)赋值给当前组件的super属性
// 将父类保存到子类的 super 字段中,确保子类能拿到父类// For props and computed properties, we define the proxy getters on// the Vue instances at extension time, on the extended prototype. This// avoids Object.defineProperty calls for each instance created.if (Sub.options.props) {//如果当前组件有props属性,则初始化propsinitProps(Sub)  }if (Sub.options.computed) {//如果当前组件有computed属性,则初始化computedinitComputed(Sub)}// allow further extension/mixin/plugin usageSub.extend = Super.extendSub.mixin = Super.mixinSub.use = Super.use
// Vue的一些原生API 等扩展到子构造器上边// create asset registers, so extended classes// can have their private assets too.ASSET_TYPES.forEach(function (type) {Sub[type] = Super[type]})// enable recursive self-lookupif (name) {Sub.options.components[name] = Sub}// keep a reference to the super options at extension time.// later at instantiation we can check if Super's options have// been updated.Sub.superOptions = Super.optionsSub.extendOptions = extendOptionsSub.sealedOptions = extend({}, Sub.options)
// Vue的一些原生API 等扩展到子构造器上边// cache constructorcachedCtors[SuperId] = Subreturn Sub}
}function initProps (Comp) {const props = Comp.options.props// props 是当前组件的props属性for (const key in props) {  // const in props 遍历对象的属性proxy(Comp.prototype, `_props`, key)// proxy 代理数据// 此处是将 组件传入的props属性代理到组件实例的_props属性上}
}function initComputed (Comp) {const computed = Comp.options.computed// computed 是当前组件的computed属性for (const key in computed) {// const in computed 遍历对象的属性defineComputed(Comp.prototype, key, computed[key])// defineComputed 代理数据// 此处是将 组件传入的computed属性代理到组件实例的_props属性上}
}

initAssetRegisters 注册或者获取全局组件、指令、过滤器

  • src\vue-2.6.14\src\core\global-api\assets.js
    函数说明
  • 注册或者获取全局 component 组件、directive指令、 filter 过滤器
    函数入参说明
  • id 标识名称id
  • definition 定义类型是函数或者对象
    • 当type 是directive或者filter的时候,是函数
    • 当type是components的时候是,对象
      核心代码说明
  • 判断是是否有传入 definition 参数
    • 无则表明不是注册全局组件、指令、过滤器,而直接读取,直接通过标识名称id读取返回即可
    • 有则标明是注册
  • 校验组件名是否合规
    • 非生产环境 并且type值是component组件名称,则需要校验组件名是否合规
    • 如果不合规则在 validateComponentName函数中抛出异常,下文有说明
  • 根据type类型分别做逻辑处理
  • component
  • type为 component,并且 isPlainObject 判断 definition类型是 object,则执行下边逻辑
    • 读取 name 属性,如果读不到definition的name属性,则使用标识名称id
    • 调用 vue 的extend扩展定义,并重新赋值
  • directive
    • type值为 directive ,并且 definition的类型为 function
    • 定义一个对象有bindupdate属性,赋值为definition
  • 以上逻辑处理好了directive和component选项下的definition,filter选项不需要特殊处理
  • 根据选项式api对象读取到指定id的component 组件、directive指令、 filter 过滤器并赋值为 definition
  • 将 definition返回给调用者
/* @flow */import { ASSET_TYPES } from 'shared/constants'
import { isPlainObject, validateComponentName } from '../util/index'export function initAssetRegisters (Vue: GlobalAPI) {/*** Create asset registration methods.*//* 'component','directive','filter'*/
//   注册或者获取全局组件、指令、过滤器debuggerASSET_TYPES.forEach(type => {//定义资源注册方法Vue[type] = function (id: string,//标识名称iddefinition: Function | Object//定义函数或者对象 // 当type 是directive或者filter的时候,是函数// 当type是components的时候是,对象): Function | Object | void {// console.log("id_definition",type,id,definition)if (!definition) {// 没有传入definition 的时候,则之直接读取并返回return this.options[type + 's'][id]} else {/* istanbul ignore if */if (process.env.NODE_ENV !== 'production' && type === 'component') {// 非生产环境 交易案组件名称,如果不合规,则抛出异常validateComponentName(id)}if (type === 'component' && isPlainObject(definition)) {definition.name = definition.name || id//设置 definition.name属性 // 值为组件传入的name || iddefinition = this.options._base.extend(definition)// 调用 vue 的extend扩展定义,并重新赋值}if (type === 'directive' && typeof definition === 'function') {definition = { bind: definition, update: definition }// 自定义指令的处理逻辑}this.options[type + 's'][id] = definitionreturn definition}}})
}

源码中使用到的小代码片段补充

ASSET_TYPES

export const ASSET_TYPES = ['component','directive','filter'
]

proxy代理函数

  • 代码引用地址 src\vue-2.6.14\src\core\instance\state.js
  • 使用defineProperty代理数据
const sharedPropertyDefinition = {//代理数据的配置enumerable: true,//是否可枚举configurable: true,//是否可修改删除get: noop,//get方法,用于读取数据 noop 定义一个临时的空的函数set: noop//set方法,用于设置数据 noop 定义一个临时的空的函数
}export function proxy (target: Object, sourceKey: string, key: string) {//  代理数据sharedPropertyDefinition.get = function proxyGetter () {return this[sourceKey][key] //返回数据}sharedPropertyDefinition.set = function proxySetter (val) {this[sourceKey][key] = val//设置数据}Object.defineProperty(target, key, sharedPropertyDefinition)// 通过Object.defineProperty方法,将sharedPropertyDefinition的get和set方法绑定到target对象的key属性上
}

toArray 将目标数组中的数据,从指定位置开始拷贝

  • 代码引用地址 src\vue-2.6.14\src\shared\util.js
  • 将目标数组中的数据,从指定位置开始拷贝

代码实现原理

  1. 接收字段
    • list 源数据
    • start 从源数据的哪个位置开始拷贝 默认为 0
  1. 声明一个变量i值为 list.length - start
  2. while 循环
    • 然后将 i + start
    • 则 最后的 i + start 仍然等于 list.length
    • 当i的值为0时,循环结束
  1. 则实现了将原数组从指定位置拷贝到目标数组的操作
    代码优秀设计思想分析,它凭什么优秀
  2. 第一点,一般拷贝数组,
  • 常规的操作就是 for 循环,遍历数组中的每一个数据,然后根据条件判断,将数组中满足条件的数据拿到或者将不满足条件的数据过滤掉,这样确实能够处理数据,但是却需要将每条数据都循环一遍 .
  • 优秀的写法 此处,使用了while循环,不需要循环每一条数据,在调件变量为false的时候就跳出了循环,提高了代码的执行效率
  1. 可拷贝从指定位置开始的数据
  2. 语法层面上使用了 new Array(i)
  • 创建了指定数组,并且指定了位数,同时生明其中的每个变量都为empty
  • 很多人都知道new Array 却不知道 可以传入个数参数

当我们还开为这中需求苦恼,并且写一堆js时,vue源码中已经写出来如此优秀的代码,值得参考

export function toArray (list: any, start?: number): Array<any> {// sjf-note-best-codestart = start || 0let i = list.length - startconst ret: Array<any> = new Array(i)// new Array() 创建一个空数组// new Array(i) 创建i个为空的数组// 相当于 Array.fill(0,i,undefined)while (i--) {ret[i] = list[i + start]//先将 i = list.length - start // 然后将 i + start // 则 最后的 i + start 仍然等于 list.length// 只不过是i 的值是从 list.length - start 到 0 递减// 当i的值为0时,循环结束}// while循环的优点是,即即使数组的数据没有处理完成,并且不需要break或者return false 以及 throw new Error()来结束循环,就可以自动结束循环return ret// 将处理好的数组返回
}

isPlainObject

  • 代码引用地址 src\vue-2.6.14\src\shared\util.js
  • 判断 数据类型是否是 object
export function isPlainObject (obj: any): boolean {return _toString.call(obj) === '[object Object]'
}

validateComponentName

  • 代码引用地址 src\vue-2.6.14\src\core\util\options.js
  • 校验组件名是否合法
export function validateComponentName (name: string) {if (!new RegExp(`^[a-zA-Z][\\-\\.0-9_${unicodeRegExp.source}]*$`).test(name)) {warn('Invalid component name: "' + name + '". Component names ' +'should conform to valid custom element name in html5 specification.')}if (isBuiltInTag(name) || config.isReservedTag(name)) {// warn('Do not use built-in or reserved HTML elements as component ' +'id: ' + name)}
}

isBuiltInTag 判断组件名是不是Vue内置的

  • 引用地址 src\vue-2.6.14\src\shared\util.js
export const isBuiltInTag = makeMap('slot,component', true)
// 判断组件名是不是内置的标签,不是原生html的标签而是vue内置的标签

isReservedTag

- 判断是否是 原生html或者isSVG标签 
export const isReservedTag = (tag: string): ?boolean => {return isHTMLTag(tag) || isSVG(tag)
}
export const isHTMLTag = makeMap('html,body,base,head,link,meta,style,title,' +'address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,' +'div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,' +'a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,' +'s,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,' +'embed,object,param,source,canvas,script,noscript,del,ins,' +'caption,col,colgroup,table,thead,tbody,td,th,tr,' +'button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,' +'output,progress,select,textarea,' +'details,dialog,menu,menuitem,summary,' +'content,element,shadow,template,blockquote,iframe,tfoot'
)
export const isSVG = makeMap('svg,animate,circle,clippath,cursor,defs,desc,ellipse,filter,font-face,' +'foreignobject,g,glyph,image,line,marker,mask,missing-glyph,path,pattern,' +'polygon,polyline,rect,switch,symbol,text,textpath,tspan,use,view',true
)

致谢

  • 感谢vue源码给予了我学习借鉴的机会
  • 感谢日常项目中给我的锻炼
  • 这篇文章是vue初始化流程的代码,其实没什么难度,但是这是最开始的一步,无法跳过,后期会有核心代码的分析,如果感兴趣请关注

  • 感谢您百忙之中抽时间阅读我写的博客,谢谢你的肯定,也希望对您能有所帮助
  • 如果您有更好的见解请在评论区留言或者私聊我,期待与您的交流

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

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

相关文章

Windows下 OracleXE_21 数据库的下载与安装

Oracle 数据库的下载与安装 数据库安装包下载数据库安装访问数据库进行测试Navicat连接数据库 1. 数据库安装包的下载 1.1 下载地址 Oracle Database Express Edition | Oracle 中国 1.2 点击“下载 Oracle Database XE”按钮&#xff0c;进去到下载页面&#xff08;选择对…

Stable diffusion零基础课程

该课程专为零基础学习者设计&#xff0c;旨在介绍和解释稳定扩散的基本概念。学员将通过简单易懂的方式了解扩散现象、数学模型及其应用&#xff0c;为日后更深入的科学研究和工程应用打下坚实基础。 课程大小&#xff1a;3.8G 课程下载&#xff1a;https://download.csdn.ne…

灵魂指针,教给(一)

欢迎来到白刘的领域 Miracle_86.-CSDN博客 系列专栏 C语言知识 先赞后看&#xff0c;已成习惯 创作不易&#xff0c;多多支持&#xff01; 一、内存和地址 1.1 内存 在介绍知识之前&#xff0c;先来想一个生活中的小栗子&#xff1a; 假如把你放在一个有100间屋子的酒店…

第三讲 汇编初步 课程随手记

一、寄存器 32位CPU通用寄存器如下图所示&#xff1a; 因为教材依照的是32位CPU寄存器&#xff0c;而我安装的是64位寄存器&#xff0c;所以找了一下64位的寄存器的资料 PS&#xff1a;一般来说&#xff0c;Intel处理器字节存储顺序为小端法存储&#xff0c;是指数据的高字节保…

基于Skywalking开发分布式监控(四)一个案例

上一篇我们简单介绍了基于SkyWalking自定义增强的基本架构&#xff0c;即通过把Trace数据导入数据加工模块进行加工&#xff0c;进行持久化&#xff0c;并赋能grafana展示。 现在我们给出一个例子&#xff0c;对于量化交易系统&#xff0c;市场交易订单提交&#xff0c;该订单…

关于springboot一个接口请求后,主动取消后,后端是否还在跑

1、最近在思考一个问题&#xff0c;如果一个springboot的请求的接口比较耗时&#xff0c;中途中断该请求后&#xff0c;则后端服务是否会终止该线程的处理&#xff0c;于是写了一个demo RequestMapping(value "/test", method RequestMethod.GET)public BasicResul…

云消息队列 Confluent 版正式上线!

作者&#xff1a;阿里云消息队列 前言 在 2023 年杭州云栖大会上&#xff0c;Confluent 成为阿里云技术合作伙伴&#xff0c;在此基础上&#xff0c;双方展开了深度合作&#xff0c;并在今天&#xff08;3月1日&#xff09;正式上线“云消息队列 Confluent 版”。 通过将 Co…

android基础学习

从上面的描述就可以知道&#xff0c;每一个Activity组件都有一个对应的ViewRoot对象、View对象以及WindowManager.LayoutParams对象。这三个对象的对应关系是由WindowManagerImpl类来维护的。具体来说&#xff0c;就是由WindowManagerImpl类的成员变量mRoots、mViews和mParams所…

【Apache Camel】基础知识

【Apache Camel】基础知识 Apache Camel是什么Apache Camel基本概念和术语CamelContextEndpointsRoutesRouteBuilderComponentsMessageExchangeProcessorsDomain Specific Language&#xff08;DSL&#xff09; Apache Camel 应用执行步骤Apache Camel 示意图参考 Apache Camel…

学习Java的第一天

一、Java简介 Java 是由 Sun Microsystems 公司于 1995 年 5 月推出的 Java 面向对象程序设计语言和 Java 平台的总称。由 James Gosling和同事们共同研发&#xff0c;并在 1995 年正式推出。 后来 Sun 公司被 Oracle &#xff08;甲骨文&#xff09;公司收购&#xff0c;Jav…

【AAAI2023】基于神经跨度的持续命名实体识别模型

论文标题&#xff1a;A Neural Span-Based Continual Named Entity Recognition Model 论文链接&#xff1a;https://arxiv.org/abs/2302.12200 代码&#xff1a;https://github.com/Qznan/SpanKL inproceedings{zhang2023spankl,title{A Neural Span-Based Continual Named En…

ElevenLabs用AI为Sora文生视频模型配音 ,景联文科技提供高质量真人音频数据集助力生成逼真音效

随着Open AI公司推出的Sora文生视频模型惊艳亮相互联网&#xff0c;AI语音克隆创企ElevenLabs又为Sora的演示视频生成了配音&#xff0c;所有的音效均由AI创造&#xff0c;与视频内容完美融合。 ElevenLabs的语音克隆技术能够从一分钟的音频样本中创建逼真的声音。为了实现这一…

RPC——远程过程调用

一、RPC介绍 1.1 概述 RPC&#xff08;Remote Procedure Call Protocol&#xff09; 远程过程调用协议。RPC是一种通过网络从远程计算机程序上请求服务&#xff0c;不需要了解底层网络技术的协议。RPC主要作用就是不同的服务间方法调用就像本地调用一样便捷。 1.2 RPC框架 …

QT----在编译器里能够连接云端数据库,使用windeployqt打包后运行程序,链接不上云端mysql数据库

问题描述 在编译器里能够连接云端数据库&#xff0c;使用windeployqt打包后运行程序&#xff0c;链接不上云端mysql数据库&#xff0c;困扰了好几天 打包发布手机上的app还是无法连接 问题解决 打包的时候没有将这个文件放入&#xff0c;我们复制放到exe的目录即可

redis原理深入解析之看完这篇还需要努力

数据结构 动态字符串SDS struct __attribute__ ((__packed__)) sdshdr8 {uint8_t len; /*已保存的字节数 不含结束标识 header*/uint8_t alloc; /*申请总的字节数&#xff0c;不含结束标识 header*/unsigned char flags;/*不同sds头类型&#xff0c;控制sds头大小 header*/…

【AI视野·今日Robot 机器人论文速览 第八十二期】Tue, 5 Mar 2024

AI视野今日CS.Robotics 机器人学论文速览 Tue, 5 Mar 2024 Totally 63 papers &#x1f449;上期速览✈更多精彩请移步主页 Interesting: &#x1f4da;双臂机器人拧瓶盖, (from 伯克利) website: https://toruowo.github.io/bimanual-twist &#x1f4da;水下抓取器, (from …

Dynamo初学尝试梳理(五)-代码块上

“学而时习之&#xff0c;不亦说乎”&#xff0c;今天接着来&#xff0c;稍微提高点难度&#xff08;高手直接忽略就行&#xff09;。 代码块&#xff08;Code Block&#xff09;&#xff0c;是 dynamo 中可以直接输入 DesignScript 的节点。可以通过双击鼠标左键&#xff0c;快…

程序员书单推荐:从入门到精通的必读之作

在程序员的职业生涯中&#xff0c;阅读技术书籍是不断学习和提升自我的重要途径。本文将为你推荐一系列从入门到精通的程序员书单&#xff0c;帮助你系统地掌握编程知识、提高技能水平&#xff0c;并在职业生涯中取得更大的进步。 一、入门篇 《Head First C语言》&#xff1…

基于SpringBoot+Vue+ElementUI+Mybatis前后端分离管理系统超详细教程(一)

Vue.js 是一个流行的前端框架&#xff0c;用于构建用户界面和单页应用程序。Vue 2 是其第二个主要版本&#xff0c;它提供了数据绑定、组件化、虚拟DOM等核心特性。要搭建一个 Vue 2 的工程化项目&#xff0c;可以遵循以下步骤&#xff1a; 一、前端环境搭建 &#xff08;一&a…

Maven入门(作用,安装配置,Idea基础maven,Maven依赖,Maven构建项目)【详解】

目录 一. Maven的作用 1.依赖管理 2.统一项目结构 3.项目构建 二.Maven安装配置 1. Maven的仓库类型 2 加载jar的顺序 3. Maven安装配置 4.安装Maven 5.配置仓库 三.idea集成maven 1.给当前project集成maven 2.给新建project集成maven 3.创建maven项目 4.pom…