[vue3进阶] 2.动态组件

[vue3进阶] 2.动态组件,第1张

之前我们用到一个组件的时候,在模板里写上组件的标签就可以使用了

这样,在页面上就会显示这个组件,这个组件是固定的
动态组件是不固定要显示哪个组件,只是有个component标签,表示在模板的相应位置有一个组件,
它具体显示哪个组件,要根据它的is属性来决定

is绑定currentComponent是一个字符串,表示一个组件的名字,组件名字改变时,component标签这个位置显示的组件就会变化

还是用我们之前用过的两个组件做示例,表示两个不同的组件componentA和componentB,在点击按钮时,切换组件,

点击按钮就可以切换显示的组件

动态组件的内容就是这么简单,下面我们来举一个实际应用中的例子,
比如在一个应用中的个人中心,有几个模块

假如这几个模块显示的顺序,或者哪个模块显示、哪个模块不显示是根据用户的不同有所区别的,
那么我们可以使用动态组件去实现这个功能,
1)把这个组件名字都放到一个数组里,
2)通过for循环把这些组件用动态组件写在template中
3)控制数组的顺序和内容,实现组件的顺序和显示

这节课就是这些内容了,下节课再见。

基本上每个项目都需要用到模态框组件,由于在最近的项目中,alert组件和confirm是两套完全不一样的设计,所以我将他们分成了两个组件,本文主要讨论的是confirm组件的实现。
组件结构
<template>
<div class="modal" v-show="show" transition="fade">
<div class="modal-dialog">
<div class="modal-content">
<!--头部-->
<div class="modal-header">
<slot name="header">
<p class="title">{{modaltitle}}</p>
</slot>
<a v-touch:tap="close(0)" class="close" href="javascript:void(0)"></a>
</div>
<!--内容区域-->
<div class="modal-body">
<slot name="body">
<p class="notice">{{modaltext}}</p>
</slot>
</div>
<!--尾部, *** 作按钮-->
<div class="modal-footer">
<slot name="button">
<a v-if="modalshowCancelButton" href="javascript:void(0)" class="button {{modalcancelButtonClass}}" v-touch:tap="close(1)">{{modalcancelButtonText}}</a>
<a v-if="modalshowConfirmButton" href="javascript:void(0)" class="button {{modalconfirmButtonClass}}" v-touch:tap="submit">{{modalconfirmButtonText}}</a>
</slot>
</div>
</div>
</div>
</div>
<div v-show="show" class="modal-backup" transition="fade"></div>
</template>
模态框结构分为三部分,分别为头部、内部区域和 *** 作区域,都提供了slot,可以根据需要定制。
样式
modal {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
z-index: 1001;
-webkit-overflow-scrolling: touch;
outline: 0;
overflow: scroll;
margin: 30/@rate auto;
}
modal-dialog {
position: absolute;
left: 50%;
top: 0;
transform: translate(-50%,0);
width: 690/@rate;
padding: 50/@rate 40/@rate;
background: #fff;
}
modal-backup {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1000;
background: rgba(0, 0, 0, 05);
}
这里只是一些基本样式,没什么好说的,这次项目是在移动端,用了淘宝的 自适应布局方案 ,@rate是切稿时候的转换率。
接口定义
/
modal 模态接口参数
@param {string} modaltitle 模态框标题
@param {string} modaltext 模态框内容
@param {boolean} modalshowCancelButton 是否显示取消按钮
@param {string} modalcancelButtonClass 取消按钮样式
@param {string} modalcancelButtonText 取消按钮文字
@param {string} modalshowConfirmButton 是否显示确定按钮
@param {string} modalconfirmButtonClass 确定按钮样式
@param {string} modalconfirmButtonText 确定按钮标文字
/
props: ['modalOptions'],
computed: {
/
格式化props进来的参数,对参数赋予默认值
/
modal: {
get() {
let modal = thismodalOptions;
modal = {
title: modaltitle || '提示',
text: modaltext,
showCancelButton: typeof modalshowCancelButton === 'undefined' true : modalshowCancelButton,
cancelButtonClass: modalcancelButtonClass modalshowCancelButton : 'btn-default',
cancelButtonText: modalcancelButtonText modalcancelButtonText : '取消',
showConfirmButton: typeof modalshowConfirmButton === 'undefined' true : modalcancelButtonClass,
confirmButtonClass: modalconfirmButtonClass modalconfirmButtonClass : 'btn-active',
confirmButtonText: modalconfirmButtonText modalconfirmButtonText : '确定',
};
return modal;
},
},
},
这里定义了接口的参数,可以自定义标题、内容、是否显示按钮和按钮的样式,用一个computed来做参数默认值的控制。
模态框内部方法
data() {
return {
show: false, // 是否显示模态框
resolve: '',
reject: '',
promise: '', // 保存promise对象
};
},
methods: {
/
确定,将promise断定为完成态
/
submit() {
thisresolve('submit');
},
/
关闭,将promise断定为reject状态
@param type {number} 关闭的方式 0表示关闭按钮关闭,1表示取消按钮关闭
/
close(type) {
thisshow = false;
thisreject(type);
},
/
显示confirmd出,并创建promise对象
@returns {Promise}
/
confirm() {
thisshow = true;
thispromise = new Promise((resolve, reject) => {
thisresolve = resolve;
thisreject = reject;
});
return thispromise; //返回promise对象,给父级组件调用
},
},
在模态框内部定义了三个方法,最核心部分confirm方法,这是一个定义在模态框内部,但是是给使用模态框的父级组件调用的方法,该方法返回的是一个promise对象,并将resolve和reject存放于modal组件的data中,点击取消按钮时,断定为reject状态,并将模态框关闭掉,点确定按钮时,断定为resolve状态,模态框没有关闭,由调用modal组件的父级组件的回调处理完成后手动控制关闭模态框。
调用
<!-- template -->
<confirm v-ref:dialog :modal-optionssync="modal"></confirm>
<!-- methods -->
this$refsdialogconfirm()then(() => {
// 点击确定按钮的回调处理
callback();
this$refsdialogshow = false;
})catch(() => {
// 点击取消按钮的回调处理
callback();
});
用 v-ref 创建一个索引,就很方便拿到模态框组件内部的方法了。这样一个模态框组件就完成了。
其他实现方法
在模态框组件中,比较难实现的应该是点击确定和取消按钮时,父级的回调处理,我在做这个组件时,也参考了一些其实实现方案。
使用事件转发
这个方法是我的同事实现的,用在上一个项目,采用的是$dispatch和$broadcast来派发或广播事件。
首先在根组件接收dispatch过来的transmit事件,再将transmit事件传递过来的eventName广播下去
events: {
/
转发事件
@param {string} eventName 事件名称
@param {object} arg 事件参数
@return {null}
/
'transmit': function (eventName, arg) {
this$broadcast(eventName, arg);
}
},
其次是模态框组件内部接收从父级组件传递过来的确定和取消按钮所触发的事件名,点击取消和确定按钮的时候触发
// 接收事件,获得需要取消和确定按钮的事件名
events: {
'tip': function(obj) {
thisevents = {
cancel: objeventscancel,
confirm: objeventsconfirm
}
}
}
// 取消按钮
cancel:function() {
this$dispatch('transmit',thiseventscancel);
}
// 确定按钮
submit: function() {
this$dispatch('transmit',thiseventssubmit);
}
在父级组件中调用模态框如下:
this$dispatch('transmit','tip',{
events: {
confirm: 'confirmEvent'
}
});
this$once('confirmEvent',function() {
callback();
}
先是传递tip事件,将事件名传递给模态框,再用$once监听确定或取消按钮所触发的事件,事件触发后进行回调。
这种方法看起来是不是很晕?所以vue 20取消了$dispatch和$broadcast,我们在最近的项目中虽然还在用10,但是也不再用$dispatch和$broadcast,方便以后的升级。
使用emit来触发
这种方法来自 vue-bootstrap-modal ,点击取消和确定按钮的时候分别emit一个事件,直接在组件上监听这个事件,这种做法的好处是事件比较容易追踪。
// 确定按钮
ok () {
this$emit('ok');
if (thiscloseWhenOK) {
thisshow = false;
}
},
// 取消按钮
cancel () {
this$emit('cancel');
thisshow = false;
},
调用:
<modal title="Modal Title" :showsync="show" @ok="ok" @cancel="cancel">
Modal Text
</modal>
但是我们在使用的时候经常会遇到这样的场景,在一个组件的内部,经常会用到多个对话框,对话框可能只是文字有点区别,回调不同,这时就需要在template中为每个对话框都写一次,有点麻烦。

最近做项目经常会用到一些UI库,比如 element 、 iview 等,这些能够快速构建应用的库真的十分方便。比如 iview 的级联菜单很是好用,但是在使用的同时不免起了一些疑惑,它是怎么做到多级联动,依我所知,如果一个数据是多层的,我们就要多次使用 v-for ,并且需要知道要循环几次,但是这个组件貌似不需要多次复用。好啦,下面进入正题!

首先我们手里是一份这样的 JSON 数据:

这是最重要的环节,组件的递归实现了级联菜单的多级联动,这个过程就如同实现对象的深复制一样。那么接下来我们按照这份数据写一个递归组件:

这里要强调以下,组件的 name 属性必须要有,否则无法实现递归,当然递归也需要有终止的条件,上边的 isFloder 便是了。

这里也有需要注意的, v-for 循环需要绑定 key ,否则会报警告。
最后来看下这个简单级联菜单的效果:

最近在做一个vue的项目,独立封装树形组件。
先说一下项目需求:
1项目原型:

此树形结构分为三级:根节点,一级节点,二级节点,每个节点都可以选中或取消选中,父级节点选中,下级的所有节点也可全部选中。二级节点中有不可选中的节点
2后台返回的数据结构:
thismenuList = [{id:1,menuName:'首页',type:1,parentId:0},
{id:2,menuName:'首页1',type:0,parentId:1},
{id:3,menuName:'首页2',type:0,parentId:1},
{id:5,menuName:'首页3',type:1,parentId:1},
{id:6,menuName:'报告看板',type:1,parentId:0},
{id:7,menuName:'看板1',type:2,parentId:6},
{id:8,menuName:'看板2',type:2,parentId:6},
{id:9,menuName:'数据中心',type:1,parentId:0},
{id:10,menuName:'数据中心1',type:1,parentId:9},
{id:10,menuName:'数据中心2',type:2,parentId:9}];
其中parentId为0 的为父节点,1为可以选择的子节点,2为已经选中的子节点
根节点为前端写死的节点
3html页面

4最终实现的效果

这个是定义组件的自定义事件的,如果组件都是用原生事件,那么可以不用emits。
其实就算有自己定义的事件也可以不写emits,程序也可以正常运行。
但是如果写了emits的话,那么就要按照要求写,否则会出现各种warn的警告,虽然也不影响运行,但是这明细是一个隐患,另外报一大堆warn也是很烦人的。

事件命名最好都是小写,因为不区分大小写,有时候会造成错误,可以用连字符来区分多个单词。

另外还可以像props 那样做一个验证

主要是验证参数是否符合要求的,然后用return true/false 表示。

这个大家都熟悉,是组件内部向父组件提交事件的,也可以用来修改props属性值。
看了一下官网,emit和v-model是一起介绍的,但是却没提emits的事。

如果这时候我们写了emits,就需要加上 emits: ['update:modelValue'] ,否则就会出现警告。

emit还可以提交其他的各种事件,比如一个select,本来是没有input事件的,但是我们可以用emit提交,然后在emits里面定义一下就可以。

封装表单控件,每个子控件都要挨个确认属性和事件,还是非常头疼的事情。不过嘛,反要一口一口的吃,早晚能够啃完。

在初学 Vue 的时候,都是利用 cdn 的方式在一个页面中导入 vuejs 的库文件

接着,肯定就学到了组件开发

当然,也是在单页面中

API文档告诉我们

在后来,学到了使用 vue-cli 搭配 vue 模板的方式开发组件

好了,三种组件创建的方式说完了,且在各自的环境里都能够正常的运作

在 Vue 开发中,所有的组件本质上都是由一个继承自 Vue 的构造函数创建的

比如在注册局部组件时

从视觉上,我们看到 TodoListComp 只是一个普通的 Object 对象

直接赋值给了其他组件的 components 属性里

然后,这个组件就成为了一个局部组件,并可以在注册了当前组件的内部去使用了

那它在内部做了什么,导致这个普通的对象最后可以被当成是一个正常的组件来使用呢

比如,普通对象上都没有 $el 之类的属性丢给 components 之后,就啥都有了

使用Vueextend(options)会根据传入的options创建一个VueComponent的组件构造函数并返回

既然使用 Vueextend 会返回一个组件的构造函数

那么我们就可以使用 new 这个返回的构造函数

并手动的 mount 并替换某个 dom 节点(就和 new App() 一样)

前面,我么已经知道了,所有的 vue 组件,不管是全局的还是局部的

都是利用 Vueextend 方法构建并返回出一个继承自 Vue 的组件构造函数

这个函数接受一个满足了 Vue 组件属性项的普通的 Object 对象

在vue模板文件开发中,也不例外

我们可以看看,在书写 vue 模板文件时,我们到底在写什么

我们写的是一个 vue 文件

并按照 <template></template> <script></script> ( 这里不关注 <style></style> 节点 ) 的格式编写 vue 文件

把它整合起来来看

等价于

好了,继续回到 vue 模板开发文件中

在另外一个组件中,使用此组件时,我们会 import xxx from xxxvue 并搭配 components:{ xxxx }

vue 会被 webpack 中配置的 vue-loader 处理这是我们已知的

结合上述的判断, vue-loader 仅仅只是把 vue 文件编译成了一个 vueextend(options) 创建组件所需要的 options 普通对象而已

既然 vue-loader 仅仅,只是把 vue 模板文件编译成了一个 options 普通对象

那么我们可以手动的使用 Vueextends(options) 来获得这个组件对象的构造函数

拿到此组件的构造函数,我们就可以在 组件 mounted 的时候,通过 new 的方式,挂在到 html 上了 (而无需去注册到 components,成为一个局部组件直接把它当成一个自己熟悉的不能在熟悉的构造函数调用即可)

既然我们已经知道:

我们完全可以直接使用 js 文件的方式来创建 vue 组件,进而省略 vue & vue-loader 这个执行的步骤

此 js 文件到处一个 vue 组件的构造函数

在另外一个组件里

通过这样的原理,我们完全可以在HTML页面的任意地方,任意位置,任意的挂在我们自己的组件并不一定必须使用vue声明式组件的语法

[ 码云地址 ]

网站搭建框架之vue

Vue是web前端快速搭建网站的框架之一。它与jQuery有所不同,是以数据驱动web界面(以 *** 作数据改变页面,而jQuery是以 *** 作节点来改变页面),同时,vue还实现了数据的双向绑定,可及时响应用户的输入。最主要的是vue的写法简单,容易掌握,组件形式可以大大提高工作效率。

对于vue的使用可以分为两种使用形式:1引入vuejs文件,在js中将vue实例化;2通过node安装第三方包--vue,搭建脚手架,用脚手架将页面分成几个组件编写,从而利用组件来搭建页面。
引入vuejs的写法

Vue分为V层(视图层)和M层(数据层),一般都是由M层的数据来驱动V层的改变。而vue的常用指令数量不多且写法简单。常用的有v-html、v-text、v-show、v-if、v-else、v-for、v-bind:、v-model。v-html和v-text都是将数据写进标签内,但它们的不同之处在于v-text会将标签当做文本内容写入
,而v-html则会对标签进行编译,只显示标签内的内容。

至于v-show、v-if、v-else这三个指令都是通过布尔值的判断来执行的,当布尔值为真时,设置了v-show、v-if指令的标签会显示出来,当布尔值为假时,标签隐藏;而v-else与这两个指令相反。除此之外,v-show和v-if、v-else之间也有差别,v-show是改变标签的display属性来使标签显示或隐藏;而v-if、v-else是通过添加或删除节点,来显示或隐藏标签的。

V-for是vue的一种遍历方法,这个方法极大的简化了数组或对象的遍历并显示到页面的步骤
而v-bind:是对html属性或自定义属性的数据驱动方式,格式为v-bind:href,可简写为:href。对于类(class)的 *** 作是通过布尔值来判断增加或者隐藏类,同时。类和样式(style)所接受的数据类型为对象。

V-model指令的作用是将数据进行双向绑定,仅限于输入类型标签。当用户在页面输入时,数据层的数据会跟着改变。这是VM模式。由v驱动m。

除了这些普通的指令之外,还有事件指令v-on:,可简写为@+事件名,例如:@click,并将执行函数写到vue的methods中
通过脚手架来写项目的话,可用通过写组件,再将组件引入(注册)到另一个vue文件里拼接在一起,从而构建出一个页面。
(组件书写格式)
(组件整合)
(注册路由)

路由是通过vue-router来实现的,在注册路由的时候要将router实例化。不同的路由跳转不同的页面,这是搭建单页面应用的优势。

而父组件与子组件之间的通讯可以通过props将父组件的信息传递给子组件,改变子组件的内容,这样子组件的复用就不会有障碍了,而子组件传递信息给父组件或者其他组件的通讯则需vuex。
通过引入vuex并实例化一个VuexStore作为一个公共平台,将数据进行传输。通过vue的computed方法接收数据,通过methods方法改变数据。而这个公用平台可以实现组件与组件之间的信息传递,从而实现组件之间的交互。

通过一个星期的实战,深深的体会到了vue的优势,在构建移动端这方面的效率很高。但在搭建的过程中,还是少不了与jQuery结合,毕竟每个工具都有其优点,择其优而用是明智的选择。


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/yw/13077371.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-30
下一篇 2023-05-30

发表评论

登录后才能评论

评论列表(0条)

保存