vue3学习第三天

892 阅读4分钟

1.初始化样式

.ellipsis { white-space: nowrap; text-overflow: ellipsis; overflow: hidden; } // 文本超出一行显示...

.ellipsis-2 { word-break: break-all; text-overflow: ellipsis; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; } // 文本超出两行显示...

.clearfix:after { content: "."; display: block; visibility: hidden; height: 0; line-height: 0; clear: both; } // 单伪元素清除浮动

我们在配置玩less 文件 全局都要用 需要在main.js 导入

2.组件路由的使用

1.在 app.vue里设置挂载点 2.在首页里设置二级路由挂载点 3.把组件写好 4.在router/index.js里配置路由规则

import { createRouter, createWebHashHistory } from 'vue-router'

const Layout = () => import('@/views/Layout')

const Home = () => import('@/views/Home/index')

const routes = [ { path: '/', component: Layout, children: [ { path: '/', component: Home } // 如果二级路由的path设置为 '' 他会作为二级路由的默认显示 ] } ]

const router = createRouter({ history: createWebHashHistory(), routes })

export default router

3.less自动化的导入

1.例如手动准备变量文件

// 主题 @xtxColor:#27BA9B;

// 辅助 @helpColor:#E26237;

// 成功 @sucColor:#1DC779;

// 警告 @warnColor:#FFB302;

// 价格 @priceColor:#CF4444;

2.在app.vue 里进行测试

<template>
  <!-- 一级路由出口 -->
  <router-view />
  <div class="test">我是测试文字</div>
</template>

<style lang="less" scoped>
// 引入我们定义了less变化的文件
// ~线不能丢
@import "~@/styles/var.less";
.test {
  color: @xtxColor;
}
</style>

4.自动引入less方案

  1. vue add style-resources-loader 执行这个命令添加vue-cli的插件
  2. 在安装的选项里选择我们要用的语法
  3. 安装完毕后会在vue.config.js中添加一下配置
module.exports = {
  pluginOptions: {
    'style-resources-loader': {
      preProcessor: 'less',
      patterns: []
    }
  }
}

4.  把需要注入的文件写在里面 
const path = require('path')
module.exports = {
  pluginOptions: {
    'style-resources-loader': {
      preProcessor: 'less',
      patterns: [
        // 配置哪些文件需要自动导入
        path.join(__dirname, './src/styles/var.less')
      ]
    }
  }
}

5.顶部通栏的布局

1)在 public/index.html 引入字体图标文件

<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<link rel="stylesheet" href="//at.alicdn.com/t/font_2143783_iq6z4ey5vu.css">
<title><%= htmlWebpackPlugin.options.title %></title>

2).然后,新建头部导航组件

3)在 src/views/Layout.vue 中导入使用

头部布局

1)新建header头部组件

Layout/components/top-header.vue

2)在 src/views/Layout.vue 中导入使用

3)抽离header-nav组件

因为在后面的吸顶交互里,我们需要复用导航部分,所以这里我们先直接把他抽离成一个单独的组件

Layout/compoennts/header-nav.vue

底部 一样

6. 接口数据渲染导航

1.在 api 里定义接口数据

import request from '@/utils/request'

// 拉取导航数据
export function fetchCategory () {
  return request('/home/category/head', 'GET')
}

在组件里渲染出来

    <li class="home"><RouterLink to="/">首页</RouterLink></li>
    <li v-for="item in categoryList" :key="item.id">
      <RouterLink :to="`/category/${item.id}`">{{item.name}}</RouterLink>
    </li>
</ul>

<script>
import { ref } from 'vue'
import { fetchCategory } from '@/api/home'
export default {
  setup () {
    const categoryList = ref([])
    async function loadCategory () {
      const res = await fetchCategory()
      categoryList.value = res.data.result
    }
    loadCategory()

    return { categoryList }
  }
}
</script>

7. 吸顶头部交互实现

电商网站的首页一般都比较长,需要滚动查看内容,在查看的过程中用户可能会随着想去其他页面,此时需要一个吸顶的交互来让用户可以方便跳转

  1. 滚动距离大于等于78个px的时候,组件固定在视口顶部跟随页面移动
  2. 滚动距离小于78个px的时候,组件消失

