Vue3.0入门 + Vant3.0移动端实践(二)轮播图模块封装及首页完善

简介: Vue3.0入门 + Vant3.0移动端实践(二)轮播图模块封装及首页完善

接着上一篇的来,上一篇介绍了环境搭建及做好了底部的导航栏模块,接下来继续完善首页。


先来张最终效果图:



记录下之前遇到的问题,Vue中img图像src变成"[object Module]"无法正确加载的问题。


我在vue项目的js代码中,使用了"imgUrl"=require('../asserts/image.png')这种形式。网上查了很多资料,说是因为file-loader默认采用ES模块语法,即import '../image.png';然而Vue生成的是CommonJS模块语法,即require('../image.png');二者不一致。要么让file-loader或url-loader采用CommonJS语法,要么让Vue采用ES语法。


但是我找了下项目中的各个文件,没找到在哪能改esModule: false的选项,于是暂时作罢。


最终我找到的折中的办法,本地图片和css资源都放在public目录下,这样就可以了。



本地的css文件在index.html文件里加载,如:


<link rel="icon" href="<%= BASE_URL %>favicon.ico">


<link rel="stylesheet" href="<%= BASE_URL %>css/font_nbicon.css">


<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
  <link rel="stylesheet" href="<%= BASE_URL %>css/font_nbicon.css">
    <title>物联网报警系统</title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>


以下是轮播图模块封装,本地的图片放在public目录里,使用时直接引入路径即可:


在components目录下新建Swiper.vue组件:


<template>
  <van-swipe class="my-swipe" :autoplay="3000" indicator-color="#1baeae">
    <van-swipe-item v-for="(item, index) in list" :key="index">
      <img :src="item.imgUrl" alt="暂无图片">
    </van-swipe-item>
  </van-swipe>
</template>
<script>
export default {
  props: {
    list: Array
  },
  methods: {
  }
}
</script>
<style lang='less' scoped>
  .my-swipe {
    display: flex;
    flex-shrink: 0;
    flex-wrap: wrap;
    width: 100%;
    padding-top: 45px;
    img {
      width: 100%;
      height: 100%;
    }
  }
</style>


style调整界面的less写法,


display: flex;含义为使用flex布局。


padding-top: 45px;为轮播图最上面的titile留出45px的位置。


js的props属性里增加了个list,类型为Array,作为子组件接收属性。


接下来看看首页Home.vue里如何用:


import swiper from '@/components/Swiper'


先import引入进来,export default的components里注册组件。


template模板标签里这么使用: <swiper :list="swiperList"></swiper>


注意setup(),ref,torefs,reactive都为vue3的新用法,setup是Vue3 的一大特性函数 。


setup函数是处于 生命周期函数 beforeCreate 和 Created 两个钩子函数之间的函数。


setup函数是 Composition API(组合API)的入口。


在setup函数中定义的变量和方法最后都是需要 return 出去的 不然无法再模板中使用。


在执行 setup函数的时候,还没有执行 Created 生命周期方法,所以在 setup 函数中,无法使用 data 和 methods 的变量和方法。


setup函数只能是同步的不能是异步的。


旧的Vue2.0 Options API 和 新的Vue3.0 Composition API 区别


Vue2.0 Options API 约定:


我们需要在 props 里面设置接收参数


我们需要在 data 里面设置变量


我们需要在 computed 里面设置计算属性


我们需要在 watch 里面设置监听属性


我们需要在 methods 里面设置事件方法


你会发现 Options APi 都约定了我们该在哪个位置做什么事,这反倒在一定程度上也强制我们进行了代码分割。


现在用 Composition API,不再这么约定了,于是乎,代码组织非常灵活,我们的控制代码写在 setup 里面即可。


setup函数提供了两个参数 props和context,重要的是在setup函数里没有了this,在 vue3.0 中,访问他们变成以下形式: this.xxx=》context.xxx


我们没有了 this 上下文,没有了 Options API 的强制代码分离,Composition API 给了我们更加广阔的天地。


