网站建设的主题,如何建设网站济南兴田德润o简介电话,网站域名申请程序,app推广是什么工作最近在写fj-service-system的时候#xff0c;遇到了一些问题。那就是我有些组件#xff0c;比如Dialog、Message这样的组件#xff0c;是引入三方组件库#xff0c;比如element-ui这样的#xff0c;还是自己实现一个#xff1f;虽然它们有按需引入的功能#xff0c;但是…最近在写fj-service-system的时候遇到了一些问题。那就是我有些组件比如Dialog、Message这样的组件是引入三方组件库比如element-ui这样的还是自己实现一个虽然它们有按需引入的功能但是整体风格和我的整个系统不搭。于是就可以考虑自己手动实现这些简单的组件了。 通常我们看Vue的一些文章的时候我们能看到的通常是讲Vue单文件组件化开发页面的。单一组件开发的文章相对就较少了。我在做fj-service-system项目的时候发现其实单一组件开发也是很有意思的。可以写写记录下来。因为写的不是什么ui框架所以也只是一个记录没有github仓库权且看代码吧。v-model或者.sync显式控制组件显示隐藏通过js代码调用通过Vue指令调用在写组件的时候很多写法、灵感来自于element-ui感谢。 Dialog 我习惯把这个东西叫做对话框实际上还有叫做modal(弹窗)组件的叫法。其实就是在页面里弹出一个小窗口这个小窗口里的内容可以定制。通常可以用来做登录功能的对话框。 这种组件就很适合通过v-model或者.sync的方式来显式的控制出现和消失。它可以直接写在页面里然后通过data去控制——这也是最符合Vue的设计思路的组件。 为此我们可以写一个组件就叫做Dialog.vue templatediv classdialogdiv classdialog__wrapper v-ifvisble clcikcloseModaldiv classdialogdiv classdialog__headerdiv classdialog__title{{ title }}/div/divdiv classdialog__bodyslot/slot/divdiv classdialog__footerslot namefooter/slot/div/div/divdiv classmodal v-showvisible/div/div
/templatescriptexport default {name: dialog,props: {title: String,visible: {type: Boolean,default: false}},methods: {close() {this.$emit(update:visible, false) // 传递关闭事件},closeModal(e) {if (this.visible) {document.querySelector(.dialog).contains(e.target) ? : this.close(); // 判断点击的落点在不在dialog对话框内如果在对话框外就调用this.close()方法关闭对话框}}}}
/script CSS什么的就不写了跟组件本身关系比较小。不过值得注意的是上面的dialog__wrapper这个class也是全屏的透明的主要用于获取点击事件并锁定点击的位置通过DOM的Node.contains()方法来判断点击的位置是不是dialog本身如果是点击到了dialog外面比如半透明的modal层那么就派发关闭事件把dialog给关闭掉。 当我们在外部要调用的时候就可以如下调用 templatediv classxxxdialog :visible.syncvisible/dialog button clickopenDialog/button/div
/templatescriptimport Dialog from Dialogexport default {components: {Dialog},data() {return {visible: false}},methods: {openDialog() {this.visible true // 通过data显式控制dialog}}}
/script 为了Dialog开启和关闭好看点你可试着加上transition/transition组件配合上过渡效果简单的一点过渡动效也将会很好看。 Notice 这个组件类似于element-ui的message消息提示。它吸引我的最大的地方在于它不是通过显式的在页面里写好组件的html结构通过v-model去调用的而是通过在js里通过形如this.$message()这样的方法调用的。这种方法虽然跟Vue的数据驱动的思想有所违背。不过不得不说在某些情况下真的特别方便。 对于Notice这种组件一次只要提示几个文字给用户简单的消息提示就行了。提示的信息可能是多变的甚至可以出现叠加的提示。如果通过第一种方式去调用事先就得写好html结构这无疑是麻烦的做法而且无法预知有多少消息提示框。而通过js的方法调用的话只需要考虑不同情况调用的文字、类型不同就可以了。 而之前的做法都是写一个Vue文件然后通过components属性引入页面显式写入标签调用的。那么如何将组件通过js的方法去调用呢 这里的关键是Vue的extend方法。 文档里并没有详细给出extend能这么用只是作为需要手动mount的一个Vue的组件构造器说明了一下而已。 通过查看element-ui的源码才算是理解了如何实现上述的功能。 首先依然是创建一个Notice.vue的文件 templatediv classnoticediv classcontent{{ content }}/div/div
/templatescriptexport default {name: notice,data () {return {visible: false,content: ,duration: 3000}},methods: {setTimer() {setTimeout(() {this.close() // 3000ms之后调用关闭方法}, this.duration)},close() {this.visible falsesetTimeout(() {this.$destroy(true)this.$el.parentNode.removeChild(this.$el) // 从DOM里将这个组件移除}, 500)}},mounted() {this.setTimer() // 挂载的时候就开始计时3000ms后消失}}
/script 上面写的东西跟普通的一个单文件Vue组件没有什么太大的区别。不过区别就在于没有props了那么是如何通过外部来控制这个组件的显隐呢 所以还需要一个js文件来接管这个组件并调用extend方法。同目录下可以创建一个index.js的文件。 import Vue from vueconst NoticeConstructor Vue.extend(require(./Notice.vue)) // 直接将Vue组件作为Vue.extend的参数let nId 1const Notice (content) {let id notice- nIdconst NoticeInstance new NoticeConstructor({data: {content: content}}) // 实例化一个带有content内容的NoticeNoticeInstance.id idNoticeInstance.vm NoticeInstance.$mount() // 挂载但是并未插入dom是一个完整的Vue实例NoticeInstance.vm.visible trueNoticeInstance.dom NoticeInstance.vm.$eldocument.body.appendChild(NoticeInstance.dom) // 将dom插入bodyNoticeInstance.dom.style.zIndex nId 1001 // 后插入的Notice组件z-index加一保证能盖在之前的上面return NoticeInstance.vm
}export default {install: Vue {Vue.prototype.$notice Notice // 将Notice组件暴露出去并挂载在Vue的prototype上}
} 这个文件里我们能看到通过NoticeConstructor我们能够通过js的方式去控制一个组件的各种属性。最后我们把它注册进Vue的prototype上这样我们就可以在页面内部使用形如this.$notice()方法了可以方便调用这个组件来写做出简单的通知提示效果了。 当然别忘了这个相当于一个Vue的插件所以需要去主js里调用一下Vue.use()方法 // main.js// ...
import Notice from notice/index.jsVue.use(Notice)// ... Loading 在看element-ui的时候我也发现了一个很有意思的组件是Loading用于给一些需要加载数据等待的组件套上一层加载中的样式的。这个loading的调用方式最方便的就是通过v-loading这个指令通过赋值的true/false来控制Loading层的显隐。这样的调用方法当然也是很方便的。而且可以选择整个页面Loading或者某个组件Loading。这样的开发体验自然是很好的。 其实跟Notice的思路差不多不过因为涉及到directive所以在逻辑上会相对复杂一点。 平时如果不涉及Vue的directive的开发可能是不会接触到modifiers、binding等概念。参考文档 简单说下形如:v-loading.fullscreentrue这句话v-loading就是directivefullscreen就是它的modifiertrue就是binding的value值。所以就是通过这样简单的一句话实现全屏的loading效果并且当没有fullscreen修饰符的时候就是对拥有该指令的元素进行loading效果。组件通过binding的value值来控制loading的开启和关闭。类似于v-model的效果 其实loading也是一个实际的DOM节点只不过要把它做成一个方便的指令还不是特别容易。 首先我们需要写一下loading的Vue组件。新建一个Loading.vue文件 templatetransitionnameloadingafter-leavehandleAfterLeavedivv-showvisibleclassloading-mask:class{fullscreen: fullscreen}div classloading.../divdiv classloading-text v-iftext{{ text }}/div/div/transition
/template
script
export default {name: loading,data () {return {visible: true,fullscreen: true,text: null}},methods: {handleAfterLeave() {this.$emit(after-leave);}}
}
/script
style
.loading-mask{position: absolute; // 非全屏模式下position是absolutez-index: 10000;background-color: rgba(255,235,215, .8);margin: 0;top: 0;right: 0;bottom: 0;left: 0;transition: opacity .3s;
}
.loading-mask.fullscreen{position: fixed; // 全屏模式下position是fixed
}
// ...
/style Loading关键是实现两个效果 1.全屏loading此时可以通过插入body下然后将Loading的position改为fixed插入body实现。 2.对所在的元素进行loading此时需要对当前这个元素的的position修改如果不是absolute的话就将其修改为relatvie并插入当前元素下。此时Loading的position就会相对于当前元素进行绝对定位了。 所以在当前目录下创建一个index.js的文件用来声明我们的directive的逻辑。 import Vue from vue
const LoadingConstructor Vue.extend(require(./Loading.vue))export default {install: Vue {Vue.directive(loading, { // 指令的关键bind: (el, binding) {const loading new LoadingConstructor({ // 实例化一个loadingel: document.createElement(div),data: {text: el.getAttribute(loading-text), // 通过loading-text属性获取loading的文字fullscreen: !!binding.modifiers.fullscreen }})el.instance loading; // el.instance是个Vue实例el.loading loading.$el; // el.loading的DOM元素是loading.$elel.loadingStyle {};toggleLoading(el, binding);},update: (el, binding) {el.instance.setText(el.getAttribute(loading-text))if(binding.oldValue ! binding.value) {toggleLoading(el, binding)} },unbind: (el, binding) { // 解绑if(el.domInserted) {if(binding.modifiers.fullscreen) {document.body.removeChild(el.loading);}else {el.loading el.loading.parentNode el.loading.parentNode.removeChild(el.loading);}}}})const toggleLoading (el, binding) { // 用于控制Loading的出现与消失if(binding.value) { Vue.nextTick(() {if (binding.modifiers.fullscreen) { // 如果是全屏el.originalPosition document.body.style.position;el.originalOverflow document.body.style.overflow;insertDom(document.body, el, binding); // 插入dom} else {el.originalPosition el.style.position;insertDom(el, el, binding); // 如果非全屏插入元素自身}})} else {if (el.domVisible) {el.instance.$on(after-leave, () {el.domVisible false;if (binding.modifiers.fullscreen el.originalOverflow ! hidden) {document.body.style.overflow el.originalOverflow;}if (binding.modifiers.fullscreen) {document.body.style.position el.originalPosition;} else {el.style.position el.originalPosition;}});el.instance.visible false;}}}const insertDom (parent, el, binding) { // 插入dom的逻辑if(!el.domVisible) {Object.keys(el.loadingStyle).forEach(property {el.loading.style[property] el.loadingStyle[property];});if(el.originalPosition ! absolute) {parent.style.position relative}if (binding.modifiers.fullscreen) {parent.style.overflow hidden}el.domVisible true;parent.appendChild(el.loading) // 插入的是el.loading而不是el本身Vue.nextTick(() {el.instance.visible true;});el.domInserted true;}}}
} 同样写完整个逻辑我们需要将其注册到项目里的Vue下 // main.js// ...
import Loading from loading/index.jsVue.use(Loading)// ... 至此我们已经可以使用形如 div v-loading.fullscreenloading loading-text正在加载中这样的方式来实现调用一个loading组件了。 总结 在用Vue写我们的项目的时候不管是写页面还是写形如这样的功能型组件其实都是一件很有意思的事情。本文介绍的三种调用组件的方式也是根据实际情况出发而实际操作、实现的。不同的组件通过不同的方式去调用方便了开发人员也能更好地对代码进行维护。当然也许还有其他的方式我并没有了解也欢迎大家在评论里指出 最后再次感谢element-ui的源码给予的极大启发。 文章作者: Molunerfinn 文章链接: https://molunerfinn.com/vue-components/ 版权声明: 本博客所有文章除特别声明外均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 MARKSZのBlog 转载于:https://www.cnblogs.com/wwhhq/p/8283769.html