# 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
# 知乎专栏仿写

## 一、项目搭建
```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
Loading...
```
#### 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 组件编写