接下来说下ref和reactive。vue3在9月18号晚上发布了,在vue3中对响应式数据的声明官方给出了ref()和reactive()这两种方式。


双向数据绑定,vue一共提供了两种数据响应式监听,有点React Hooks的味道。ref 函数传入一个值作为参数,返回一个基于该值的响应式Ref对象,该对象中的值一旦被改变和访问,都会被跟踪到,就像我们改写后的示例代码一样,通过修改 count.value 的值,可以触发模板的重新渲染,显示最新的值。

其实,除了 ref 函数,Vue3.0中还提供了另外一个可以创建响应式对象的函数,那就是 reactive 函数。下面就来说说为什么要提供两种API


ref写法简单,但也有弊端,经过尝试发现他只能监听一些如数字、字符串、布尔之类的简单数据。


ref修改数据需要使用这样count.value=xxx的形式,而reactive只需要state.reactiveField=值这样来使用。


reactive在return时候需要toRefs来转换成响应式对象。


toRefs函数能将reactive创建的响应式对象,转化成为普通的对象,并且这个对象上的每个节点,都是ref()类型的响应式数据。


在Vue中使用可以直接使用ref (template中),Vue会自动添加.value。在Js中使用ref需要.value。


setup函数必须有返回值,必须返回个对象。


setup函数有一个props参数,用于接收props,也就是定义在组件上的属性(同vue2),但是接收的props必须先在props属性中定义,否则是不会被接收到。


vue2的所有生命周期写法与vue3兼容,而在vue3中,生命周期添加了on前缀,需要导入并写在setup()函数中。


<template>
  <div>
    <header class="home-header wrap" :class="{'active' : headerScroll}">
      <div class="header-search">
        <span class="app-name">物联网报警系统</span>
      </div>
    </header>
     <nav-bar />
     <swiper :list="swiperList"></swiper>
     <div class="category-list">
       <div v-for="item in categoryList" v-bind:key="item.categoryId" @click="tips">
         <img :src="item.imgUrl">
         <span>{{item.name}}</span>
       </div>
     </div>
  </div>
</template>
<script>
import navBar from '@/components/NavBar'
import swiper from '@/components/Swiper'
import { getHome } from '@/service/home'
import { Toast } from 'vant'
import { reactive, onMounted , toRefs} from 'vue'
export default {
  name: 'home',
  components: {
    navBar,
    swiper
  },
  setup() {
    const state = reactive({
      swiperList: [] ,// 轮播图列表
      categoryList: [
       {
          name: '查看设备',
          imgUrl: '/image/kj1.png',
          categoryId: 100001
        }, {
          name: '用户信息',
          imgUrl: '/image/kj2.png',
          categoryId: 100002
        }, {
          name: '充值中心',
          imgUrl: '/image/kj3.png',
          categoryId: 100003
        },{
          name: '功能预留',
          imgUrl: '/image/kj4.png',
          categoryId: 100004
        }, {
          name: '全部',
          imgUrl: '/image/kj5.png',
          categoryId: 100005
        }
      ],
      })
    onMounted(async () => {
      Toast.loading({
        message: '加载中...',
        forbidClick: true
      });
      const { data } = await getHome()
      console.log(data)
      state.swiperList = data.swiperLists
      Toast.clear()
    })
    const tips = () => {
      Toast('敬请期待');
    }
    return {
      ...toRefs(state),
       tips
    }
  }
}
</script>
<style lang="less" scoped >
  @import '../common/style/mixin';
 .home-header {
   position: fixed;
   left: 0;
   top: 0;
   .wh(100%, 45px);
   .fj(center);
   line-height: 45px;
   padding: 0 15px;
   .boxSizing();
   font-size: 15px;
   color: #fff;
   background: #39A2FD;
   z-index: 10000;
   .app-name {
     padding: 0 5px;
     color: #ffffff;
     font-size: 18px;
  }
  }
  .category-list {
    display: flex;
    flex-shrink: 0;
    flex-wrap: wrap;
    width: 100%;
    padding-bottom: 13px;
    div {
      display: flex;
      flex-direction: column;
      width: 20%;
      text-align: center;
      img {
        .wh(36px, 36px);
        margin: 13px auto 8px auto;
      }
    }
  }
