创建主页面

二级路由的入口

  1. <template>
  2. <div>顶部通栏</div>
  3. <div>顶部导航</div>
  4. <div>
  5. <!-- 二级路由出口 -->
  6. <router-view></router-view>
  7. </div>
  8. <div>底部</div>
  9. </template>
  10. <script>
  11. export default {
  12. name: 'XtxLayout'
  13. }
  14. </script>
  15. <style scoped lang='less'>
  16. </style>

组件

将页面中的重复模块封装组件然后全部导入主页面

顶部通栏

需要在 public/index.html中引入字体图标文件

  1. <link rel="icon" href="<%= BASE_URL %>favicon.ico">
  2. <link rel="stylesheet" href="//at.alicdn.com/t/font_2143783_iq6z4ey5vu.css">
  3. <title><%= htmlWebpackPlugin.options.title %></title>
  1. <template>
  2. <nav class="app-topnav">
  3. <div class="container">
  4. <ul>
  5. <li><a href="javascript:;"><i class="iconfont icon-user"></i>周杰伦</a></li>
  6. <li><a href="javascript:;">退出登录</a></li>
  7. <li><a href="javascript:;">请先登录</a></li>
  8. <li><a href="javascript:;">免费注册</a></li>
  9. <li><a href="javascript:;">我的订单</a></li>
  10. <li><a href="javascript:;">会员中心</a></li>
  11. <li><a href="javascript:;">帮助中心</a></li>
  12. <li><a href="javascript:;">关于我们</a></li>
  13. <li><a href="javascript:;"><i class="iconfont icon-phone"></i>手机版</a></li>
  14. </ul>
  15. </div>
  16. </nav>
  17. </template>
  18. <script>
  19. export default {
  20. name: 'AppTopnav'
  21. }
  22. </script>
  23. <style scoped lang="less">
  24. .app-topnav {
  25. background: #333;
  26. ul {
  27. display: flex;
  28. height: 53px;
  29. justify-content: flex-end;
  30. align-items: center;
  31. li {
  32. a {
  33. padding: 0 15px;
  34. color: #cdcdcd;
  35. line-height: 1;
  36. display: inline-block;
  37. i {
  38. font-size: 14px;
  39. margin-right: 2px;
  40. }
  41. &:hover {
  42. color: @xtxColor;
  43. }
  44. }
  45. ~ li {
  46. a {
  47. border-left: 2px solid #666;
  48. }
  49. }
  50. }
  51. }
  52. }
  53. </style>

根据当前的登录状态显示 用户名和退出登录

  1. <ul>
  2. <template v-if="$store.state.user.profile.token">
  3. <li><a href="javascript:;"><i class="iconfont icon-user"></i>周杰伦</a></li>
  4. <li><a href="javascript:;">退出登录</a></li>
  5. </template>
  6. <template v-else>
  7. <li><a href="javascript:;">请先登录</a></li>
  8. <li><a href="javascript:;">免费注册</a></li>
  9. </template>
  10. </ul>

头部

  1. <template>
  2. <header class='app-header'>
  3. <div class="container">
  4. <h1 class="logo"><RouterLink to="/">小兔鲜</RouterLink></h1>
  5. <ul class="app-header-nav">
  6. <li class="home"><RouterLink to="/">首页</RouterLink></li>
  7. <li><a href="#">美食</a></li>
  8. <li><a href="#">餐厨</a></li>
  9. <li><a href="#">艺术</a></li>
  10. <li><a href="#">电器</a></li>
  11. <li><a href="#">居家</a></li>
  12. <li><a href="#">洗护</a></li>
  13. <li><a href="#">孕婴</a></li>
  14. <li><a href="#">服装</a></li>
  15. <li><a href="#">杂货</a></li>
  16. </ul>
  17. <div class="search">
  18. <i class="iconfont icon-search"></i>
  19. <input type="text" placeholder="搜一搜">
  20. </div>
  21. <div class="cart">
  22. <a class="curr" href="#">
  23. <i class="iconfont icon-cart"></i><em>2</em>
  24. </a>
  25. </div>
  26. </div>
  27. </header>
  28. </template>
  29. <script>
  30. export default {
  31. name: 'AppHeader'
  32. }
  33. </script>
  34. <style scoped lang='less'>
  35. .app-header {
  36. background: #fff;
  37. .container {
  38. display: flex;
  39. align-items: center;
  40. }
  41. .logo {
  42. width: 200px;
  43. a {
  44. display: block;
  45. height: 132px;
  46. width: 100%;
  47. text-indent: -9999px;
  48. background: url('~@/assets/images/logo.png') no-repeat center 18px / contain;
  49. }
  50. }
  51. .app-header-nav {
  52. width: 820px;
  53. display: flex;
  54. padding-left: 40px;
  55. position: relative;
  56. z-index: 998;
  57. li {
  58. margin-right: 40px;
  59. width: 38px;
  60. text-align: center;
  61. a {
  62. font-size: 16px;
  63. line-height: 32px;
  64. height: 32px;
  65. display: inline-block;
  66. }
  67. }
  68. }
  69. .search {
  70. width: 170px;
  71. height: 32px;
  72. position: relative;
  73. border-bottom: 1px solid #e7e7e7;
  74. line-height: 32px;
  75. .icon-search {
  76. font-size: 18px;
  77. margin-left: 5px;
  78. }
  79. input {
  80. width: 140px;
  81. padding-left: 5px;
  82. color: #666;
  83. }
  84. }
  85. .cart {
  86. width: 50px;
  87. .curr {
  88. height: 32px;
  89. line-height: 32px;
  90. text-align: center;
  91. position: relative;
  92. display: block;
  93. .icon-cart{
  94. font-size: 22px;
  95. }
  96. em {
  97. font-style: normal;
  98. position: absolute;
  99. right: 0;
  100. top: 0;
  101. padding: 1px 6px;
  102. line-height: 1;
  103. background: @helpColor;
  104. color: #fff;
  105. font-size: 12px;
  106. border-radius: 10px;
  107. font-family: Arial;
  108. }
  109. }
  110. }
  111. }
  112. </style>

