# vue-xiaotuxian-shop
**Repository Path**: shiyu228/vue-xiaotuxian-shop
## Basic Information
- **Project Name**: vue-xiaotuxian-shop
- **Description**: 仿写黑马的小兔鲜儿,基于vue3实现的小兔鲜电商项目,应用了大多数技术栈,还有组件的封装和第三方组件的使用,以及第三方包和插件的使用
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2022-08-23
- **Last Updated**: 2024-12-12
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
---
typora-root-url: ./
---
# vue3小兔鲜儿项目
vue3最大的特点:
**组合API**(Composition API)
# 运行项目
1.进入目录
```
cd vue-eribbit-shop
```
2.启动项目
```
npm run serve
```
3.访问
```
http://localhost:8080/
```
# 使用技术
- vue3.0(使用组合api的方式来开发)
- vue-cli(项目脚手架)
- axios(请求接口)
- Vue-Router(单页路由)
- vuex(状态管理)
- vuex-oersistedstate(vuex数据持久化)
- normalize.css(初始化样式)
- vueuse/core(组合api常用工具库)
- 算法Power Set
- dayjs(日期处理)
- vee-validate(表单校验)
# 重点难点
- 第三方登录
- 商品详情
- 购物车
- 支付结算
- 订单管理
# 2022/8/23
# 一、vue3复习
## 1.vite基本使用
vite是一个更轻量级的vue项目脚手架工具
创建
```
npm init vite-app vue-shop
```
装包
```
npm i
```
运行
```
npm run dev
```
## 2.分析目录
(1)main.js
```
//主要职责:创建一个vue应用
//1.导入createApp函数从vue中
//2.创建一个根组件App.vue导入到main.js
//3.使用createApp创建实例
//4.应用实例挂载到#app容器中
import {createApp} from 'vue'
import App from './App'
const app=createApp(App)
app.mount('#app')
```
## 3.选项API和组合API
Option API(vue2):data,methods,created...
Composition API (vue3):setup
> setup
>
> 1、组合API的起点,将来的组合API的代码基本上都写在这里面
>
> 2、可以理解为:在beforeCreated钩子执行前执行,组件实例创建前
>
> 3、函数中不能使用this ==》报错undefined
>
> 4、模板中需要使用数据和函数,需要在setup中返回
>
> 注意:return 一个对象
```
setup(){
console.log('setup',this) //setup undefined
const msg='hello'
const say=()=>{
console.log('world')
}
// 必须返回
return {msg,say}
}
```
## 4.vue3生命周期
- setup 创建实例前
- onBeforeMount 挂载DOM前
- onMounted 挂载DOM后
- onBeforeUpdate 更新组件前
- onUpdated 更新组件后
- onBeforeUnmounted 销毁组件前
- onUnmounted 销毁组件后
> 导入API
>
> import {onBeforeMount ,onMounted } from 'vue'
>
> 注意:是从vue中导入
## 5.组合API-reactive函数
定义响应式数据
- reactive是一个函数,它可以定义一个复杂数据类型,成为响应式数据
- 通常用来定义响应式数据
```
const obj=reactive({
name:'ls',
age:18
})
// 修改数据
updateName=()=>{
obj.name='zs'
}
```
## 6.组合API-toRef函数
toRef转换为响应式数据包装成对象,
> 获取值的时候,需要使用.value
```
const obj=reactive({
name:'ls',
age:18
})
const name=toRef(obj,'name')
// 修改数据
updateName=()=>{
// 需要通过.value来修改数据
name.value='zs'
}
```
## 7.组合API-toRefs函数
toRef每次只能转换一个属性,就很麻烦,toRefs就可以解决这个问题
toRefs函数定义转换响应式中所有属性为响应书数据,通常用于解构|展开reactive定义的对象
> 如果单纯的解构或者扩展对象之后就不是响应式数据了
>
> 例如:const obj={...obj}
```
const obj=reactive({
name:'ls',
age:18
})
const obj1=toRefs(obj)
// 修改数据
updateName=()=>{
// 需要通过.value来修改数据
obj1.name='zs'
}
return {...obj}
```
## 8.组合API-ref函数
> 作用:一般用于简单数据类型,使用ref函数定义响应式函数
>
> 1、获取值的时候,需要使用.value
>
> 2、在模板中使用ref声明的数据不需要使用.value
```
{{name}}
setup(){
const name=ref('lisi')
const age=ref(10)
return {name,age}
updateName=()=>{
// 需要通过.value来修改数据
name.value='zs'
}
}
```
使用场景:
- 当明确知道需要的是一个响应式数据对象,就使用reactive
- 其它情况使用ref
## 9.组合API-computed函数
> 1、计算属性:当需要依赖现有的响应式数据,根据一定逻辑得到一个新的数据
>
> 2、计算属性要有一个return值
>
> 3、computed是不能绑定v-model的(只能读取)
```
setup(){
const age=ref(10)
// 计算属性
const updateAge=computed(()=>{
return age.value+2
})
return {age,updateAge}
}
```
computed的高级用法,这样我就可以绑定v-model(但是不常用)
```
setup(){
const age=ref(10)
// 计算属性
const updateAge=computed({
get(){
return age.value+2
},
// 当给计算属性赋值时触发
set(value){
age.value=value-2
}
)
return {age,updateAge}
}
```
总结:计算属性的两种用法
- 给computed传入函数,返回值就是计算属性的值
- 给computed传入对象,get获取计算属性的值,set监听计算属性的改变
## 10.组合API-watch函数
目标:掌握使用watch
> 1、监听某个属性的数据变化
```
setup(){
const count=ref(10)
const add=()=>{
count.value++
}
// 监听一个ref数据
// 第一个参数 需要监听的目标 count
// 第二个参数 改变后的触发函数
watch(count,(newVal,oldVal)=>{
console.log(newVal,oldVal)
})
}
```
> 2、监听多个数据的变化
```
watch([count,name,obj],()=>{})
```
> 3、监听对象中某个属性的变化
>
> 注意:需要写成函数返回该属性你的方式才能监听到
```
watch(()=>obj.name,()=>{})
```
!!!!reactive声明的响应式数据具有深度监听功能,不用使用deep了
> deep:深度监听
>
> immediate:立即执行
## 11.组合API-ref属性
注意和vue2区分开
> 1、通过ref属性绑定ODM元素
>
> 2、通过ref.value获取元素
>
> 使用:
>
> 1.先定义一个空的响应式数据ref
>
> 2.setup中返回该数据,你想获取那个dom元素,在该元素上使用ref属性绑定数据即可
```
hello
setup(){
// 1.先定义一个空的响应式数据ref
// 2.setup中返回该数据,你想获取那个dom元素,在该元素上使用ref属性绑定数据即可
const box=ref(null)
onMounted(()=>{
console.log(boxRef.value)
})
return {box}
}
```
## 12.组合API-父子通信
> 目标:掌握props和$emit实现组件通信
**1.父传子**
父组件
```
```
子组件
你哈,世界
{{money}}
**2.子传父**
> 通过emit向父组件传递自定义事件
父组件
```
```
子组件
```
你哈,世界
{{money}}
```
> 注意:emit写在setup参数中
>
> setup(props,{emit})
## 13.组合API-依赖注入
父组件
```
{{money}}
```
后代组件
```
你哈,世界
{{money}}
```
#### 6.实现鼠标经过容器上移阴影动画效果
```
// 实现鼠标经过容器上移阴影动画效果
.hoverShadow(){
transition: all .5s;
&:hover{
transform: translate3d(0,-3px,0);
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.2);
}
}
```
#### 7.实现ul盒子移动
主要是通过transformX移动的,依赖index索引
```
-
```
# 2022/9/3
## 七、首页主体
#### 1.图片懒加载
WebAPI:IntersectionObserver
```
// 导入默认图片
import defalutImg from '@/assets/images/200.png'
export default {
install (app) {
defineDirective(app)
}
}
// 指令
const defineDirective = (app) => {
// 图片懒加载指令
app.directive('lazy', {
mounted (el, binding) {
const observe = new IntersectionObserver(([{ isIntersecting }]) => {
// 如果进入可视区域
if (isIntersecting) {
// 停止观察
observe.unobserve(el)
el.onerror = () => {
// 设置请求错误时的默认图片
el.src = defalutImg
}
el.src = binding.value
}
}, {
threshold: 0.01
})
// 观察
observe.observe(el)
}
})
}
```
#### 2.封装面包屑导航
参考element-UI组件
bread组件:
```
```
bread-item组件
```
```
# 2022/9/6
## 八、分类部分
#### 1.组件批量注册
方法:
> 1、使用require提供的函数context加载某一个目录下的所有.vue后缀的文件
>
> 2、context函数会返回一个导入函数importFn,它有一个属性keys()获取所有文件的路径
>
> 3、通过文件路径数组,遍历数组,再使用importFn根据路径导入组件对象
>
> 4、遍历的同时进行全局注册即可
```
/**
* 参数1:加载文件的目录
* 参数2:是否加载子目录
* 参数3:正则,匹配的文件
*/
const importFn = require.context('./', false, /\.vue$/)
export default {
install (app) {
importFn.keys().forEach(key => {
const component = importFn(key).default
app.component(component.name, component)
})
}
}
```
#### 2.watch监听路由变化
```
import { ref, watch } from 'vue'
import { useRoute } from 'vue-router'
// 监听路由发生变化时发起请求获取二级分类的推荐数据
watch(() => route.params.id, newValue => {
newValue && getSubList()
}, {
immediate: true
})
```
#### 3.vue中的transition过度组件
```
首页
{{subList.name}}