</style>


至此,首页基本设计完成,接下来会继续介绍个人中心页面的详细设计过程。先来张截图吧:


相关文章
|
1月前
|
JavaScript
如何在 Vue 项目中选择合适的模块格式
【10月更文挑战第20天】选择合适的模块格式需要综合考虑多个因素,没有一种绝对正确的选择。需要根据项目的具体情况进行权衡和分析。在实际选择过程中,要保持灵活性,根据项目的发展和变化适时调整模块格式。
21 7
|
26天前
|
前端开发 JavaScript 容器
在 vite+vue 中使用@originjs/vite-plugin-federation 模块联邦
【10月更文挑战第25天】模块联邦是一种强大的技术,它允许将不同的微前端模块组合在一起,形成一个统一的应用。在 vite+vue 项目中,使用@originjs/vite-plugin-federation 模块联邦可以实现高效的模块共享和组合。通过本文的介绍,相信你已经了解了如何在 vite+vue 项目中使用@originjs/vite-plugin-federation 模块联邦,包括安装、配置和使用等方面。在实际开发中,你可以根据自己的需求和项目的特点,灵活地使用模块联邦,提高项目的可维护性和扩展性。
|
1月前
|
JavaScript 前端开发 编译器
在 Vue 项目中使用 ES 模块格式的优点
【10月更文挑战第20天】在 Vue 项目中使用 ES 模块格式具有众多优点,这些优点共同作用,使得项目能够更高效、更可靠地开发和运行。当然,在实际应用中,还需要根据项目的具体情况和需求进行合理的选择和配置。
33 6
|
26天前
|
缓存 JavaScript UED
Vue 中异步加载模块的方式
【10月更文挑战第23天】这些异步加载模块的方式各有特点和适用场景,可以根据项目的需求和架构选择合适的方法来实现模块的异步加载,以提高应用的性能和用户体验
|
26天前
|
JavaScript 测试技术 UED
解决 Vue 项目中 Tree shaking 无法去除某些模块
【10月更文挑战第23天】解决 Vue 项目中 Tree shaking 无法去除某些模块的问题需要综合考虑多种因素,通过仔细分析、排查和优化,逐步提高 Tree shaking 的效果,为项目带来更好的性能和用户体验。同时,持续关注和学习相关技术的发展,不断探索新的解决方案,以适应不断变化的项目需求。
|
2月前
|
JavaScript 前端开发 小程序
一小时入门Vue.js前端开发
本文是作者关于Vue.js前端开发的快速入门教程,包括结果展示、参考链接、注意事项以及常见问题的解决方法。文章提供了Vue.js的基础使用介绍,如何安装和使用cnpm,以及如何解决命令行中遇到的一些常见问题。
一小时入门Vue.js前端开发
|
1月前
|
存储 JavaScript 前端开发
前端开发:Vue.js入门与实战
【10月更文挑战第9天】前端开发:Vue.js入门与实战
|
1月前
|
JavaScript API 开发者
十分钟 带你强势入门 vue3
十分钟 带你强势入门 vue3
63 1
|
1月前
|
JavaScript
vue3完整教程从入门到精通(新人必学2,搭建项目)
本文介绍了如何在Vue 3项目中安装并验证Element Plus UI框架,包括使用npm安装Element Plus、在main.js中引入并使用该框架,以及在App.vue中添加一个按钮组件来测试Element Plus是否成功安装。
73 0
vue3完整教程从入门到精通(新人必学2,搭建项目)
|
1月前
|
JavaScript Java CDN
vue3完整教程从入门到精通(新人必学1,vue3快速上手)
本文提供了Vue 3从入门到精通的完整教程,涵盖了创建Vue应用、通过CDN使用Vue、定义网站以及使用ES模块构建版本的步骤和示例代码。
173 0
vue3完整教程从入门到精通(新人必学1,vue3快速上手)

相关实验场景

更多
下一篇
无影云桌面