iview源码解析

iview源码解析

对iview源码项目的结构和组件进行解析,仅个人学习过程中的记录和理解,不对之处还请不吝赐教

源码

version:3.1.5

地址:https://github.com/iview/iview

项目结构

Fmpc6g.png

├─assets 图片存放目录
├─build Webpack配置存放目录
├─dist 打包之后页面存放目录
├─examples 组件的demo页面存放目录
├─node_modules 项目依赖目录
├─src 组件根目录
│ │ index.js 组件入口
│ ├─components 组件存放目录
│ ├─directives 组件封装的指令存放目录
│ ├─locale 组件封装的语言配置存放目录
│ ├─mixins 组件封装的混入存放目录
│ ├─styles 组件的样式根目录
│ │ │ copyright.less
│ │ │ custom.less 样式公共变量
│ │ │ index.less 样式入口
│ │ │ README.md
│ │ │
│ │ ├─animation 动画样式
│ │ │
│ │ ├─color
│ │ │
│ │ ├─common 公共样式
│ │ │
│ │ ├─components 组件样式
│ │ │
│ │ └─mixins 混入样式
│ │
│ └─utils 组件内部公共方法
├─test 测试文件
└─types typeScript文件

组件目录

FmCEMF.png

Let‘s Start

index.js 入口文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
//大致结构
//引入所有的组件
import ... from './components/...';

//定义包含所有组件的对象
const components ={...};

//在非 template/render 模式下(例如使用 CDN 引用时),需要使用加前缀 i-,针对部分组件
const iview = {...components,iButton: Button,...};

const install = function(Vue, opts = {}) {
//避免组件的重复加载
if (install.installed) return;
//配置语言
locale.use(opts.locale);
locale.i18n(opts.i18n);
//加载组件
Object.keys(iview).forEach(key => {
Vue.component(key, iview[key]);
});
//全局注册IVIEW对象,size:用于组件大小,transfer:是否将弹层放置于 body 内,在 Tabs、带有 fixed 的 Table 列内使用时,建议添加此属性,它将不受父级样式影响,从而达到更好的效果
Vue.prototype.$IVIEW = {
size: opts.size || '',
transfer: 'transfer' in opts ? opts.transfer : ''
};
//全局注册部分组件
Vue.prototype.$Loading = LoadingBar;
Vue.prototype.$Message = Message;
Vue.prototype.$Modal = Modal;
Vue.prototype.$Notice = Notice;
Vue.prototype.$Spin = Spin;
};

// auto install
//在浏览器环境下默认加载组件
if (typeof window !== 'undefined' && window.Vue) {
install(window.Vue);
}
//组件vue.user的对象
const API = {
version: process.env.VERSION, // eslint-disable-line no-undef
locale: locale.use,
i18n: locale.i18n,
install,
Circle,
Switch,
...components
};

API.lang = (code) => {
const langObject = window['iview/locale'].default;
if (code === langObject.i.locale) locale.use(langObject);
else console.log(`The ${code} language pack is not loaded.`); // eslint-disable-line no-console
};
//输出对象
module.exports.default = module.exports = API; // eslint-disable-line no-undef

使用方法

1
2
3
4
5
6
7
import iView from '../src/index';
// import locale from '../src/locale/lang/en-US';
import locale from '../src/locale/lang/zh-CN';

Vue.use(iView, {
locale
});

Components

Icon 图标组件

所有的icon的样式文件和编码定义都可以在src\styles\common\iconfont 下找到,prefix=ivu-icon-。

组件很简单,用的是原生的 i 标签,绑定了原生的click方法。

1
<i :class="classes" :style="styles" @click="handleClick"></i>
1
2
3
handleClick (event) {
this.$emit('click', event);
}

原生事件在使用的时候要添加native修饰符

1
<Icon @click.native="handleClick">

Button 按钮组件

1
2
3
4
5
<component :is="tagName" :class="classes" :disabled="disabled" @click="handleClickLink" v-bind="tagProps">
<Icon class="ivu-load-loop" type="ios-loading" v-if="loading"></Icon>
<Icon :type="icon" :custom="customIcon" v-if="(icon || customIcon) && !loading"></Icon>
<span v-if="showSlot" ref="slot"><slot></slot></span>
</component>

最外层用 component 标签是用于如果用到了 to API,按钮点击跳转,则用原生的a标签包裹,否则为button标签

button的类型有下列几种,其中的oneOf方法跳转/util/assist.js文件,用于判断第一个参数是否在第二个数组参数内