抽离模板中的header-nav组件,后面的顶部通栏需要复用,这里封装成组件 将当导航栏替换成该组件

  1. <template>
  2. <ul class="app-header-nav">
  3. <li class="home"><RouterLink to="/">首页</RouterLink></li>
  4. <li><a href="#">美食</a></li>
  5. <li><a href="#">餐厨</a></li>
  6. <li><a href="#">艺术</a></li>
  7. <li><a href="#">电器</a></li>
  8. <li><a href="#">居家</a></li>
  9. <li><a href="#">洗护</a></li>
  10. <li><a href="#">孕婴</a></li>
  11. <li><a href="#">服装</a></li>
  12. <li><a href="#">杂货</a></li>
  13. </ul>
  14. </template>
  15. <style scoped lang='less'>
  16. .app-header-nav {
  17. width: 820px;
  18. display: flex;
  19. padding-left: 40px;
  20. position: relative;
  21. z-index: 998;
  22. li {
  23. margin-right: 40px;
  24. width: 38px;
  25. text-align: center;
  26. a {
  27. font-size: 16px;
  28. line-height: 32px;
  29. height: 32px;
  30. display: inline-block;
  31. }
  32. }
  33. }
  34. </style>

底部

  1. <template>
  2. <footer class="app_footer">
  3. <!-- 联系我们 -->
  4. <div class="contact">
  5. <div class="container">
  6. <dl>
  7. <dt>客户服务</dt>
  8. <dd><i class="iconfont icon-kefu"></i> 在线客服</dd>
  9. <dd><i class="iconfont icon-question"></i> 问题反馈</dd>
  10. </dl>
  11. <dl>
  12. <dt>关注我们</dt>
  13. <dd><i class="iconfont icon-weixin"></i> 公众号</dd>
  14. <dd><i class="iconfont icon-weibo"></i> 微博</dd>
  15. </dl>
  16. <dl>
  17. <dt>下载APP</dt>
  18. <dd class="qrcode"><img src="@/assets/images/qrcode.jpg" /></dd>
  19. <dd class="download">
  20. <span>扫描二维码</span>
  21. <span>立马下载APP</span>
  22. <a href="javascript:;">下载页面</a>
  23. </dd>
  24. </dl>
  25. <dl>
  26. <dt>服务热线</dt>
  27. <dd class="hotline">400-0000-000 <small>周一至周日 8:00-18:00</small></dd>
  28. </dl>
  29. </div>
  30. </div>
  31. <!-- 其它 -->
  32. <div class="extra">
  33. <div class="container">
  34. <div class="slogan">
  35. <a href="javascript:;">
  36. <i class="iconfont icon-footer01"></i>
  37. <span>价格亲民</span>
  38. </a>
  39. <a href="javascript:;">
  40. <i class="iconfont icon-footer02"></i>
  41. <span>物流快捷</span>
  42. </a>
  43. <a href="javascript:;">
  44. <i class="iconfont icon-footer03"></i>
  45. <span>品质新鲜</span>
  46. </a>
  47. </div>
  48. <!-- 版权信息 -->
  49. <div class="copyright">
  50. <p>
  51. <a href="javascript:;">关于我们</a>
  52. <a href="javascript:;">帮助中心</a>
  53. <a href="javascript:;">售后服务</a>
  54. <a href="javascript:;">配送与验收</a>
  55. <a href="javascript:;">商务合作</a>
  56. <a href="javascript:;">搜索推荐</a>
  57. <a href="javascript:;">友情链接</a>
  58. </p>
  59. <p>CopyRight © 小兔鲜儿</p>
  60. </div>
  61. </div>
  62. </div>
  63. </footer>
  64. </template>
  65. <script>
  66. export default {
  67. name: 'AppFooter'
  68. }
  69. </script>
  70. <style scoped lang='less'>
  71. .app_footer {
  72. overflow: hidden;
  73. background-color: #f5f5f5;
  74. padding-top: 20px;
  75. .contact {
  76. background: #fff;
  77. .container {
  78. padding: 60px 0 40px 25px;
  79. display: flex;
  80. }
  81. dl {
  82. height: 190px;
  83. text-align: center;
  84. padding: 0 72px;
  85. border-right: 1px solid #f2f2f2;
  86. color: #999;
  87. &:first-child {
  88. padding-left: 0;
  89. }
  90. &:last-child {
  91. border-right: none;
  92. padding-right: 0;
  93. }
  94. }
  95. dt {
  96. line-height: 1;
  97. font-size: 18px;
  98. }
  99. dd {
  100. margin: 36px 12px 0 0;
  101. float: left;
  102. width: 92px;
  103. height: 92px;
  104. padding-top: 10px;
  105. border: 1px solid #ededed;
  106. .iconfont {
  107. font-size: 36px;
  108. display: block;
  109. color: #666;
  110. }
  111. &:hover {
  112. .iconfont {
  113. color: @xtxColor;
  114. }
  115. }
  116. &:last-child {
  117. margin-right: 0;
  118. }
  119. }
  120. .qrcode {
  121. width: 92px;
  122. height: 92px;
  123. padding: 7px;
  124. border: 1px solid #ededed;
  125. }
  126. .download {
  127. padding-top: 5px;
  128. font-size: 14px;
  129. width: auto;
  130. height: auto;
  131. border: none;
  132. span {
  133. display: block;
  134. }
  135. a {
  136. display: block;
  137. line-height: 1;
  138. padding: 10px 25px;
  139. margin-top: 5px;
  140. color: #fff;
  141. border-radius: 2px;
  142. background-color: @xtxColor;
  143. }
  144. }
  145. .hotline {
  146. padding-top: 20px;
  147. font-size: 22px;
  148. color: #666;
  149. width: auto;
  150. height: auto;
  151. border: none;
  152. small {
  153. display: block;
  154. font-size: 15px;
  155. color: #999;
  156. }
  157. }
  158. }
  159. .extra {
  160. background-color: #333;
  161. }
  162. .slogan {
  163. height: 178px;
  164. line-height: 58px;
  165. padding: 60px 100px;
  166. border-bottom: 1px solid #434343;
  167. display: flex;
  168. justify-content: space-between;
  169. a {
  170. height: 58px;
  171. line-height: 58px;
  172. color: #fff;
  173. font-size: 28px;
  174. i {
  175. font-size: 50px;
  176. vertical-align: middle;
  177. margin-right: 10px;
  178. font-weight: 100;
  179. }
  180. span {
  181. vertical-align: middle;
  182. text-shadow: 0 0 1px #333;
  183. }
  184. }
  185. }
  186. .copyright {
  187. height: 170px;
  188. padding-top: 40px;
  189. text-align: center;
  190. color: #999;
  191. font-size: 15px;
  192. p {
  193. line-height: 1;
  194. margin-bottom: 20px;
  195. }
  196. a {
  197. color: #999;
  198. line-height: 1;
  199. padding: 0 10px;
  200. border-right: 1px solid #999;
  201. &:last-child {
  202. border-right: none;
  203. }
  204. }
  205. }
  206. }
  207. </style>

