最近在学习若依系统的框架,其中发现一个很奇怪的事情,网上查询很多地方,也是一知半解。
网上搜索的结果如下,大家可以先看看:
简单的说就是:
将字典做成了插件,添加到了Vue全局中,然后使用混入技术mixin,将dict的内容混入其中,然后每一个组件就都可以使用,但是我们发现并没有定义dict,很多人会觉得很奇怪。
<el-select v-model="form.sex" placeholder="请选择性别">
<el-option
v-for="dict in dict.type.sys_user_sex"
:key="dict.value"
:label="dict.label"
:value="dict.value"
></el-option>
</el-select>
这里就是,使用的dict好像没有定义啊???
但是我们发现,有这样的东西。
export default {
name: "User",
// 使用字典属性
dicts: ['sys_normal_disable', 'sys_user_sex'],
components: { Treeselect },
}
是不是很迷糊?下面我们取dict的源码中去找找看?
-------------------------------以下是源码,已经有注释了,大家可以自己看-----------------
将dict相关的属性封装成组件,然后使用插件的形式放入Vue,通过Vue实现全局混入,这样在任何地方就可以使用dict属性使用字典
第一步:字典插件初始化
// 字典数据组件----------->main.js import DictData from '@/components/DictData' // 字典组件挂载到Vue上当做插件使用 DictData.install()
第二步:字典组件定义
注意,这里vue.use方法的第二个参数是option参数表,这个值是可选项,使用use函数的时候,将会作为参数传递进来,可以搜索use源码:const args = toArray(arguments, 1),这里将参数在赋给字典插件
import Vue from 'vue'
import DataDict from '@/utils/dict'
import {getDicts as getDicts} from '@/api/system/dict/data' // 这是查询字典的方法
function install() {
// 使用vue挂载DataDict插件,这里插件做成了函数形式,不需要install方法,直接use即可
Vue.use(DataDict, {
metas: {
'*': {
labelField: 'dictLabel',
valueField: 'dictValue',
request(dictMeta) {
return getDicts(dictMeta.type).then(res => res.data)
},
},
},
})
}
export default {
install,
}
第三步:自定义字典函数
这里主要是将自定义内容挂载到vue实例当中去,充分使用mixin技术实现
export default function(Vue, options) {
// 1. 用插件参数替换默认配置参数
mergeOptions(options)
// Vue全局混入dict属性
Vue.mixin({
data() {
// 注意这里this.$options表示vue实例中data以外定义的属性,所以用户需要使用的时候,只需要在实例中加dicts属性列表即可
if (this.$options === undefined || this.$options.dicts === undefined || this.$options.dicts === null) {
return {}
}
// 这里将结果返回给了dict对象,所以使用dict对象可以实现数据使用
const dict = new Dict()
dict.owner = this
return {
dict
}
},
created() {
// 如果当前组件没有定义属性列表dicts,那么就没有混入dict属性,this.dict就不存在,直接返回,不调用dict.init()
if (!(this.dict instanceof Dict)) {
return
}
options.onCreated && options.onCreated(this.dict)
// dict的初始化,这里的$options.dicts是当前组件的dicts属性,包含用户自定义属性值列表type
// init函数执行完毕,那么所欲的dict数据均加载完毕
this.dict.init(this.$options.dicts).then(() => {
// 如果初始化组件的时候,参数中定义onReady函数,那么此时就会调用
options.onReady && options.onReady(this.dict)
this.$nextTick(() => {
// 触发dictReady事件
this.$emit('dictReady', this.dict)
// 调用组件实例中的methods属性,如果其中的onDictReady存在,那么就执行他,并把dict作为参数传递进去,并执行
if (this.$options.methods && this.$options.methods.onDictReady instanceof Function) {
this.$options.methods.onDictReady.call(this, this.dict)
}
})
})
},
})}
首先,看看mergeOptions(options)函数干了什么
export const options = {
metas: {
'*': {
/**
* 字典请求,方法签名为function(dictMeta: DictMeta): Promise
*/
request: (dictMeta) => {
console.log(`load dict ${dictMeta.type}`)
return Promise.resolve([])
},
/**
* 字典响应数据转换器,方法签名为function(response: Object, dictMeta: DictMeta): DictData
*/
responseConverter,
labelField: 'label',
valueField: 'value',
},
},
/**
* 默认标签字段
*/
DEFAULT_LABEL_FIELDS: ['label', 'name', 'title'],
/**
* 默认值字段
*/
DEFAULT_VALUE_FIELDS: ['value', 'id', 'uid', 'key'],
}
export function mergeOptions(src) {
// 以递归的形式用src中属性值去替换options中同位置的值,没有的话就使用默认options
mergeRecursive(options, src)
}
// 数据合并
export function mergeRecursive(source, target) {
for (var p in target) {
try {
if (target[p].constructor == Object) {
source[p] = mergeRecursive(source[p], target[p]);
} else {
source[p] = target[p];
}
} catch (e) {
source[p] = target[p];
}
}
return source;
}
以上我们可以得出结论,mergeOptions就是将src和options合并,然后返回,其中src有得都会对应给options,src中没有的则默认使用options中的属性,结果如下:
// 1.内置的options参数
export const options = {
metas: {
'*': {
request: (dictMeta) => {
console.log(`load dict ${dictMeta.type}`)
return Promise.resolve([])
},
responseConverter,
labelField: 'label',
valueField: 'value',
},
},
DEFAULT_LABEL_FIELDS: ['label', 'name', 'title'],
DEFAULT_VALUE_FIELDS: ['value', 'id', 'uid', 'key'],
}
// 2. 用户自定义插件时传入的参数
src = {
metas: {
'*': {
labelField: 'dictLabel',
valueField: 'dictValue',
request(dictMeta) {
return getDicts(dictMeta.type).then(res => res.data)
},
},
},
}
// 3.合并之后的结果
{
metas: {
'*': {
request(dictMeta) {
return getDicts(dictMeta.type).then(res => res.data)
},
responseConverter,
labelField: 'dictLabel',
valueField: 'dictValue',
},
},
DEFAULT_LABEL_FIELDS: ['label', 'name', 'title'],
DEFAULT_VALUE_FIELDS: ['value', 'id', 'uid', 'key'],
}
其中responseConverter是自定义转换函数,如下:
function responseConverter(response, dictMeta) {
const dicts = response.content instanceof Array ? response.content : response
if (dicts === undefined) {
console.warn(`no dict data of "${dictMeta.type}" found in the response`)
return []
}
return dicts.map(d => dictConverter(d, dictMeta))
}
export default function(dict, dictMeta) {
const label = determineDictField(dict, dictMeta.labelField, ...DictOptions.DEFAULT_LABEL_FIELDS)
const value = determineDictField(dict, dictMeta.valueField, ...DictOptions.DEFAULT_VALUE_FIELDS)
return new DictData(dict[label], dict[value], dict)
}
/**
* 确定字典字段
* @param {DictData} dict
* @param {...String} fields
*/
function determineDictField(dict, ...fields) {
return fields.find(f => Object.prototype.hasOwnProperty.call(dict, f))
}
//=============第一次学着写博文,希望大家多鼓励=====================//
前言一般来说,前端根据后台返回code码展示对应内容只需要在前台判断code值展示对应的内容即可,但要是匹配的code码比较多或者多个页面用到时,为了便于后期维护,后台就会使用字典表让前端匹配,下面我将在微信小程序中通过wxs的方法实现这个操作。为什么要使用wxs?{{method(a,b)}}可以看到,上述代码是一个调用方法传值的操作,在vue中很常见,多用于数据之间的转换,但由于微信小程序诸多限制的原因,你并不能优雅的这样操作,可能有人会说,为什么不用if判断实现呢?但是if判断的局限性在于如果存在数据量过大时,大量重复性操作和if判断会让你的代码显得异常冗余。wxswxs相当于是一个独立
项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU
我在我的rails应用程序中安装了来自github.com的acts_as_versioned插件,但有一段代码我不完全理解,我希望有人能帮我解决这个问题class_eval我知道block内的方法(或任何它是什么)被定义为类内的实例方法,但我在插件的任何地方都找不到定义为常量的CLASS_METHODS,而且我也不确定是什么here,并且有问题的代码从lib/acts_as_versioned.rb的第199行开始。如果有人愿意告诉我这里的内幕,我将不胜感激。谢谢-C 最佳答案 这是一个异端。http://en.wikipedia
我正在学习Ruby,遇到了inject。我正处于理解它的风口浪尖,但当我是那种需要真实世界的例子来学习一些东西的人时。我遇到的最常见的例子是人们使用inject来添加一个(1..10)范围的总和,我不太关心这个。这是一个任意的例子。在实际程序中我会用它做什么?我正在学习,所以我可以继续使用Rails,但我不必有一个以Web为中心的示例。我只需要一些我可以全神贯注的目标。谢谢大家。 最佳答案 inject有时可以通过它的“其他”名称reduce更好地理解。它是一个对Enumerable进行操作(迭代一次)并返回单个值的函数。它有许多有
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我最近开始学习Ruby,这是我的第一门编程语言。我对语法感到满意,并且我已经完成了许多只教授相同基础知识的教程。我已经写了一些小程序(包括我自己的数组排序方法,在有人告诉我谷歌“冒泡排序”之前我认为它非常聪明),但我觉得我需要尝试更大更难的东西来理解更多关于Ruby.关于如何执行此操作的任何想法?
我正在处理一些作为Ruby哈希字符串返回的命令输出。(来自名为mcollective的东西)。这是我收到的示例字符串:{:changes=>{"total"=>0},:events=>{"failure"=>0,"success"=>0,"total"=>0},:version=>{"puppet"=>"2.7.21(PuppetEnterprise2.8.1)","config"=>1381497648},:time=>{"filebucket"=>0.000287,"cron"=>0.00212,"package"=>0.398982,"exec"=>0.001314,"confi
我在Ruby中遇到了一个关于Dir[]和File.join()的简单程序,blobs_dir='/path/to/dir'Dir[File.join(blobs_dir,"**","*")].eachdo|file|FileUtils.rm_rf(file)ifFile.symlink?(file)我有两个困惑:首先,File.join(@blobs_dir,"**","*")中的第二个和第三个参数是什么意思?其次,Dir[]在Ruby中有什么用?我只知道它等价于Dir.glob(),但是,我对Dir.glob()确实不是很清楚。 最佳答案
我在尝试使用Faraday将文件上传到网络服务时遇到问题。我的代码:conn=Faraday.new('http://myapi')do|f|f.request:multipartendpayload={:file=>Faraday::UploadIO.new('...','image/jpeg')}conn.post('/',payload)尝试发布后似乎没有任何反应。当我检查响应时this是我所看到的:#:post,:body=>#,#,@opts={}>,#],@index=0>>,#>],@ios=[#,#,@opts={}>,#],@index=0>,#],@index=0>
我使用raise(ConfigurationError.new(msg))引发错误我试着用rspec测试一下:expect{Base.configuration.username}.toraise_error(ConfigurationError,message)但这行不通。我该如何测试呢?目标是匹配message。 最佳答案 您可以使用正则表达式匹配错误消息:it{expect{Foo.bar}.toraise_error(NoMethodError,/private/)}这将检查NoMethodError是否由privateme
1.回顾.TransportServicepublicclassTransportServiceextendsAbstractLifecycleComponentTransportService:方法:1publicfinalTextendsTransportResponse>voidsendRequest(finalTransport.Connectionconnection,finalStringaction,finalTransportRequestrequest,finalTransportRequestOptionsoptions,TransportResponseHandlerT>