1
2
3
4
5
6
type: {
validator (value) {
return oneOf(value, ['default', 'primary', 'dashed', 'text', 'info', 'success', 'warning', 'error']);
},
default: 'default'
},

最外层的标签上绑定了handleClickLink方法,

1
2
3
4
5
6
7
/ Ctrl or CMD and click, open in new window when use `to`
handleClickLink (event) {
this.$emit('click', event);
const openInNewWindow = event.ctrlKey || event.metaKey;

this.handleCheckClick(event, openInNewWindow);
}

如果用到to跳转,即最外层是a标签时,使用ctrl和cmd的同时点击跳转,则打开新窗口跳转,handleCheckClick方法通过mixins引入,见/mixin/link,是一个封装的打开新窗口的方法

ButtonGroup 按钮组合

通过设置动态的class来实现按钮组合的效果

Grid 栅格组件

组件内分为行组件row.vue和列组件col.vue,

1
2
3
<div :class="classes" :style="styles">
<slot></slot>
</div>

两个组件都类似,使用到了插槽方法,大部分的功能也是用样式实现,这边主要介绍组件中使用的几个方法,/utils/assist中的findComponentUpward,findComponentDownward,findBrothersComponents,从名称也可以看出来,功能是找寻父组件,子组件,兄弟组件。

Layout 布局组件

  • Layout:布局容器,其下可嵌套 Header`SiderContentFooterLayout` 本身,可以放在任何父容器中。
  • Header:顶部布局,自带默认样式,其下可嵌套任何元素,只能放在 Layout 中。
  • Sider:侧边栏,自带默认样式及基本功能,其下可嵌套任何元素,只能放在 Layout 中。
  • Content:内容部分,自带默认样式,其下可嵌套任何元素,只能放在 Layout 中。
  • Footer:底部布局,自带默认样式,其下可嵌套任何元素,只能放在 Layout 中。
1
<div :class="wrapClasses"><slot></slot></div>

都是使用slot插槽的方法实现,layout.vue中有findSider方法,查询是否有侧边栏,

1
2
3
4
5
findSider () {
return this.$children.some(child => {
return child.$options.name === 'Sider';
});
}

some 方法判断是否存在,$children找到子组件

Card 卡片组件

1
2
3
4
5
6
7
8
9
10
<div :class="classes">
<div :class="headClasses" v-if="showHead"><slot name="title">
<p v-if="title">
<Icon v-if="icon" :type="icon"></Icon>
<span>{{title}}</span>
</p>
</slot></div>
<div :class="extraClasses" v-if="showExtra"><slot name="extra"></slot></div>
<div :class="bodyClasses" :style="bodyStyles"><slot></slot></div>
</div>

总共有3个插槽,自定义标题、额外操作、主题内容,可以完全自由控制各个部分

Collapse 折叠面板

分为单个的面板组件panel.vue和一个放置面板的容器collapse.vue。

面板组件的主题内容也是通过插槽插入,

1
2
3
4
5
<collapse-transition>
<div :class="contentClasses" v-show="isActive">
<div :class="boxClasses"><slot name="content"></slot></div>
</div>
</collapse-transition>

CollapseTransition是面板打开关闭的transition动画,

1
2
3
4
5
6
toggle () {
this.$parent.toggle({
name: this.name || this.index,
isActive: this.isActive
});
}

面板组件里点击title触发父元素的toggle方法,name参数 为操作的面板名称,isActive为开启还是关闭。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
toggle (data) {
const name = data.name.toString();
let newActiveKey = [];//开启的面板

if (this.accordion) {//手风琴模式
if (!data.isActive) {
newActiveKey.push(name);
}
} else {
let activeKey = this.getActiveKey();
const nameIndex = activeKey.indexOf(name);

if (data.isActive) {
if (nameIndex > -1) {
activeKey.splice(nameIndex, 1);
}
} else {
if (nameIndex < 0) {
activeKey.push(name);
}
}

newActiveKey = activeKey;
}

this.currentValue = newActiveKey;
this.$emit('input', newActiveKey);
this.$emit('on-change', newActiveKey);
}

父元素的toggle方法,

-------------The End-------------

本文标题:iview源码解析

文章作者:JunYiZzz

发布时间:2018年11月29日 - 17:11

最后更新:2018年12月03日 - 13:12

原始链接:https://junyizzz.github.io/iviewSourceCode/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。