接口数据渲染导航

  1. import request from '@/utils/request'
  2. /**
  3. * 获取导航数据
  4. */
  5. export const reqFindHeadCategory = () => request('/home/category/head', 'get')

在组件中调用接口讲数据渲染到组件中 首页数据接口中没有,自己手写一个

  1. <ul class="app-header-nav">
  2. <li class="home"><RouterLink to="/">首页</RouterLink></li>
  3. <li v-for="item in categoryList" :key="item.id">
  4. <RouterLink :to="`/category/${item.id}`">{{item.name}}</RouterLink>
  5. </li>
  6. </ul>
  7. <script>
  8. import { ref } from 'vue'
  9. import { reqFindHeadCategory } from '@/api/home'
  10. export default {
  11. setup () {
  12. const categoryList = ref([])
  13. async function loadCategory () {
  14. const res = await reqFindHeadCategory()
  15. categoryList.value = res.result
  16. }
  17. loadCategory()
  18. return {
  19. categoryList
  20. }
  21. }
  22. }
  23. </script>

vuex 管理导航数据

导航栏的数据是通用的,使用vuex管理

  1. import { reqFindHeadCategory } from '@/api/home'
  2. export default {
  3. namespaced: true,
  4. state: () => {
  5. return {
  6. list: []
  7. }
  8. },
  9. mutations: {
  10. setList (state, categoryList) {
  11. state.list = categoryList
  12. }
  13. },
  14. actions: {
  15. async getList (context) {
  16. const res = await reqFindHeadCategory()
  17. context.commit('setList', res.result)
  18. }
  19. }
  20. }

