# zhihu-imitate **Repository Path**: CodingGorit/zhihu-imitate ## Basic Information - **Project Name**: zhihu-imitate - **Description**: 基于 Vue3 + TypeScirpt + BootStrap 实现的仿知乎专栏项目,使用 Vuex 实现数据存储,封装通用业务组件库,项目对接真实的后端接口,实现登录和注册、文件上传、专栏编辑和删除等功能; - **Primary Language**: JavaScript - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-12-14 - **Last Updated**: 2026-01-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: 组件库, Vue ## README # 知乎专栏仿写 ![Alt text](image.png) ## 一、项目搭建 ```shell // 初始化项目 npm install -g yarn // 创建项目,并选择 vue3 + ts,如果没有安装 vite,先安装 vite yarn create vite zhihu-imitate cd zhihu-imitate // 安装环境 yarn yarn dev ``` ## 二、功能开发 及 技术亮点 Vue3 + TypeScript + Vuex + Vue Router 实现前后端分离项目 结合 BootStrap 实现通用业务组件库 使用后端 API 权限和管理和控制 自定义 hooks 编程式组件( 使用 createApp + mount 的形式来创建组件) ### 2.1 自定义 HOOKS > 实现组件复用 1. useMousePosition(获取鼠标的焦点) 2. useURLLoader(axios 加载实现内容) 3. useClickOutside (监听鼠标点击元素外部事件) 4. useDOMCreate (自定义 dom 创建 以及 结合 teleport) ### 2.2 vue3 内置组件使用 #### 2.2.1 Suspense > 结合 Promose,异步组件 拥有两个状态: 1. default(正常显示) 2. fallback(还没加载好) ```html ``` #### 2.2.2 teleport modal 使用 ### 2.3 自定义模态框(Modal) > 没有全局注册,所以作为局部组件使用 ```js import Modal from './components/Modal.vue'; ``` ### 2.3 自定义组件开发心得 - watch 的使用场景,监听属性状态变化 ### 2.4 如何给子组件实现 v-model 功能 > 见 validate-input 组件 1. props 接收一个 modalValue 的属性 2. 在定义 emit 的时候,属性增加这个 modal 参数 3. 该提交解决了子组件 v-model 不生效的问题 ```js // const emit = defineEmits(['update:modelValue']); /** * PS: 仅在 TypeScript 环境下生效 * 事件与 props 绑定 * @Refer https://v3.cn.vuejs.org/api/sfc-script-setup.html#%E4%BB%85%E9%99%90-typescript-%E7%9A%84%E5%8A%9F%E8%83%BD */ const emit = defineEmits<{ (e: 'update:modalValue', value: string): void }>(); ``` 3. 想办法在子组件拿到用户输入的值,并通过 emit 回去 ```js emit('update:modalValue', targetValue); ``` ### 2.5 非 prop 属性 ? inheritAttrs && $attr ? inheritAttrs 在 setup 中用不了的问题 ```typescript defineOptions({ inheritAttrs: false }) ``` [禁用 Attributes 继承](https://cn.vuejs.org/guide/components/attrs.html#disabling-attribute-inheritance) 在开发 validate-input 时, 我们给其添加一些HTML 标签内置属性时,遇到属性加到了父容器标签上 > 查阅文档得知, 非 prop 属性, 需要通过 inheritAttrs: false 关闭默认行为, 设置透传了还不够,需要使用 v-bind="$attrs" 来访问这些 `非 prop 属性` 非 props Attribute 问题 1. 组件外传入自定义属性 2. 组件使用 v-bind="$attrs" 3. 在定义 inheritAttrs: false 即可 ### 2.6 全局状态管理工具 > 基本准则 1. 一个类似 object 的全局数据结构 — 称之为 store 2. 只能调用一些特殊方法来实现数据修改 ### 2.7 使用 FormData 对象上传 form 数据 ```typescript const handleFileChange = (e: Event) => { const target = e.target as HTMLInputElement; const files = target.files; // 列表 if (files) { const uploadedFile = files[0]; const formData = new FormData(); formData.append(uploadedFile.name, uploadedFile); axios.post('/api/upload', formData, { headers: { 'Content-Type': 'multipart/form-data' } }).then((resp: any) => { console.log(resp); }) } } ``` ## 三、项目依赖 1. vue3.2 2. axios 3. typescript 支持 4. BootStap 5.x 5. 运行依赖:@types/node 6. 新增 mitt 3.0.0 依赖,用来监听组件,事件([mitt](https://github.com/developit/mitt)) 7. 新增 vue-router4.x ## 四、一个 Vue 项目结构有哪些? - 数据的展示 - 最好有多级负责数据的展示 - 数据的创建 - 可以发散多个功能 - 组件的抽象 - 循序渐进组件的开发 - 整体状态数据结构的设计与实现 - 权限管理和控制 - 真实的后端 API ## 五、更新日志 - 使用 map 优化存储结构,提升性能 - 给 slot,template 中添加属性,给外部访问. Upload 上传组件开发, setup 语法糖中,inheritAttrs 写法有区别 - Loader 组件开发, 登录逻辑优化,使用 `axios.defaults.headers.common['Authorization']` 实现常用 header 请求头, 新增 useDONCreate hooks - 使用 vuex action 发送异步请求, 使用 async、await 优化 action 异步请求 - 重新巩固项目, 完善 README, 修复 mitt 3.x 版本 ts 编译报错问题 - 解决了 validate-input 中,子组件 v-model 拿不到值的情况 - 新增 Vuex,用于 login page - 新增 PostList 组件,完善 ColumnList,新增 mock 数据 和 types 类型定义 - 新增路由组件 vue-router@next,使用 router-view,router-link。 useRoute 获取路径参数,useRouter 实现编程式跳转 - 完善 validate-form 和 validate-input 控件,新增 mitt 依赖 - 完善 validate-input组件,新增 v-model 功能, 新增非 props 组件防止获取自定义属性 - 完成 form 表单单个组件, validate-input 组件编写,及完善优化 - 完成 Dropdown 和 DropdownItem 组件的编写,useClickOutside hook 的编写 - 完成 ColumnList 和 GlobalHeader 组件编写