当前位置:   article > 正文

分享记录vue3+ts基于element-plus通过父子组件交互实现聊天窗口的转发弹框,支持多选、单选、搜索等基础功能。开整_vue实现一个聊天对话框

vue实现一个聊天对话框

一、先下载引入element-plus
//直接冲官网指南
https://element-plus.gitee.io/zh-CN/guide/installation.html
//我这边用的scss预处理,直接下载就好了
npm install sass

二、子组件实现代码
//html代码
<template>
    <div>
        <el-dialog v-model="dialogVisible" :show-close="false" :close-on-click-modal="false">
            <div class="dialog">
                <div class="fs-16 bold c-0">选择好友<span class="fs-12 c-80">{{ contactList.length }}/{{ contacts.length
                }}</span><span style="margin-left: 200px;cursor:pointer" @click="chooses()">{{ choose == 1 ? '单选' : '多选'}}</span></div>
                <el-input v-model="contact" placeholder="搜索" clearable :prefix-icon="Search" @input="search" />
                <div class="list">
                    <el-scrollbar height="420px">
                        <div class="li" v-for="(item, index) in contacts" :key="index" @click="forwarding(item)">
                            <img :src="item.choose ? 'https://pic.imgdb.cn/item/6426503fa682492fcc5e327d.png' : 'https://pic.imgdb.cn/item/64265063a682492fcc5e65ad.png'"
                                alt="" class="li-left">
                            <div class="li-right">
                                <img src="https://pic.imgdb.cn/item/64265077a682492fcc5e7d6f.gif" alt="">
                                <!-- <img :src="item.img" alt=""> -->
                                <div class="fs-14 c-3">{{ item.name }}</div>
                            </div>
                        </div>
                    </el-scrollbar>
                </div>
                <div class="bottom">
                    <el-button type='primary' text @click="cancel">取消</el-button>
                    <el-button type='primary' text @click="determine">确认</el-button>
                </div>
            </div>
        </el-dialog>
    </div>
</template>
//组件通过dialog控制和scrollbar滚动条实现,所以先引用这2个组件
import { ref, toRefs, watch } from 'vue'
import { ElScrollbar, ElMessage, } from 'element-plus';
import { Search } from '@element-plus/icons-vue'

//然后定义组件的初始值,组件状态以及组件接受的参数等
let props = defineProps({
    dialogShow: {
        type: Boolean,
        default: false,
    },
});
const refProps = toRefs(props)
const emit = defineEmits(['getContact', 'contactShow'])
let dialogVisible = ref(props.dialogShow)//本地组件状态
watch(refProps.dialogShow, (val, old) => {
    dialogVisible.value = val
}, { deep: true })//监听修改本地
let contact = ref('')//联系人搜索
let contactList = ref([] as any)//选中转发的联系人
let choose = ref(2)//单选为1 多选为2
let contacts: any = ref([{
    img: '',
    name: 'Lingzi',
    choose: false,
    id: 1,
}, {
    img: '',
    name: 'zhangsan0',
    choose: false,
    id: 2,
}, {
    img: '',
    name: 'lisi',
    choose: false,
    id: 3,
}, {
    img: '',
    name: 'Wanger',
    choose: false,
    id: 4,
}, {
    img: '',
    name: 'yangyu',
    choose: false,
    id: 5,
}, {
    img: '',
    name: '007',
    choose: false,
    id: 6,
}, {
    img: '',
    name: 'YangyuS',
    choose: false,
    id: 7,
},])
let contactsCopy: any = ref(contacts.value)
//相关逻辑和方法
const chooses = () => {//单选多选切换
    choose.value = choose.value == 1 ? 2 : 1
    contacts.value.forEach((i:any)=>{
        i.choose=false
    })
    contactList.value=[]
}
const forwarding = (item: any) => {//选择
    if (choose.value == 1) {//单选
        if (!item.choose) {
            let y = contacts.value.some((i: any) => {
                return i.choose
            })
            if (y) {//有选中的
                contacts.value.forEach((item: any) => {
                    item.choose = false
                    contactList.value = []
                })
            }
        }
        item.choose = !item.choose
        if (item.choose) {
            contactList.value.push(item.name)
        } else {
            contactList.value = []
        }
    } else {//多选
        item.choose = !item.choose
        if (item.choose && contactList.value.indexOf(item.name) == -1) {
            contactList.value.push(item.name)
        } else if (!item.choose && contactList.value.indexOf(item.name) != -1) {
            contactList.value.splice(contactList.value.indexOf(item.name), 1)
        }
    }
};
const cancel = () => {//取消操作
    emit('contactShow', false)//通过emit传值给父组件
    contactList.value = []
    contacts.value.forEach((item: any) => {
        item.choose = false
    })
}
const determine = () => {//确定操作
    if (contactList.value && contactList.value.length) {
        emit('getContact', contactList.value)//把选中的信息传递给父组件
        cancel()
    } else {
        ElMessage.error('请选择转发的对象')
    }
}
const search = () => {//搜索
    if (contact.value == '') {
        contacts.value = contactsCopy.value
    }
    let arr = ref([] as any)
    contactsCopy.value.map((item: any) => {
        if (item.name.toLowerCase().indexOf(contact.value.toLowerCase()) != -1) {
            return arr.value.push(item)
        }
    })
    contacts.value = arr.value
}

