## 项目介绍
> Vue3.x的推出让vue.js在2021年又再一次成为开发者受青睐的前端框架。
> [Vue3WChat聊天项目](https://blog.csdn.net/yanxinyun1990/article/details/112355981) 使用vue3.x+@vue/cli+vuex+vue-router+vant-ui3.x等技术架构的移动端仿微信聊天实例。支持发送消息/emoj图、图片/视频查看、网址预览、红包/朋友圈等功能。
![](https://oscimg.oschina.net/oscnet/up-4d7c98c793aa2b20930c887e3620a1b97e1.png)
`vue3.x+vant-ui` 实现仿`微信朋友圈`功能。
![](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3f4f9f90683440d39f3e3c9912f34474~tplv-k3u1fbpfcp-watermark.image)
## 框架技术
- 编码+技术:Vscode + Vue3/Vuex4/Vue-Router4
- UI组件库:Vant3.x (有赞移动端vue3.0组件库)
- 弹层组件:V3Popup(基于vue3自定义弹层组件)
- iconfont图标:阿里字体图标库
- 自定义顶部Navbar+底部Tabbar组件
## 项目结构
![](https://oscimg.oschina.net/oscnet/up-f45da6144c825776973de7672cddab12718.png)
![](https://oscimg.oschina.net/oscnet/up-3d232fd526d14ea436bff7e104fe4013a40.png)
![](https://image-static.segmentfault.com/111/819/1118197263-5ff809670370d_articlex)
![](https://oscimg.oschina.net/oscnet/up-eeaff96aa696c4e0fb2ceaf8ccca41946ad.png)
![](https://oscimg.oschina.net/oscnet/up-ff8bc4a7103babc6c4116b787c9223a266f.png)
![](https://oscimg.oschina.net/oscnet/up-7c62f617aac010b80b78f27907830589009.png)
![](https://oscimg.oschina.net/oscnet/up-2cb347591f9a415e67ed98f20b7db213f99.png)
![](https://oscimg.oschina.net/oscnet/up-4c1f58d2d565c42ee9b1f1983d4d4b2f53e.png)
![](https://oscimg.oschina.net/oscnet/up-422e2dca7979cd2459312f41355477cb989.png)
![](https://oscimg.oschina.net/oscnet/up-ebc16c4ff45ff348d9d9d956ffeb8c7c3fc.png)
![](https://oscimg.oschina.net/oscnet/up-10764305ec64574bf81edd4cddb3d415d2d.png)
![](https://oscimg.oschina.net/oscnet/up-bee141b69db5f4541e39d3f2a9a40a8929a.png)
![](https://oscimg.oschina.net/oscnet/up-5e054f264e5ef0884e77565fef51ddd9aa7.png)
![](https://oscimg.oschina.net/oscnet/up-7213c999d62d47cd13ef08d3dd847d972ef.png)
![](https://oscimg.oschina.net/oscnet/up-add561d07ba1f4b69b63d73ef2efc8a11f0.png)
![](https://oscimg.oschina.net/oscnet/up-4c31134468c8b9078bcf3ee3cde78403766.png)
## vue3.0自定义全局弹层
大家看到的项目中所有弹框场景,都是使用vue3自定义组件实现。
![](https://image-static.segmentfault.com/279/781/2797817210-5fec1fd1df93e_articlex)
v3popup 一款集合了众多弹框类型的vue3手机端自定义弹框组件。
[vue3.x自定义组件系列:vue3移动端弹框组件v3popup](https://blog.csdn.net/yanxinyun1990/article/details/111975487)
## vue3.0配置文件
使用vue.config.js进行一些简单的项目配置。
```
const path = require('path')
module.exports = {
// 基本路径
// publicPath: '/',
// 输出文件目录
// outputDir: 'dist',
// assetsDir: '',
// 环境配置
devServer: {
// host: 'localhost',
// port: 8080,
// 是否开启https
https: false,
// 编译完是否打开网页
open: false,
// 代理配置
// proxy: {
// '^/api': {
// target: '<url>',
// ws: true,
// changeOrigin: true
// },
// '^/foo': {
// target: '<other_url>'
// }
// }
},
// webpack配置
chainWebpack: config => {
// 配置路径别名
config.resolve.alias
.set('@', path.join(__dirname, 'src'))
.set('@assets', path.join(__dirname, 'src/assets'))
.set('@components', path.join(__dirname, 'src/components'))
.set('@views', path.join(__dirname, 'src/views'))
}
}
```
## vue3.0引入公共组件/样式
对main.js主入口页面进行一些配置,使得引入公共组件/样式、路由和vuex。
```
import { createApp } from 'vue'
import App from './App.vue'
// 引入vuex和路由配置
import store from './store'
import router from './router'
// 引入js
import '@assets/js/fontSize'
// 引入公共组件
import Plugins from './plugins'
const app = createApp(App)
app.use(store)
app.use(router)
app.use(Plugins)
app.mount('#app')
```
## vue3.0表单验证
因为vue3.x中没有this,只能使用getCurrentInstance来获取上下文操作。
```
<script>
import { reactive, inject, getCurrentInstance } from 'vue'
export default {
components: {},
setup() {
const { ctx } = getCurrentInstance()
const v3popup = inject('v3popup')
const utils = inject('utils')
const formObj = reactive({})
// ...
const handleSubmit = () => {
if(!formObj.tel){
Snackbar('手机号不能为空!')
}else if(!utils.checkTel(formObj.tel)){
Snackbar('手机号格式不正确!')
}else if(!formObj.pwd){
Snackbar('密码不能为空!')
}else{
ctx.$store.commit('SET_TOKEN', utils.setToken());
ctx.$store.commit('SET_USER', formObj.tel);
// ...
}
}
return {
formObj,
handleSubmit
}
}
}
</script>
```
## vue3.0聊天部分
聊天编辑框部分封装了一个公共组件Editor,使用div可编辑contenteditable属性实现功能。
![](https://image-static.segmentfault.com/129/669/1296690296-5ff80f791f496_articlex)
```
<template>
<div
ref="editorRef"
class="editor"
contentEditable="true"
v-html="editorText"
@click="handleClick"
@input="handleInput"
@focus="handleFocus"
@blur="handleBlur"
style="user-select:text;-webkit-user-select:text;">
</div>
</template>
```
vue3获取光标位置,在光标处插入emoj表情。
```
/**
* @Desc Vue3.0实现文字+emoj表情混排
* <a href="/user/Time" title="@Time">@Time</a> andy by 2021-01
* @About Q:282310962 wx:xy190310
*/
<script>
import { ref, reactive, toRefs, watch, nextTick } from 'vue'
export default {
props: {
modelValue: { type: String, default: '' }
},
setup(props, { emit }) {
const editorRef = ref(null)
const data = reactive({
editorText: props.modelValue,
isChange: true,
lastCursor: null,
})
// ...
// 获取光标最后位置
const getLastCursor = () => {
let sel = window.getSelection()
if(sel && sel.rangeCount > 0) {
return sel.getRangeAt(0)
}
}
// 光标处插入内容 @param html 需要插入的内容
const insertHtmlAtCursor = (html) => {
let sel, range
if(window.getSelection) {
// IE9及其它浏览器
sel = window.getSelection()
// ##注意:判断最后光标位置
if(data.lastCursor) {
sel.removeAllRanges()
sel.addRange(data.lastCursor)
}
if(sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0)
let el = document.createElement('div')
el.appendChild(html)
var frag = document.createDocumentFragment(), node, lastNode
while ((node = el.firstChild)) {
lastNode = frag.appendChild(node)
}
range.insertNode(frag)
if(lastNode) {
range = range.cloneRange()
range.setStartAfter(lastNode)
range.collapse(true)
sel.removeAllRanges()
sel.addRange(range)
}
}
} else if(document.selection && document.selection.type != 'Control') {
// IE < 9
document.selection.createRange().pasteHTML(html)
}
// ...
}
return {
...toRefs(data),
editorRef,
handleInput,
handleDel,
// ...
}
}
}
</script>
```
ok,基于vue3开发仿制微信聊天界面实例暂时就分享到这里。后续还会分享一些vue3实战开发。
![](https://oscimg.oschina.net/oscnet/up-21c6790fe77f33db7625477c8073bd8354c.png)
有疑问加站长微信联系(非本文作者)