【pinia源码】系列文章主要分析pinia的实现原理。该系列文章源码参考pinia v2.0.14。
源码地址:https://github.com/vuejs/pinia
本篇文章将分析createPinia的实现。
通过createPinia创建一个pinia实例,供应用程序使用。
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const pinia = createPinia()
const app = createApp(App)
app.use(pinia).mount('#app')
createPinia不接受任何参数,它会返回一个pinia实例。
源码位置:packages/pinia/src/createPinia.ts
export function createPinia(): Pinia {
const scope = effectScope(true)
const state = scope.run<Ref<Record<string, StateTree>>>(() =>
ref<Record<string, StateTree>>({})
)!
let _p: Pinia['_p'] = []
let toBeInstalled: PiniaPlugin[] = []
const pinia: Pinia = markRaw({
install(app: App) {
setActivePinia(pinia)
if (!isVue2) {
pinia._a = app
app.provide(piniaSymbol, pinia)
app.config.globalProperties.$pinia = pinia
if (__DEV__ && IS_CLIENT) {
registerPiniaDevtools(app, pinia)
}
toBeInstalled.forEach((plugin) => _p.push(plugin))
toBeInstalled = []
}
},
use(plugin) {
if (!this._a && !isVue2) {
toBeInstalled.push(plugin)
} else {
_p.push(plugin)
}
return this
},
_p,
_a: null,
_e: scope,
_s: new Map<string, StoreGeneric>(),
state,
})
if (__DEV__ && IS_CLIENT && !__TEST__) {
pinia.use(devtoolsPlugin)
}
return pinia
}
在createPinia中首先会创建一个effect作用域对象(如果你不了解effectScope,可参考:RFC),使用ref创建一个响应式对象。紧接着声明了两个数组_p、toBeInstalled,其中_p用来存储扩展store的所有插件,toBeInstalled用来存储那些未install之前使用pinia.use()添加的的plugin。
// 创建effect作用域
const scope = effectScope(true)
// 创建响应式对象
const state = scope.run<Ref<Record<string, StateTree>>>(() =>
ref<Record<string, StateTree>>({})
)!
// 存储扩展store的plugin
let _p: Pinia['_p'] = []
// install之前,使用pinia.use()添加的plugin
let toBeInstalled: PiniaPlugin[] = []
然后声明一个pinia对象(这个pinia会使用markRaw进行包装,使其不会转为proxy),将其return。
const pinia: Pinia = markRaw({
install(app: App) {
// ...
},
use(plugin) {
// ...
},
// 扩展store的plugins
_p,
// app实例
_a: null,
// effecet作用域对象
_e: scope,
// 在这个pinia中注册的stores
_s: new Map<string, StoreGeneric>(),
state,
})
if (__DEV__ && IS_CLIENT && !__TEST__) {
pinia.use(devtoolsPlugin)
}
return pinia
这里重点看下install和use方法。
当使用app.use(pinia)时,触发pinia.install函数。在install中首先执行了setActivePinia(pinia),它会将pinia赋给一个activePinia的全局变量。
然后会判断是不是Vue2环境。如果不是Vue2,将app实例赋给pinia._a,然后将pinia注入到app实例,并将pinia设置为全局属性$pinia。如果此时toBeInstalled中有plugins(在install之前添加的plugins),那么会把这些plugins添加到pinia._p中,添加完之后,置空toBeInstalled。
install(app: App) {
setActivePinia(pinia)
if (!isVue2) {
pinia._a = app
app.provide(piniaSymbol, pinia)
app.config.globalProperties.$pinia = pinia
if (__DEV__ && IS_CLIENT) {
registerPiniaDevtools(app, pinia)
}
toBeInstalled.forEach((plugin) => _p.push(plugin))
toBeInstalled = []
}
}
使用use方法可添加一个plugin以扩展每个store。它接收一个plugin参数,返回当前pinia。
如果this._a是空的,并且不是Vue2环境,会将plugin中暂存到toBeInstalled中,等待install时进行安装。否则,直接添加到this._p中。
use(plugin) {
if (!this._a && !isVue2) {
toBeInstalled.push(plugin)
} else {
_p.push(plugin)
}
return this
}
你可能有疑问,在install、use中都判断了Vue2的情况,难道pinia没有处理Vue2的情况吗?其实并不是,pinia提供了PiniaVuePlugin专门用来处理Vue2的情况。
如果是Vue2需要使用如下方式:
Vue.use(PiniaVuePlugin)
const pinia = createPinia()
new Vue({
el: '#app',
pinia,
})
我们来看下PiniaVuePlugin的实现方式。
export const PiniaVuePlugin: Plugin = function (_Vue) {
// Equivalent of
// app.config.globalProperties.$pinia = pinia
_Vue.mixin({
beforeCreate() {
const options = this.$options
if (options.pinia) {
const pinia = options.pinia as Pinia
if (!(this as any)._provided) {
const provideCache = {}
Object.defineProperty(this, '_provided', {
get: () => provideCache,
set: (v) => Object.assign(provideCache, v),
})
}
;(this as any)._provided[piniaSymbol as any] = pinia
if (!this.$pinia) {
this.$pinia = pinia
}
pinia._a = this as any
if (IS_CLIENT) {
setActivePinia(pinia)
if (__DEV__) {
registerPiniaDevtools(pinia._a, pinia)
}
}
} else if (!this.$pinia && options.parent && options.parent.$pinia) {
this.$pinia = options.parent.$pinia
}
},
destroyed() {
delete this._pStores
},
})
}
PiniaVuePlugin通过向全局混入一个对象来支持pinia。这个对象有两个生命周期函数:beforeCreate、destory。
在beforeCreate中设置this.$pinia,以使vue实例可以通过this.$pinia的方式来获取pinia
我有一个字符串input="maybe(thisis|thatwas)some((nice|ugly)(day|night)|(strange(weather|time)))"Ruby中解析该字符串的最佳方法是什么?我的意思是脚本应该能够像这样构建句子:maybethisissomeuglynightmaybethatwassomenicenightmaybethiswassomestrangetime等等,你明白了......我应该一个字符一个字符地读取字符串并构建一个带有堆栈的状态机来存储括号值以供以后计算,还是有更好的方法?也许为此目的准备了一个开箱即用的库?
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
我正在使用ruby1.9解析以下带有MacRoman字符的csv文件#encoding:ISO-8859-1#csv_parse.csvName,main-dialogue"Marceu","Giveittohimóhe,hiswife."我做了以下解析。require'csv'input_string=File.read("../csv_parse.rb").force_encoding("ISO-8859-1").encode("UTF-8")#=>"Name,main-dialogue\r\n\"Marceu\",\"Giveittohim\x97he,hiswife.\"\
简而言之错误:NOTE:Gem::SourceIndex#add_specisdeprecated,useSpecification.add_spec.Itwillberemovedonorafter2011-11-01.Gem::SourceIndex#add_speccalledfrom/opt/local/lib/ruby/site_ruby/1.8/rubygems/source_index.rb:91./opt/local/lib/ruby/gems/1.8/gems/rails-2.3.8/lib/rails/gem_dependency.rb:275:in`==':und
一、引擎主循环UE版本:4.27一、引擎主循环的位置:Launch.cpp:GuardedMain函数二、、GuardedMain函数执行逻辑:1、EnginePreInit:加载大多数模块int32ErrorLevel=EnginePreInit(CmdLine);PreInit模块加载顺序:模块加载过程:(1)注册模块中定义的UObject,同时为每个类构造一个类默认对象(CDO,记录类的默认状态,作为模板用于子类实例创建)(2)调用模块的StartUpModule方法2、FEngineLoop::Init()1、检查Engine的配置文件找出使用了哪一个GameEngine类(UGame
我正在使用ruby2.1.0我有一个json文件。例如:test.json{"item":[{"apple":1},{"banana":2}]}用YAML.load加载这个文件安全吗?YAML.load(File.read('test.json'))我正在尝试加载一个json或yaml格式的文件。 最佳答案 YAML可以加载JSONYAML.load('{"something":"test","other":4}')=>{"something"=>"test","other"=>4}JSON将无法加载YAML。JSON.load("
我想用Nokogiri解析HTML页面。页面的一部分有一个表,它没有使用任何特定的ID。是否可以提取如下内容:Today,3,455,34Today,1,1300,3664Today,10,100000,3444,Yesterday,3454,5656,3Yesterday,3545,1000,10Yesterday,3411,36223,15来自这个HTML:TodayYesterdayQntySizeLengthLengthSizeQnty345534345456563113003664354510001010100000344434113622315
我使用的第一个解析器生成器是Parse::RecDescent,它的指南/教程很棒,但它最有用的功能是它的调试工具,特别是tracing功能(通过将$RD_TRACE设置为1来激活)。我正在寻找可以帮助您调试其规则的解析器生成器。问题是,它必须用python或ruby编写,并且具有详细模式/跟踪模式或非常有用的调试技术。有人知道这样的解析器生成器吗?编辑:当我说调试时,我并不是指调试python或ruby。我指的是调试解析器生成器,查看它在每一步都在做什么,查看它正在读取的每个字符,它试图匹配的规则。希望你明白这一点。赏金编辑:要赢得赏金,请展示一个解析器生成器框架,并说明它的
我有这样的HTML代码:Label1Value1Label2Value2...我的代码不起作用。doc.css("first").eachdo|item|label=item.css("dt")value=item.css("dd")end显示所有首先标记,然后标记标签,我需要“标签:值” 最佳答案 首先,您的HTML应该有和中的元素:Label1Value1Label2Value2...但这不会改变您解析它的方式。你想找到s并遍历它们,然后在每个你可以使用next_element得到;像这样:doc=Nokogiri::HTML(
我想禁用HTTP参数的自动XML解析。但我发现命令仅适用于Rails2.x,它们都不适用于3.0:config.action_controller.param_parsers.deleteMime::XML(application.rb)ActionController::Base.param_parsers.deleteMime::XMLRails3.0中的等价物是什么? 最佳答案 根据CVE-2013-0156的最新安全公告你可以将它用于Rails3.0。3.1和3.2ActionDispatch::ParamsParser::