实现思路

基于滚动事件,在滚动事件的回调函数中 不断的拿到当前距离顶部的像素值 如果像素值大于78 组件显示

如果小于78 组件隐藏

  1. 准备一个吸顶组件,准备一个类名,控制样式让其固定在顶部
  2. 监听页面滚动,判断滚动距离,距离大于78px添加类名,小于78px移除类名

1)安装@vueuse/core 包,它封装了常见的一些交互逻辑

yarn add @vueuse/core

2)在吸顶导航中使用

src/components/header-sticky.vue

  <div class="app-header-sticky" :class="{show:y >= 78}">
    <div class="container">
      <RouterLink class="logo" to="/" />
      <HeaderNav />
      <div class="left">
        <RouterLink to="/" >品牌</RouterLink>
        <RouterLink to="/" >专题</RouterLink>
      </div>
    </div>
  </div>
</template>

<script>
import HeaderNav from './header-nav'
import { useWindowScroll } from '@vueuse/core'
export default {
  name: 'AppHeaderSticky',
  components: { HeaderNav },
  setup () {
    // y表示具体顶部的滚动距离 会动态更新
    const { y } = useWindowScroll()
    return { y }
  }
}
</script>
<style scoped lang='less'>
.app-header-sticky {
  width: 100%;
  height: 80px;
  position: fixed;
  left: 0;
  top: 0;
  z-index: 999;
  background-color: #fff;
  border-bottom: 1px solid #e4e4e4;
  // 此处为关键样式!!!
  // 默认情况下完全把自己移动到上面
  transform: translateY(-100%);
  // 完全透明
  opacity: 0;
  // 显示出来的类名
  &.show {
    transition: all 0.3s linear;
    transform: none;
    opacity: 1;
  }
  .container {
    display: flex;
    align-items: center;
  }
  .logo {
    width: 200px;
    height: 80px;
    background: url("~@/assets/images/logo.png") no-repeat right 2px;
    background-size: 160px auto;
  }
  .right {
    width: 220px;
    display: flex;
    text-align: center;
    padding-left: 40px;
    border-left: 2px solid @xtxColor;
    a {
      width: 38px;
      margin-right: 40px;
      font-size: 16px;
      line-height: 1;
      &:hover {
        color: @xtxColor;
      }
    }
  }
}
</style>

8.配置 jsconfig.json文件

  "compilerOptions": {
      "target": "ES6",
      "module": "commonjs",
      "allowSyntheticDefaultImports": true,
      "baseUrl": "./",
      "paths": {
        "@/*": ["src/*"]
      }
  },
  "exclude": [
      "node_modules"
  ]
}

volar 插件 可以让vue3代码高亮 可以把模板 脚本分屏

9. Home- 分类和轮播图

1)拆分左侧分类组件

home/components/home-category.vue

  <div class="home-category">
     分类组件
  </div>
</template>

<script>
export default {
  name: 'HomeCategory'
}
</script>

2)拆分banner组件

home/components/home-banner.vue

  <div class="home-banner">
    banner
  </div>
</template>

<script>
export default {
  name: 'HomeBanner'
}
</script>

<style scoped lang='less'>
.home-banner {
  width: 1240px;
  height: 500px;
  position: absolute;
  left: 0;
  top: 0;
  z-index: 98;
}
</style>

3)home组件中引入使用

  <div class="page-home">
    <div class="home-entry">
      <div class="container">
        <!-- 左侧分类 -->
        <HomeCategory />
        <!-- banner轮播图 -->
        <HomeBanner/>
      </div>
    </div>
  </div>
</template>
<script>
import HomeCategory from './components/home-category'
import HomeBanner from './components/home-banner'
export default {
  name: 'PageHome',
  components: { HomeCategory, HomeBanner }
}
</script>

10.左侧导航栏的数据渲染

发送请求 渲染标签

11.把列表数据存入vuex 把三个页面的请求封装

1.在store/modules里定义文件


