诉求:在做后台系统用户组权限这块,后台要求点击多选框时把当前ID传过去
但ivew Checkbox组件文档写的不全,于是研究了一番
CheckboxGroup v-model绑定所有勾选项,格式为数组、on-change事件可以获取当前所有勾选项,格式为数组
Checkbox用@clicknative绑定点击事件(直接用@click无反应),然后在事件里进行相应的 *** 作,把id传给后台
但是写的过程中发现了iview的bug,就是CheckboxGroup v-model绑定的数组渲染时后出现错误,会勾选错误,于是只能放弃iview用原始的checkbox
用原生checkbox就灵活多了,加@click,@change都可以,而且可以把数组直接传入方法里,也不需要$event获取
然后渲染勾选项直接v-model绑定就好,不用再处理为数组
写到这里请让我说一声iview垃圾!!!
对了说一句项目里用的iview2x by the way
对于一些快速迭代的产品来说,特别是移动端 C端产品,基于用户运营的目的,在 app首页给用户展示各种各样的d窗是很常见的事情,在产品初期,由于迭代版本和运营策略变化地还不是太大,所以可能觉得没什么,但当产品运营到后期,各种八竿子打不着的运营策略轮番上阵,d窗的样式、逻辑等都变了不知道多少遍的时候,问题就出来了
由于前期没有做好规划,首页的d窗组件可能放了十多个甚至更多,不仅是首页有,首页内又引入了十多个个子组件,这些子组件内也有,搞不好这些子组件内还有子组件,子组件的子组件同样还有d窗,每个d窗都有对应的一组控制显隐逻辑,分散在多个组件多个方法中,但是首页只有一个页面,你不可能让所有符合显示条件的d窗,全都一下子d出来,反正我是没见过这么做的 app,那么如何管理这些d窗就成了头等大事
而往往当你意识到这一点的时候,很可能也正是局势发展到无法控制的时候 治不了,等死吧
场景:Ad窗和 Bd窗位于主组件内,Cd窗位于主组件的子组件 C中,Dd窗位于主组件的子组件 B中,Ed窗位于主组件的子组件F的子组件G中
PM:我希望刚进入这个页面的时候,只有当 Ad窗 和 Bd窗以及 Cd窗,都不展示的时候,才展示 Dd窗,如果 Dd窗展示过了,除非 Bd窗之后又展示了一遍,否则无论什么情况下都不展示 Ed窗
FE:???
稍加思考一下,其实这件事情并不难办,交给后端通过接口控制所有d窗的显隐就行了 主要是架构的提前规划,以及低耦合的代码逻辑
d窗的配置化
先确定一个大体思路,首先,必须要明确地知道当前页面共有哪些d窗组件,包括页面的子组件以及子组件的子组件内的d窗组件,这是必须的,否则你连有哪些组件都不知道怎么精确控制?
所以,还是上面那句话,提前规划,防患于未然是很重要的,不然等页面迭代了几十版,当初写代码的人都不在了你才想到去统计一下页面上到底有多少个d窗,那真是够你喝一壶的
那么就需要在一个地方统一把这些d窗全记录下来,方便管理,于是可以得到下面这种数据结构:
// modalMapjs
export default {
// 记录首页 index页面内的d窗项
index: {
modalList: [{
name: 'modal_1',
level: 10,
show: true
}, {
name: 'modal_2',
level: 22,
show: true
}, {
name: 'modal_3',
level: 70,
show: true
}],
children: {
child1: {
modalList: [{
name: 'modal_1_1',
level: 8,
show: true
}, {
name: 'modal_1_2',
level: 62,
show: true
}],
children: {
child1_1: {
modalList: [{
name: 'modal_1_1_1',
level: 8,
show: true
}, {
name: 'modal_1_1_2',
level: 60,
show: true
}]
}
}
}
}
}
// 还可以继续记录其他页面的d窗结构
}
modalMapjs文件记录每个页面内所有的d窗项,例如,首页 index内的d窗项都在属性名index对于的值数据结构中,index这个页面主组件内存在两个 modal,可以分别命名为 modal_1和 modal_2,如果 index这个页面主组件的子组件内也有 modal,则继续嵌套,例如,index主组件的子组件 child1中也有 modal,那么就把 child1放到 index的 children中继续记录,以此类推
这种结构看起来比较清晰,主组件及主组件内的子组件内的 modal都很清晰,一目了然,当然,你可以不用这种结构,完全取决于你,这里就暂时这么定义
每个 modal除了 name之外,还有 level 和 show属性
level 用于标识当前 modal的层级,每个页面正常只能同时展示一个 modal,但如果有多个 modal都同一时间都满足展示的条件,则对比它们的 level值,哪个大就优先展示哪个,其余的忽略掉,杜绝一个页面可能提示展示多个d窗的情况;
show属性则是在 modal内部来决定 modal最终是否展示,这样一来就可以无视外界条件,很轻松地通过配置来禁止掉d窗的显示
通过发布/订阅模式来管理d窗
d窗的配置结构已经确定了,下一步就是对这些配置的管理了
一般情况下,多个页面同时满足条件需要进行展示的场景,大多数都是发生在刚进入页面,页面发出多个请求,这些请求的返回结果分别控制对应的一个d窗的展示
因为发出去的这些请求很可能分属于不同的业务线或部门管辖,相互独立,所以说如果把d窗的控制权交给后端来做,其实是有点困难的,再加上请求是异步的,前端想要用意大利面条式代码来保证d窗之间的互斥性也不太容易,综合起来,也就导致了当页面上迭代出了数十个以上d窗的时候,如果没有提前规划好,还是很容易出现d窗同时展示的问题的
这里暂时就以刚进入页面的情况为例,进行逻辑梳理
首先,我需要知道页面上有哪些d窗可能会在刚进入页面的时候d出来(即通过接口控制单个d窗的展现与否),然后在所有d窗的数据都拿到了的时候(即跟d窗相关的接口都已经返回数据),才进行d窗的展示
这种情况比较适合使用发布/订阅者模式,单个接口的数据返回就是一个订阅,当所有接口都订阅之后,就进行发布,也就是d窗展示
// modalManagejs
class ModalManage {
constructor (modalList) {
thismodalFlatMap = {}
thismodalList = modalList
}
//
}
通过 ModalManage类来管理d窗,此类在初始化时接收一个参数 modalList,这个参数其实就是刚进入页面时,页面上所有可能展示的d窗(包括子组件的d窗)的名称集合,也就是必须要知道页面上到底有多少个可能同时展示的d窗,以上述示例代码 modalMapjs为例, index页面的 modalList值就是 ['modal_1', 'modal_2', 'modal_3', 'modal_1_1', 'modal_1_2', 'modal_1_1_1', 'modal_1_1_2']
这里其实直接传d窗数量就行了,index中有 7个d窗可能同时展示,所以可以直接传 7,我这里之所以要传名称进去,实际上是为了方便调试,如果代码出问题了,比如页面上实际有 5个接口可以控制 5个d窗的展示,但你却只订阅了 4次,如果只传数字,你就需要一个个找过去看是哪一个忘记订阅了,但如果传名称,你一下子就能调试出来,也就是代码的可维护性会好一点
当页面上任意一个d窗的状态(即是否满足展示的条件)确定下来后,就进行订阅 *** 作:
// modalManagejs
add (name, dataInfo) {
// level, handler
if (thismodalListindexOf(name) !== -1) {
if (!thismodalFlatMap[name]) {
thismodalFlatMap[name] = dataInfo
thisnotify()
} else {
consolelog('重复订阅')
}
} else {
consolelog('无效订阅')
}
}
thismodalFlatMap是为了记录订阅列表,当订阅列表的长度和 modalList相同时,说明所有的d窗状态都已经准备就绪,可以根据这些d窗的优先级进行展示了,也就是 notify方法要做的事情
notify方法中,先排除掉属性 show为 false的d窗项,再对比剩下的d窗的 level,只展示 level最大的那个d窗:
// modalManagejs
notify () {
if (Objectkeys(thismodalFlatMap)length === thismodalListlength) {
const highLevelModal = Objectkeys(thismodalFlatMap)filter(key => thismodalFlatMap[key]show)reduce((t, c) => {
return thismodalFlatMap[c]level > tlevel thismodalFlatMap[c] : t
// 这个 { level: -1 } 只是为了给 reduce函数一个 initialValue,modal项的 level都应该大于这个 initialValue的 level值,即 -1
}, { level: -1 })
highLevelModalhandler()
}
}
使用单例模式管理嵌套组件以及多个页面的d窗
上述的 ModalManage类已经足以管理d窗了,但还有个问题,如果一个页面上的d窗,分散位于页面主组件及其子组件,甚至是子组件的子组件内,怎么办?
这个时候就需要使用单例了
// 单例管理
const manageTypeMap = {}
// 获取单例
function createModalManage (type) {
if (!manageTypeMap[type]) {
manageTypeMap[type] = new ModalManage(getAllModalList(modalMap[type]))
}
return manageTypeMap[type]
}
通过 createModalManage这个方法来创建 ModalManage实例,根据传入的 type来决定是否创建新的实例,如果单例管理对象 manageTypeMap中不存在 type对于的实例,则 new一个 ModalManage实例,存入 manageTypeMap中,并返回这个新实例,否则就返回 manageTypeMap中已经创建好了的实例
这样一来,无论d窗分散在多少个组件内,无论这些组件嵌套得有多深,都能够在保证代码低耦合的前提下,顺利地订阅/发布事件
这里的 getAllModalList方法是个工具方法,用于从 modalMap中获取页面对应的d窗数据结构:
// utiljs
const getAllModalList = modalInfo => {
let currentList = []
if (modalInfomodalList) {
currentList = currentListconcat(
modalInfomodalListreduce((t, c) => tconcat(cname), [])
)
}
if (modalInfochildren) {
currentList = currentListconcat(
Objectkeys(modalInfochildren)reduce((t, c) => {
return tconcat(getAllModalList(modalInfochildren[c]))
}, [])
)
}
return currentList
}
至于 createModalManage的参数type,其值可以就是一个字符串,例如如果需要管理首页 index上可能同时展示的所有的d窗,则可以将 type 的值指定为 index,在 index主组件以及其包含d窗的子组件内,都通过这个字段来获取 ModalManage单例对象:
const modalManage = createModalManage('index')
这样做同时也解决了另外一个问题,就是多个页面的d窗管理问题,index页面通过 index创建 ModalManage单例,详情页就可以通过 detail来创建
今天在使用<slot>插槽时,出来一个问题,那就是使用v-show的标签没有被执行
但是,<slot>插槽的功能是可以正常使用的。
废话不多说了,下面先看图,然后在说解决办法:
想要问题再现,照着上的写一些就行,我这里使用的modal模板是 iview 提供的,至于安装自己去官网上看
在中父组件使用了<slot>和v-show
解决办法:
v-show 改成 v-if
网上找到了解释是:
就跟<template></template>一样页面上跟本没有这个标签对,当然没办法在其上添加css display属性了,所以对 <slot> <template> 都不能使用 v-show 改用 v-if
slot 不能用v-show,只能使用v–if
在制作eclipse插件的时候,时常需要对已经存在的视图做一些扩展,例如在project explorer中增加一个右键菜单,或者需要获取outline中当前选中项,等等。而这些 *** 作的前提,是获取这些视图的id,然后通过获取视图的语句获取到视图,并进行下一步 *** 作。
例如:如果是在view中:
IViewPartpart=getViewSite()getPage()findView("orgeclipseuiviewsContentOutline");
如果是在action中:
IViewPartpart=PlugingetDefault()getWorkbench()getActiveWorkbenchWindow()getActivePage()findView("orgeclipseuiviewsContentOutline");
可见获取到视图的id是很重要的。如何获取id呢,有很多方法,我觉得比较常用的是以下两种:
1通过手动查找目标视图所在的插件的pluginxml中对改视图的定义,获得视图id。
描述:我觉得这是最保险的办法,因为所有的视图都必定有一个pluginxml定义,但是找到这个pluginxml还是需要一些 *** 作,可能会耗费一些时间。
步骤:
a点击“工具栏”->“Search”->“Search”,或者热键“ctrl+h”。选“ Plugin Search”。
bSearch for 选"Extention Point",Limit to 选“references”,External Scope 选“Enabled Plug-ins only”。
c下面的scope选“Worksapaces”。
d上面的Search String框填入我们要搜索的插件的扩展点的名字,这里我们要找视图插件,所以填入:orgeclipseuiviews
e点击search以后,在底部Search视图内列出很多搜索结果,任意选中一个,双击,可以看到editor内打开了该pluginxml,选中编辑器底部的Extentions,用图形化的方式来查看会更快捷。
f可以看到该插件使用的扩展点已经以列表的形式列出,我们查找的orgeclipseuiviews扩展点也已经选中,展开选中的扩展点,可以看到它实现了哪些view,点击某一个,可以在页面右边看到该视图的详细信息,第一项即是视图的id。
我们无法知道目标视图在搜索结果中的哪个plugin中,所以可能会耗费一些时间,建议在查看搜索结果时,通过对视图的分类分析,确定一个大概范围再进行查看。
同时,用这种方法也可以查找其他扩展点的实现插件。
2通过代码直接读出该视图的id。
描述:通过这种方法,可以直接用鼠标点击某个你想知道的视图,控制台会打印出该视图的id和所属插件的id。
步骤:
a通过插件向导新建一个插件,并使用Available Templates中的Plugin with a view模板,点finish。
b对自动创建的SampleView代码进行修改,修改结果如下。其中主要步骤有三个:实现IPartListener2接口,编写isActivePart()方法,调用isActivePart()方法。
packagecomraullearnsampleviewviews;
importorgeclipseswtwidgetsComposite;
importorgeclipseuipart;
importorgeclipsejfaceviewers;
importorgeclipseswtgraphicsImage;
importorgeclipsejfaceaction;
importorgeclipsejfacedialogsMessageDialog;
importorgeclipseui;
importorgeclipseswtwidgetsMenu;
importorgeclipseswtSWT;
importcomraullearnsampleviewActivator;
/
Thissampleclassdemonstrateshowtoplug-inanew
workbenchviewTheviewshowsdataobtainedfromthe
modelThesamplecreatesadummymodelonthefly,
butarealimplementationwouldconnecttothemodel
availableeitherinthisoranotherplug-in(egtheworkspace)
Theviewisconnectedtothemodelusingacontentprovider
<p>
Theviewusesalabelprovidertodefinehowmodel
objectsshouldbepresentedintheviewEach
viewcanpresentthesamemodelobjectsusing
differentlabelsandicons,ifneededAlternatively,
asinglelabelprovidercanbesharedbetweenviews
inordertoensurethatobjectsofthesametypeare
presentedinthesamewayeverywhere
<p>
/
publicclassSampleViewextendsViewPartimplementsIPartListener2{
privateTableViewerviewer;
privateActionaction1;
privateActionaction2;
privateActiondoubleClickAction;
/
Thecontentproviderclassisresponsiblefor
providingobjectstotheviewItcanwrap
existingobjectsinadaptersorsimplyreturn
objectsas-isTheseobjectsmaybesensitive
tothecurrentinputoftheview,orignore
itandalwaysshowthesamecontent
(likeTaskList,forexample)
/
classViewContentProviderimplementsIStructuredContentProvider{
publicvoidinputChanged(Viewerv,ObjectoldInput,ObjectnewInput){
}
publicvoiddispose(){
}
publicObject[]getElements(Objectparent){
returnnewString[]{"One","Two","Three"};
}
}
classViewLabelProviderextendsLabelProviderimplementsITableLabelProvider{
publicStringgetColumnText(Objectobj,intindex){
returngetText(obj);
}
publicImagegetColumnImage(Objectobj,intindex){
returngetImage(obj);
}
publicImagegetImage(Objectobj){
returnPlatformUIgetWorkbench()
getSharedImages()getImage(ISharedImagesIMG_OBJ_ELEMENT);
}
}
classNameSorterextendsViewerSorter{
}
/
Theconstructor
/
publicSampleView(){
ActivatorgetDefault()getWorkbench()getActiveWorkbenchWindow()
getActivePage()addPartListener(this);
}
@Override
publicvoiddispose(){
//TODOAuto-generatedmethodstub
ActivatorgetDefault()getWorkbench()getActiveWorkbenchWindow()
getActivePage()removePartListener(this);
superdispose();
}
/
Thisisacallbackthatwillallowus
tocreatetheviewerandinitializeit
/
publicvoidcreatePartControl(Compositeparent){
viewer=newTableViewer(parent,SWTMULTI|SWTH_SCROLL|SWTV_SCROLL);
viewersetContentProvider(newViewContentProvider());
viewersetLabelProvider(newViewLabelProvider());
viewersetSorter(newNameSorter());
viewersetInput(getViewSite());
makeActions();
hookContextMenu();
hookDoubleClickAction();
contributeToActionBars();
}
privatevoidhookContextMenu(){
MenuManagermenuMgr=newMenuManager("#PopupMenu");
menuMgrsetRemoveAllWhenShown(true);
menuMgraddMenuListener(newIMenuListener(){
publicvoidmenuAboutToShow(IMenuManagermanager){
SampleViewthisfillContextMenu(manager);
}
});
Menumenu=menuMgrcreateContextMenu(viewergetControl());
viewergetControl()setMenu(menu);
getSite()registerContextMenu(menuMgr,viewer);
}
privatevoidcontributeToActionBars(){
IActionBarsbars=getViewSite()getActionBars();
fillLocalPullDown(barsgetMenuManager());
fillLocalToolBar(barsgetToolBarManager());
}
privatevoidfillLocalPullDown(IMenuManagermanager){
manageradd(action1);
manageradd(newSeparator());
manageradd(action2);
}
privatevoidfillContextMenu(IMenuManagermanager){
manageradd(action1);
manageradd(action2);
//Otherplug-inscancontributethereactionshere
manageradd(newSeparator(IWorkbenchActionConstantsMB_ADDITIONS));
}
privatevoidfillLocalToolBar(IToolBarManagermanager){
manageradd(action1);
manageradd(action2);
}
@Override
publicvoidpartBroughtToTop(IWorkbenchPartReferencepartRef){
//TODOAuto-generatedmethodstub
}
@Override
publicvoidpartClosed(IWorkbenchPartReferencepartRef){
//TODOAuto-generatedmethodstub
}
@Override
publicvoidpartDeactivated(IWorkbenchPartReferencepartRef){
//TODOAuto-generatedmethodstub
}
@Override
publicvoidpartHidden(IWorkbenchPartReferencepartRef){
//TODOAuto-generatedmethodstub
}
@Override
publicvoidpartInputChanged(IWorkbenchPartReferencepartRef){
//TODOAuto-generatedmethodstub
}
@Override
publicvoidpartOpened(IWorkbenchPartReferencepartRef){
//TODOAuto-generatedmethodstub
}
privatevoidisActivePart(){
IWorkbenchPartpart=getViewSite()getPage()getActivePart();
//returnpart!=null&&partequals(this);
Systemoutprintln(partgetSite()getId());
partgetSite()getPluginId();
}
}
然后调插件,在运行环境中调出该视图,接着当你用鼠标点击你想知道的视图时,在开发环境中的控制台,就会打印出该视图的id以及所属插件的id。
iview-Upload组件官网链接: >
以上就是关于vue iview checkbox点击事件全部的内容,包括:vue iview checkbox点击事件、vued窗组件出现时,页面结构发生了什么、vue 使用<slot>和v-show 同时使用的问题等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)