1.给窗口监听滚动事件获得距离顶部的像素值
// 封装各种逻辑函数方法
// 1. 先完成函数的架子(参数+返回值)
// 2. 实现核心逻辑
import { ref } from 'vue'
export function useWindowScroll () {
// 1. y是一个响应式数据
// 2. 返回的是一个对象
const y = ref(0)
// 核心逻辑:在滚动事件中不断拿到距离顶部的像素值
window.addEventListener('scroll', () => {
// 获取一下距离顶部的像素值
const scrollTop = document.documentElement.scrollTop
// 把像素值 交给我们用来使用的响应式数据y
y.value = scrollTop
})
return {
y
}
}
给div 一个属性判断 大于多少的时候为true
<div class="app-header-sticky" :class="{show: y > 78}">
2. Home-骨架组件优化
1.写两个tempalate标签 通过判断渲染数据的长度,判断显示那个标签
2.通过全局注册的组件来写骨架屏 通过往组件里传入数据来显示骨架屏的宽高,
3.最后渲染数据,循环显示骨架屏
<!-- 骨架屏模板 用骨架屏小组件 搭建一个类似于真实结构的模板出来-->
<!--
加不加冒号都是父传子 都可以传过去
加冒号 -> 识别类型 响应式数据 (number,布尔值,数组,对象)
不加冒号 -> 字符串
-->
<ul class="menu">
<li v-for="i in 9" :key="i">
<XtxSkeleton
:width="40"
:height="20"
style="margin-right: 5px"
bg="rgba(255,255,255,0.2)"
/>
<XtxSkeleton
:width="50"
:height="20"
bg="rgba(255,255,255,0.2)"
style="margin-right: 5px"
/>
<XtxSkeleton :width="50" :height="20" bg="rgba(255,255,255,0.2)" />
</li>
</ul>
</template>
3.新鲜好物组件的封装和利用
/**
思路:
1. 不管其他事儿 先把一个基础的静态结构搭建起来
2. 找到那些可能由于使用的地方不同 可变的地方
主标题 副标题 右侧内容 列表主体内容
3. 把可变的那些部分 转化成组件props或者是插槽
props -> 数据 主标 + 副标题
slot -> 模板(html) 右侧 + 列表主体
组件传参的思想
基于组件本身 说一下参数传递的事儿
一个组件 -> 函数
函数 可以接收参数 返回值(一个函数执行完毕之后 你可以得到什么)
function get(num,name,cb){
}
组件 可以接收参数 props(数据 类型) + slot(模板 html)
返回值? 最终呈现到浏览器中的UI
UI = fn(state) 组件 确实就是一个函数
*/
1.通过封装组件来完成布局
1.引入并使用组件 通过插槽技术和组件传值来完成
<homePannelVue title="人气推荐" sub-title="新鲜出炉 品质靠谱">
<template #right>
<XtxMore />
</template>
<template #main>
<!-- 数据列表 -->
<ul class="goods-list">
<li v-for="item in hotData" :key="item.id">
<RouterLink to="/">
<!-- 把原来的src去掉 由我们的指令接管 -->
<img alt v-img-lazy="item.picture"/>
<p class="name">{{ item.title }}</p>
<p class="desc">{{ item.alt }}</p>
</RouterLink>
</li>
</ul>
</template>
</homePannelVue>
4.图片懒加载
// vue3有什么变化?
// 插件?
// 1. 定义插件 2.注册插件
// 定义插件 俩种方式 对象定义法 函数定义法
/*
// vue2 定义
const plugin = {
install (Vue) {
// 插件的逻辑
}
}
// 如果是函数定义的话 函数本身会被当成 install方法执行
function plugin(Vue){
// 插件的逻辑
}
// 注册 调用use方法的时候 会自动执行插件的install方法并且会自动把Vue构造函数传入
// install方法中
Vue.use(plugin)
*/
/**
vue3
先定义 再注册
定义的俩种写法也没有变化 对象定义法 + 函数定义法
const plugin = {
install(app){
// 插件逻辑
}
}
// 当执行use方法的时候 应用实例对象app会自动当成实参传入install方法
createApp().use(plugin)
*/
/**
* vue2
Vue.direactive('指令名称',{
inserted(el, binding){
// el: 指令挂在哪个元素 就指的是那个dom对象
// binding.value: 指令等于号后面的表达式的值
}
})
<img v-指令名称="表达式"/>
vue3
createApp() -> app
app.direactive('指令名称',{
mounted(el, binding){
// el: 指令挂在哪个元素 就指的是那个dom对象
// binding.value: 指令等于号后面的表达式的值
}
})
*/
import { useIntersectionObserver } from '@vueuse/core'
const plugin = {
install (app) {
console.log('插件已经注册好了', app)
// 定义指令
app.directive('img-lazy', {
mounted (el, binding) {
console.log(el, binding.value)
// 在这里写核心逻辑 架子已经都搭好了
// 核心思想:监控图片是否进入到视口区域 如果进来才发送图片请求
// 技术点:1. 如何知道图片进入到视口了? 2. 如何发送请求?
// vueUse img.src = 'url'
const { stop } = useIntersectionObserver(
el,
([{ isIntersecting }], observerElement) => {
// isIntersecting: 布尔值 true代表监听的元素已经进入了视口
// false代表监听的元素离开了视口
// 这个函数的监听很精确 不光可以横向 还有纵向
// 这个回调在每次进入离开视口都会不断执行
// 图片一旦请求回来之后 就不需要你这个监听逻辑了?
console.log(isIntersecting)
if (isIntersecting === true) {
// ? 当前图片进入视口了 赋值src正式发送图片请求
el.src = binding.value
// 优化 停止监听
stop()
}
},
// threshold: 0 - 1 值越小 代表进入的视口的面积越小就会触发
// 反之越大触发 0 img刚刚露头就触发 1 完全暴露在视口中才会触发
{ threshold: 0 }
)
}
})
}
}
export default plugin
5.完成路由组件和跳转
1.在路由界面配置子路由
{
path: '/Login',
component: Login
},
{
path: '/',
component: Layout,
children: [
{
path: '', // ? 如果二级路由的path为空串的时候 当前的二级路由将作为默认二级路由显示
component: Home
},
{
// 添加动态路由参数 用占位符站位 /:id
path: 'category/:id',
component: Category
}
]
}
]
2.在需要做跳转的页面加上
<RouterLink :to="`/category/${item.id}`">{{item.name}}</RouterLink>
- 需要传参加模板字符串
query 是 ?传参 params 是 :传参 路径传参
6.通过从路径上拿参数
import { ref } from 'vue'
import { findTopCategory } from '@/api/category'
import { useRoute } from 'vue-router'
export function useCategory () {
const categoryData = ref({})
const route = useRoute() // this.$route
async function loadCategory () {
// id? 路由上面获取的? this.$route.params.id
// setup使用路由参数? useRoute
// 如果想要路由跳转? useRouter this.$router
const res = await findTopCategory(route.params.id)
categoryData.value = res.data.result
}
loadCategory()
return {
categoryData
}
}
主页面解构拿参数 const {categoryData} =useCategory ()