在首页发送请求 app-header-nav中使用computed获取vuex数据

  1. export default {
  2. name: 'XtxLayout',
  3. components: {
  4. AppTopnav,
  5. AppHeader,
  6. AppFooter
  7. },
  8. setup () {
  9. const store = useStore()
  10. store.dispatch('category/getList')
  11. }
  12. }
  1. export default {
  2. setup () {
  3. const store = useStore()
  4. const categoryList = computed(() => {
  5. return store.state.category.list
  6. })
  7. return {
  8. categoryList
  9. }
  10. }
  11. }

吸顶导航

  1. <template>
  2. <div class="app-header-sticky">
  3. <div class="container">
  4. <RouterLink class="logo" to="/" />
  5. <AppHeaderNav />
  6. <div class="right">
  7. <RouterLink to="/">品牌</RouterLink>
  8. <RouterLink to="/">专题</RouterLink>
  9. </div>
  10. </div>
  11. </div>
  12. </template>
  13. <script>
  14. import AppHeaderNav from './app-header-nav'
  15. export default {
  16. name: 'AppHeaderSticky',
  17. components: { AppHeaderNav }
  18. }
  19. </script>
  20. <style scoped lang='less'>
  21. .app-header-sticky {
  22. width: 100%;
  23. height: 80px;
  24. position: fixed;
  25. left: 0;
  26. top: 0;
  27. z-index: 999;
  28. background-color: #fff;
  29. border-bottom: 1px solid #e4e4e4;
  30. // 此处为关键样式!!!
  31. // 默认情况下完全把自己移动到上面
  32. transform: translateY(-100%);
  33. // 完全透明
  34. opacity: 0;
  35. // 显示出来的类名
  36. &.show {
  37. transition: all 0.3s linear;
  38. transform: none;
  39. opacity: 1;
  40. }
  41. .container {
  42. display: flex;
  43. align-items: center;
  44. }
  45. .logo {
  46. width: 200px;
  47. height: 80px;
  48. background: url("~@/assets/images/logo.png") no-repeat right 2px;
  49. background-size: 160px auto;
  50. }
  51. .right {
  52. width: 220px;
  53. display: flex;
  54. text-align: center;
  55. padding-left: 40px;
  56. border-left: 2px solid @xtxColor;
  57. a {
  58. width: 38px;
  59. margin-right: 40px;
  60. font-size: 16px;
  61. line-height: 1;
  62. &:hover {
  63. color: @xtxColor;
  64. }
  65. }
  66. }
  67. }
  68. </style>

监听dom 需要在 onMuounted 生命周期函数 监听 scroll

:class="{show:showFlag}"动态添加类名

  1. setup () {
  2. const showFlag = ref('')
  3. onMounted(() => {
  4. window.addEventListener('scroll', () => {
  5. const scrollTop = document.documentElement.scrollTop
  6. // console.log(scrollTop)
  7. showFlag.value = scrollTop >= 78
  8. })
  9. })
  10. return {
  11. showFlag
  12. }
  13. }

插件重构导航逻辑

装包npm i @vueuse/core@5.3.0 插件网址:https://vueuse.org/core/usewindowscroll/

  1. <template>
  2. <div class="app-header-sticky" :class="{show:y >= 78}">
  3. <div class="container">
  4. <RouterLink class="logo" to="/" />
  5. <AppHeaderNav />
  6. <div class="right">
  7. <RouterLink to="/">品牌</RouterLink>
  8. <RouterLink to="/">专题</RouterLink>
  9. </div>
  10. </div>
  11. </div>
  12. </template>
  13. <script>
  14. import { useWindowScroll } from '@vueuse/core'
  15. import AppHeaderNav from './app-header-nav'
  16. export default {
  17. name: 'AppHeaderSticky',
  18. components: { AppHeaderNav },
  19. setup () {
  20. const { y } = useWindowScroll()
  21. // console.log('y', y)
  22. return {
  23. y
  24. }
  25. }
  26. }
  27. </script>