三、父组件实现代码
//html代码
<el-button type="primary" @click="show()">打开弹框</el-button>
    <Dialog :dialogShow="dialogShow" @contactShow="contactShow" @getContact="getContact"></Dialog>

//js代码
import {ref} from 'vue'
import Dialog from '../components/forwarding.vue';
let dialogShow=ref(false)
const show=()=>{//控制子组件状态
    dialogShow.value=true
}
const contactShow = (e: boolean) => {//接受子组件传递过来的状态
  dialogShow.value = e
}
const getContact = (e: object) => {//接受子组件传递过来的状态
  console.log(e)
}
四、相关效果图

 


五、整体代码

  1. //父组件
  2. <template>
  3. <el-button type="primary" @click="show()">打开弹框</el-button>
  4. <Dialog :dialogShow="dialogShow" @contactShow="contactShow" @getContact="getContact"></Dialog>
  5. </template>
  6. <script setup lang="ts">
  7. import {ref} from 'vue'
  8. import Dialog from '../components/forwarding.vue';
  9. let dialogShow=ref(false)
  10. const show=()=>{//控制子组件显示
  11. dialogShow.value=true
  12. }
  13. const contactShow = (e: boolean) => {//接受子组件传递过来的状态
  14. dialogShow.value = e
  15. }
  16. const getContact = (e: object) => {//接受子组件传递过来的状态
  17. console.log(e)
  18. }
  19. </script>
  20. <style scoped lang="scss"></style>
  21. //子组件
  22. <template>
  23. <div>
  24. <el-dialog v-model="dialogVisible" :show-close="false" :close-on-click-modal="false">
  25. <div class="dialog">
  26. <div class="fs-16 bold c-0">选择好友<span class="fs-12 c-80">{{ contactList.length }}/{{ contacts.length
  27. }}</span><span style="margin-left: 200px;cursor:pointer" @click="chooses()">{{ choose == 1 ? '单选' : '多选'}}</span></div>
  28. <el-input v-model="contact" placeholder="搜索" clearable :prefix-icon="Search" @input="search" />
  29. <div class="list">
  30. <el-scrollbar height="420px">
  31. <div class="li" v-for="(item, index) in contacts" :key="index" @click="forwarding(item)">
  32. <img :src="item.choose ? 'https://pic.imgdb.cn/item/6426503fa682492fcc5e327d.png' : 'https://pic.imgdb.cn/item/64265063a682492fcc5e65ad.png'"
  33. alt="" class="li-left">
  34. <div class="li-right">
  35. <img src="https://pic.imgdb.cn/item/64265077a682492fcc5e7d6f.gif" alt="">
  36. <!-- <img :src="item.img" alt=""> -->
  37. <div class="fs-14 c-3">{{ item.name }}</div>
  38. </div>
  39. </div>
  40. </el-scrollbar>
  41. </div>
  42. <div class="bottom">
  43. <el-button type='primary' text @click="cancel">取消</el-button>
  44. <el-button type='primary' text @click="determine">确认</el-button>
  45. </div>
  46. </div>
  47. </el-dialog>
  48. </div>
  49. </template>
  50. <!-- 多选组件---------------- -->
  51. <script setup lang="ts">
  52. import { ref, toRefs, watch } from 'vue'
  53. import { ElScrollbar, ElMessage, } from 'element-plus';
  54. import { Search } from '@element-plus/icons-vue'
  55. let props = defineProps({
  56. dialogShow: {
  57. type: Boolean,
  58. default: false,
  59. },
  60. });
  61. const refProps = toRefs(props)
  62. const emit = defineEmits(['getContact', 'contactShow'])
  63. let dialogVisible = ref(props.dialogShow)//本地组件状态
  64. watch(refProps.dialogShow, (val, old) => {
  65. dialogVisible.value = val
  66. }, { deep: true })//监听修改本地
  67. let contact = ref('')//联系人搜索
  68. let contactList = ref([] as any)//选中转发的联系人
  69. let choose = ref(2)//单选为1 多选为2
  70. let contacts: any = ref([{
  71. img: '',
  72. name: 'Lingzi',
  73. choose: false,
  74. id: 1,
  75. }, {
  76. img: '',
  77. name: 'zhangsan0',
  78. choose: false,
  79. id: 2,
  80. }, {
  81. img: '',
  82. name: 'lisi',
  83. choose: false,
  84. id: 3,
  85. }, {
  86. img: '',
  87. name: 'Wanger',
  88. choose: false,
  89. id: 4,
  90. }, {
  91. img: '',
  92. name: 'yangyu',
  93. choose: false,
  94. id: 5,
  95. }, {
  96. img: '',
  97. name: '007',
  98. choose: false,
  99. id: 6,
  100. }, {
  101. img: '',
  102. name: 'YangyuS',
  103. choose: false,
  104. id: 7,
  105. },])
  106. let contactsCopy: any = ref(contacts.value)
  107. const chooses = () => {//单选多选切换
  108. choose.value = choose.value == 1 ? 2 : 1
  109. contacts.value.forEach((i:any)=>{
  110. i.choose=false
  111. })
  112. contactList.value=[]
  113. }
  114. const forwarding = (item: any) => {//选择
  115. if (choose.value == 1) {//单选
  116. if (!item.choose) {
  117. let y = contacts.value.some((i: any) => {
  118. return i.choose
  119. })
  120. if (y) {//有选中的
  121. contacts.value.forEach((item: any) => {
  122. item.choose = false
  123. contactList.value = []
  124. })
  125. }
  126. }
  127. item.choose = !item.choose
  128. if (item.choose) {
  129. contactList.value.push(item.name)
  130. } else {
  131. contactList.value = []
  132. }
  133. } else {//多选
  134. item.choose = !item.choose
  135. if (item.choose && contactList.value.indexOf(item.name) == -1) {
  136. contactList.value.push(item.name)
  137. } else if (!item.choose && contactList.value.indexOf(item.name) != -1) {
  138. contactList.value.splice(contactList.value.indexOf(item.name), 1)
  139. }
  140. }
  141. };
  142. const cancel = () => {//取消操作
  143. emit('contactShow', false)//通过emit传值给父组件
  144. contactList.value = []
  145. contacts.value.forEach((item: any) => {
  146. item.choose = false
  147. })
  148. }
  149. const determine = () => {//确定操作
  150. if (contactList.value && contactList.value.length) {
  151. emit('getContact', contactList.value)//把选中的信息传递给父组件
  152. cancel()
  153. } else {
  154. ElMessage.error('请选择转发的对象')
  155. }
  156. }
  157. const search = () => {//搜索
  158. if (contact.value == '') {
  159. contacts.value = contactsCopy.value
  160. }
  161. let arr = ref([] as any)
  162. contactsCopy.value.map((item: any) => {
  163. if (item.name.toLowerCase().indexOf(contact.value.toLowerCase()) != -1) {
  164. return arr.value.push(item)
  165. }
  166. })
  167. contacts.value = arr.value
  168. }
  169. </script>
  170. <style scoped lang="scss">
  171. .fs-16 {
  172. font-size: 16px;
  173. font-family: Source Han Sans CN;
  174. font-weight: 400;
  175. color: #333333;
  176. }
  177. .fs-12 {
  178. font-size: 12px;
  179. font-family: SourceHanSansSC;
  180. font-weight: 400;
  181. color: #999999;
  182. }
  183. .fs-14 {
  184. font-size: 14px;
  185. font-family: Source Han Sans CN;
  186. font-weight: 400;
  187. color: #FFFFFF;
  188. }
  189. .fs-20 {
  190. font-size: 20px;
  191. font-family: Source Han Sans CN;
  192. font-weight: 500;
  193. color: #333333;
  194. }
  195. .c-0 {
  196. color: #000000;
  197. }
  198. .c-3 {
  199. color: #333333;
  200. font-weight: 500;
  201. }
  202. .c-80 {
  203. color: #808080;
  204. }
  205. .bold {
  206. font-weight: bold;
  207. }
  208. :deep(.el-dialog) {
  209. width: 362px;
  210. height: 580px;
  211. background: #FFFFFF;
  212. border-radius: 6px;
  213. position: absolute;
  214. top: 2%;
  215. left: 40%;
  216. .el-dialog__header {
  217. padding: 0;
  218. }
  219. .el-dialog__body {
  220. padding: 0;
  221. }
  222. .dialog {
  223. padding: 20px;
  224. text-align: left;
  225. .el-input__wrapper {
  226. margin-top: 30px;
  227. padding: 0;
  228. border-bottom: 1px solid #f2f2f2;
  229. box-shadow: none
  230. }
  231. .list {
  232. margin-top: 2px;
  233. .li {
  234. display: flex;
  235. align-items: center;
  236. padding: 10px 0;
  237. // padding:0 20px;
  238. .li-left {
  239. width: 18px;
  240. height: 18px;
  241. margin-right: 10px;
  242. }
  243. .li-right {
  244. display: flex;
  245. align-items: center;
  246. img {
  247. width: 46px;
  248. height: 46px;
  249. border-radius: 50%;
  250. margin-right: 12px;
  251. }
  252. }
  253. }
  254. .li:hover {
  255. background: #e6eaf2;
  256. }
  257. }
  258. .bottom {
  259. display: flex;
  260. margin-top: 10px;
  261. justify-content: flex-end;
  262. }
  263. }
  264. }</style>

六、总结
一个简单的转发弹框,有相同业务逻辑的项目可以直接copy现用,代码写的有点渣,有相关代码优化的地方还望各位大佬能指点一二。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/355546
推荐阅读
相关标签
  

闽ICP备14008679号