企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
## 组件导出 Vue.use(options)时会执行options中的install属性,即上文导出的install函数,函数包含了注册全局组件的代码; 所以如果想要能被Vue的use方法,就必须导出options对象中包含install方法 ### **派发和广播: dispatch和broadcast** https://juejin.cn/post/6844903929633849357 dispatch和broadcast--通过mixin的方式混入到需要跨级组件通信的组件中。 vue1.x有dispatch和broadcast功能的,在vue2.x中被废弃 dispatch派发事件往上冒泡,broadcast广播事件往下散播,遇到处理对应事件的监听器就处理,监听器没有返回true就停止 elementUI源码以局部混入minix的方式引入,实现多层级分发对应事件的组件间通信: broadcast与dispatch ```js // /src/mixins/emitter.js文件 function broadcast(componentName, eventName, params) { this.$children.forEach(child => { const name = child.$options.name; if (name===componentName){ child.$emit.apply(child, [eventName].concat(params));} else{ broadcast.apply(child, [componentName, eventName].concat([params])); } }); } export default { methods: { dispatch(componentName, eventName, params) { let parent = this.$parent || this.$root; let name = parent.$options.name; while (parent && (!name || name !== componentName)) { parent = parent.$parent; if (parent) { name = parent.$options.name; } } if (parent) { parent.$emit.apply(parent, [eventName].concat(params)); } }, broadcast(componentName, eventName, params) { broadcast.call(this, componentName, eventName, params); } } }; ``` **mixins混入原理** 原因:修改Vue.options属性进而影响之后的所有Vue实例。 做法: 将传入的mixin对象与this.options合并,然后将合并后的新对象作为this.options传给之后的所有Vue实例。 ```js Vue.mixin = function (mixin: Object) { this.options = mergeOptions(this.options, mixin) return this } ``` ### **Popup** Popup是层级关系(z-index)管理工具类,用于管理组件的层级关系,例如message-box,dialog组件。 在element-ui源码中,主要分为两个两部分popup-manger.js和popup 实现覆盖功能需要保证新的弹出框的z-index要比旧的弹出框的z-index值相等或着更高,为达到这个目的element为所有的弹出框(所有下拉框、提示框、Dialog对话框等等)直接或间接的使用到一个js组件element-ui/src/utils/vue-popper,而这个vue-popper又使用了另一个组件element-ui/src/utils/popup/popup-manager.js。 ## **组件库结构** 工程化目录结构 - github:存放了`Element UI`贡献指南、`issue`和`PR`模板 - build:存放了打包相关的配置文件 - examples:组件相关示例 demo - packages:组件源码 - src:存放入口文件和一些工具辅助函数 - test:单元测试相关文件,这也是一个优秀的开源项目必备的 - types:类型声明文件 - components.json:标明了组件的文件路径,方便 `webpack` 打包时获取组件的文件路径。 ```js |- assets/ # 存放一些额外的资源文件,图片之类的 |- build/ # webpack打包配置 |- docs/ # 存放文档 |- .vuepress # vuepress配置目录 |- component # 组件相关的文档放这里 |- README.md # 静态首页 |- lib/ # 打包生成的文件放这里 |- styles/ # 打包后的样式文件 |- src/ # 在这里写代码 |- mixins/ # mixin文件 |- packages/ # 各个组件,每个组件是一个子目录 |- styles/ # 样式文件 |- common/ # 公用的样式内容 |- mixins/ # 复用的mixin |- utils # 工具目录 |- index.js # 打包入口,组件的导出 |- test/ # 测试文件夹 |- specs/ # 存放所有的测试用例 |- .npmignore |- .gitignore |- .babelrc |- README.md |- package.json ``` - 组件测试 --> vue-test-utils 工具 - 文档生成 --> vuepress 或 在 webpack 打包过程中自定义个 loader 来实现:markdown 转成 vue 实现 - 自定义主题 --> 覆盖了组件库中的一些主题变量(把主题变量文件和样式文件拆开来) - webpack打包 --> 外部化依赖 外部化依赖 :当组件库项目中的某个地方引入了vue,打包时vue也会被打包进入组件库bundle文件。解决: webpack的 externals将vue依赖外部化。 ```js module.exports = { externals: { vue: {root: 'Vue', commonjs: 'vue', commonjs2: 'vue', amd: 'vue'} } } ``` - 按需加载 --> babel-plugin-component插件, 将引入组件库和组件样式的模式自动化 ```js // 原始代码 import { Button } from 'components' // 转换代码 var button = require('components/lib/button') require('components/lib/button/style.css') ``` ### **render()渲染函数** https://juejin.cn/post/6844903823194980360 render渲染函数,返回值为VNode即虚拟节点,只有一个参数createElement,也是函数,该参数接受三个参数: 要渲染的最外层HTML标签,标签的属性,子虚拟节点 (VNodes) ```js render: createElement => { return createElement( 'div', { // 接受一个字符串、对象或字符串和对象组成的数组 'class': { foo: true, bar: false }, style: { color: 'red', fontSize: '14px' }, // 普通的 HTML attribute attrs: { id: 'foo' }, props: { myProp: 'bar' }, // DOM property domProps: { innerHTML: 'baz' }, // 事件监听器, 但不再支持如 `v-on:keyup.enter` 这样的修饰器。 需要在处理函数中手动检查 keyCode。 on: { click: this.clickHandler }, // 仅用于组件,用于监听原生事件,而不是组件内部使用; `vm.$emit` 触发的事件。 nativeOn: { click: this.nativeClickHandler }, // 自定义指令。注意,你无法对 `binding` 中的 `oldValue`赋值,因为 Vue 已经自动为你进行了同步。 directives: [{ name:'my-directive', value:'2', expression:'1 + 1', arg:'foo', modifiers:{bar: true} }], // 作用域插槽的格式为 { name: props => VNode | Array<VNode> } scopedSlots: { default: props => createElement('span', props.text) }, // 如果组件是其它组件的子组件,需为插槽指定名称 slot: 'name-of-slot', key: 'myKey', ref: 'myRef', refInFor: true }, // 3. 第三个参数,1中渲染的标签的子元素数组【可选】,不使用此参数,用 null 占位 或不写 [ createElement('a', {attrs: {name: headingId, href: 'https://www.baidu.com'}}, []) ] ) } ```