const category = {
  namespaced: true, // 命名空间
  state: {
    categoryList: [] // 导航列表
  },
  // state的计算属性 基于categoryList做一定的数据处理 children前俩项
  getters: {
  },
  mutations: {
    setCategoryList (state, list) {
      state.categoryList = list
    }
  },
  actions: {
    async asynGetCategory (ctx) {
      // 1. 发送接口请求
      const res = await categoryApi()
      // 2. 把数据拿到之后通过触发mutation存入state
      ctx.commit('setCategoryList', res.data.result)
      // 我们找一个合适的时机 把这个action函数调用一下?
      // 去哪里触发?
    }
  }

}

export default category

// 1.如何在setup中使用store

// import {useStore} from 'vuex'
// setup(){ const store = useStore() }

// 2.如何在setup中使用state中的数据

// computed(()=> store.state.模块名.属性名)

// 3.如何在setup中使用计算属性

// computed(()=> store.getters['模块名/getter名'])

2.在layout/index 里触发

import { useStore } from 'vuex'

export default {
  name: 'XtxLayout',
  components: {
    topNavVue,
    topHeaderVue,
    layoutFooterVue,
    headerStickyVue
  },
  setup () {
    // 触发获取分类数据的action this.$store.dispatch
    const store = useStore() // this.$store等价
    store.dispatch('category/asynGetCategory')
  }
}
</script>

3.在使用界面使用计算属性

import { useStore } from 'vuex'
export default {
  setup () {
    // 在组件里使用store里面存好的数据
    // 如何在setup中使用store中的数据?
    // 方法:借助计算属性做一个数据映射
    const store = useStore()
    // 当前组件的cagetoryData就和store中的categoryList完成了映射
    // 他俩始终保持响应式的同步
    const cagetoryData = computed(() => store.state.category.categoryList)
    return {
      cagetoryData
    }
  }
}

12.通过数组的裁切属性把多余的数据隐藏

第一种方法

第二种方法

  1. 在 store/category 里定义计算属性
  getters: {
    formatList (state) {
      return state.categoryList.map(item => {
        return {
          id: item.id,
          name: item.name,
          children: item.children.slice(0, 2),
          goods: item.goods // 用来显示右侧弹框中的列表
        }
      })
    }
  },

2)在组件里获取store 里的计算属性

import { useStore } from 'vuex'
export default {
  setup () {
    // 在组件里使用store里面存好的数据
    // 如何在setup中使用store中的数据?
    // 方法:借助计算属性做一个数据映射
    const store = useStore()
    // 当前组件的cagetoryData就和store中的categoryList完成了映射
    // 他俩始终保持响应式的同步
    const cagetoryData = computed(() => store.state.category.categoryList)
    return {
      cagetoryData
    }
  }
}
</script>

13.注册全局组件

1.把需要注册的全局组件放到src/components文件夹下

2.在main.js 里引入 并且注册使用


import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
// 初始化样式文件
import '@/styles/common.less'
// 注册全局组件
import componentsPlugin from '@/components'
import directivePlugin from '@/directives'

// use: 方法,用来注册插件 (Vue.use) 支持串联调用
// 以app根组件为参数生成一个实例对象然后注册store插件注册router插件 最后完成挂载
createApp(App).use(store).use(router).use(componentsPlugin).use(directivePlugin).mount('#app')

14.轮播图的展示

1.查看轮播图组件的名字 2.在需要的banner的位置使用组件 传入组件需要的参数 3.掉接口拿到图片数据地址渲染数据

15.鼠标移入layer让它显示隐藏的盒子

  1. 设置样式 让本来处于display:none 的盒子 display:black

2.在store里吧需要的数据goods加上

  getters: {
    formatList (state) {
      return state.categoryList.map(item => {
        return {
          id: item.id,
          name: item.name,
          children: item.children.slice(0, 2),
          goods: item.goods // 用来显示右侧弹框中的列表
        }
      })
    }
  },

3.在需要的组件中调用

import { useStore } from 'vuex'
export default {
  setup () {
    const store = useStore()
    // 当前组件的cagetoryData就和store中的categoryList完成了映射
    // 他俩始终保持响应式的同步

    // 如何在这里获取store中的getters
    // store.getters['模块名/getter名字']
    const cagetoryData = computed(() => store.getters['category/formatList'])
    return {
      cagetoryData
    }
  }
}