# 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 ``` 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属性绑定数据即可 ``` setup(){ // 1.先定义一个空的响应式数据ref // 2.setup中返回该数据,你想获取那个dom元素,在该元素上使用ref属性绑定数据即可 const box=ref(null) onMounted(()=>{ console.log(boxRef.value) }) return {box} } ``` ## 12.组合API-父子通信 > 目标:掌握props和$emit实现组件通信 **1.父传子** 父组件 ``` ``` 子组件 **2.子传父** > 通过emit向父组件传递自定义事件 父组件 ``` ``` 子组件 ``` ``` > 注意:emit写在setup参数中 > > setup(props,{emit}) ## 13.组合API-依赖注入 父组件 ``` ``` 后代组件 ``` ``` #### 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过度组件 ```