英文网站建设网站/金昌网站seo
day-059-fifty-nine-20230427-移动端商城
移动端商城
vant2
-
看vant官网,发现vue2要用vant2,进入vant2官网。
- vant官网-首页
- vant官网-首页-版本提示
- vant官网-首页
-
Vant 4.x
版本 的文档,适用于Vue 3
开发。- 使用
Vue 2
,请浏览Vant 2
文档。- vant官网-Vant2官网
- 使用
安装vant2
- 安装vant2插件
npm i vant@latest-v2
使用vant2组件
选一种使用
-
方式一-自动按需引入组件 (推荐)
-
安装插件
npm i babel-plugin-import -D
-
在
/babel.config.js
中添加module.exports = {presets: ['@vue/cli-plugin-babel/preset'],plugins: [['import', {libraryName: 'vant',libraryDirectory: 'es',style: true}, 'vant']] }
-
在
/src/main.js
中导入import 'vant/lib/index.css';import { Button } from 'vant';Vue.use(Button)
-
不过一般在
/src/vant/index.js
中统一配置,以统一处理并解耦关于vant的组件引入// 1. 引入vue; import Vue from "vue";// 2. 引入vant的css样式 import "vant/lib/index.css";// 3. 引入button组件,在组件中使用时是用`van-button`使用 import { Button } from "vant"; Vue.use(Button);
-
在
/src/main.js
中引入/src/vant/index.js
并让它运行一次import './vant/index.js'
-
-
-
方式二-手动按需引入组件
-
在不使用插件的情况下,可以手动引入需要的组件。
-
在具体的某个组件内
<template><div class="home"><van-button type="danger">使用van-button组件</van-button><h1>h1</h1><h3>h3</h3></div> </template><script> import 'vant/lib/button/style';//引入button的样式,使用这个的前提是安装了vant这个ui框架。 import Button from 'vant/lib/button';//引入button的js代码,使用这个的前提是安装了vant这个ui框架。 export default {name: "HomeView",components: {"van-button": Button,//要重命名引入的组件,最好是两个字母,中间用连接符分隔。}, }; </script>
-
-
方式三-导入所有组件
-
Vant支持一次性导入所有组件,引入所有组件会增加代码包体积,因此不推荐这种做法。
-
在
/src/main.js
中导入//1. 全局导入 //import Vue from 'vue';//这个一般不用写,因为之前Vue脚手架已经导入了 import Vant from 'vant'; import 'vant/lib/index.css'; Vue.use(Vant);
-
vant2组件的注册方式
全局注册
-
全局组件-要全局注册
-
在
/src/main.js
或/src/vant/index.js
中导入对应的组件import Vue from 'vue'; import { Button } from 'vant';
-
全局注册组件
-
通过 Vue.use 注册
// 方式一. 通过 Vue.use 注册 // 注册完成后,在模板中通过 <van-button> 或 <VanButton> 标签来使用按钮组件 Vue.use(Button);
-
通过 Vue.component 注册
// 方式二. 通过 Vue.component 注册 // 注册完成后,在模板中通过 <van-button> 标签来使用按钮组件 Vue.component(Button.name, Button);
-
- 全局注册后,在项目所有的vue文件中都可以直接在模板中使用
-
局部注册
-
局部组件-要局部注册
-
在具体的一个vue组件中调用
<template><div class="home"><van-button type="primary">主要按钮</van-button><van-button type="info">信息按钮</van-button><van-button type="default">默认按钮</van-button><van-button type="warning">警告按钮</van-button><van-button type="danger">危险按钮</van-button><h1>h1</h1><h3>h3</h3></div> </template><script> import { Button } from 'vant'; export default {name: "HomeView",components: {"van-button": Button,//要重命名引入的组件,最好是两个字母,中间用连接符分隔。}, }; </script>
-
局部注册后,你只可以在当前组件中使用注册的 Vant 组件。
-
-
仅演示,一般项目不用这种方式,有点麻烦
- 但如果要放博客或vue2与vue3兼容,这种方式比较清晰
作用域插槽
- Vant 提供了丰富的组件插槽,通过插槽可以对组件的某一部分进行个性化定制。
<template><div><van-checkbox v-model="checked"><!-- 使用组件提供的 icon 插槽 --><!-- 将默认图标替换为个性化图片 --><template #icon="props"><img :src="props.checked ? 'https://img01.yzcdn.cn/vant/user-active.png' : 'https://img01.yzcdn.cn/vant/user-inactive.png'" /></template></van-checkbox></div>
</template><script>
export default {data() {return {checked: true,};},
};
</script>
浏览器适配
移动端适配
-
Viewport 布局
- Vant 默认使用 px 作为样式单位,如果需要使用 viewport 单位 (vw, vh, vmin, vmax),推荐使用 postcss-px-to-viewport 进行转换。
- 步骤:
-
安装postcss插件和postcss-px-to-viewport插件
//npm i postcss -D //vant默认已经安装了 npm i postcss-px-to-viewport -D
-
/postcss.config.js
module.exports = {plugins: {'postcss-px-to-viewport': {viewportWidth: 375,},}, };
-
-
Rem 布局适配
- 根标签设置rem基准值,使用rem单位
- px em rem 区别?
- px是物理像素,em是相对父元素字体大小,rem是相对根元素字体大小。
- 步骤
-
引入插件,用于在根标签设置rem基准值
npm i -S amfe-flexible yarn add amfe-flexible
-
要求在根元素中引入一个js文件–即amfe-flexible插件中生成的js文件
-
生效版:在
/src/main.js
中导入import "../node_modules/amfe-flexible/index.js"
-
官网推荐:在模块文件
/public/index.html
中使用<script src="./node_modules/amfe-flexible/index.js"></script>
- 不过不生效,是因为路径出错了。没能引到amfe-flexible插件中生成的js文件
- 应该要在vue-cli或webpack中配置好,或者script的标签写对路径
- 不过不生效,是因为路径出错了。没能引到amfe-flexible插件中生成的js文件
-
-
使用rem单位
- 自己计算转化
- 自动计算转化,通过postcss-pxtorem这个postcss插件
- 在项目中可以直接写px,自动转化为rem,不需要进行计算了
- 步骤:
-
安装postcss插件和postcss-pxtorem插件
//npm i postcss -D //vant默认已经安装了 npm install postcss postcss-pxtorem@5.1.1 --save-dev//vue2的postcss-pxtorem要用@5.1.1,最新版不太支持。vue3可以使用最新版比较多。
-
/postcss.config.js
//设计稿的尺寸是 375 // postcss.config.jsmodule.exports = { plugins: {'postcss-pxtorem': {rootValue: 37.5,propList: ['*'],},}, };
-
-
桌面端适配
- Vant 是一个面向移动端的组件库,因此默认只适配了移动端设备,这意味着组件只监听了移动端的 触摸touch 事件,没有监听桌面端的 鼠标mouse 事件。
- 如果需要在桌面端使用 Vant,可以引入Vant提供的 @vant/touch-emulator。
- 这个库会在桌面端自动将 mouse 事件转换成对应的 touch 事件,使得组件能够在桌面端使用。
- 如果需要在桌面端使用 Vant,可以引入Vant提供的 @vant/touch-emulator。
- 步骤:
-
安装@vant/touch-emulator模块
npm i @vant/touch-emulator -S
-
在
/src/main.js
中导入// 引入模块后自动生效 import '@vant/touch-emulator';
-
底部安全区适配
- iPhone X 等机型底部存在底部指示条,指示条的操作区域与页面底部存在重合,容易导致用户误操作,因此我们需要针对这些机型进行安全区适配。
- Vant 中部分组件提供了
safe-area-inset-top
或safe-area-inset-bottom
属性,设置该属性后,即可在对应的机型上开启适配。
- Vant 中部分组件提供了
- 步骤:
-
在 head 标签中添加 meta 标签,并设置 viewport-fit=cover 值。
-
/public/index.html
<metaname="viewport"content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover" />
-
-
在vue组件中使用
safe-area-inset-top
或safe-area-inset-bottom
属性。-
顶部安全区适配
<template><div class="home-root"><!-- 开启顶部安全区适配 --><van-nav-bar safe-area-inset-top /></div> </template>
-
底部安全区适配
<template><div class="home-root"><!-- 开启底部安全区适配 --><van-number-keyboard safe-area-inset-bottom /></div> </template>
-
-
基础页面
<template><div style="height: 2000px"><h1>ClassifyView</h1></div>
</template>
<script>
export default {};
</script>
<style>
</style>
路由配置
- 写五个vue页面组件,用于让van-tabbar标签来跳转对应的页面。
/src/views/IndexView.vue
<template><div style="height: 2000px"><h1>IndexView</h1></div> </template> <script> export default {}; </script>
/src/views/ClassifyView.vue
<template><div style="height: 2000px"><h1>ClassifyView</h1></div> </template> <script> export default {}; </script>
/src/views/CartView.vue
<template><div style="height: 2000px"><h1>CartView</h1></div> </template> <script> export default {}; </script>
/src/views/MyView.vue
<template><div style="height: 2000px"><h1>MyView</h1></div> </template> <script> export default {}; </script>
/src/views/LoginView.vue
<template><div style="height: 2000px"><h1>LoginView</h1></div> </template> <script> export default {}; </script>
- 配置路由及重定向
/src/router/index.js
import Vue from "vue"; import VueRouter from "vue-router"; import IndexView from "../views/IndexView.vue";Vue.use(VueRouter);const ClassifyView = () =>import(/* webpackChunkName: "ClassifyView" */ "../views/ClassifyView.vue"); const CartView = () =>import(/* webpackChunkName: "CartView" */ "../views/CartView.vue"); const MyView = () =>import(/* webpackChunkName: "MyView" */ "../views/MyView.vue"); const LoginView = () =>import(/* webpackChunkName: "LoginView" */ "../views/LoginView.vue"); const routes = [{path: "/",redirect: "/IndexView",//让`/#/`可以跳转到`/#/IndexView`//component: IndexView,},{path: "*",//让`/#/未定义路径`可以跳转到`/#/IndexView`redirect: "IndexView",},{path: "/IndexView",name: "IndexView",component: IndexView,},{path: "/ClassifyView",name: "ClassifyView",component: ClassifyView,},{path: "/CartView",name: "CartView",component: CartView,},{path: "/MyView",name: "MyView",component: MyView,},{path: "/LoginView",name: "LoginView",component: LoginView,}, ];const router = new VueRouter({routes, });export default router;
- 使用vant组件
- 用[].forEach()
// 1. 引入vue; import Vue from "vue";// 2. 引入vant的css样式 import "vant/lib/index.css";// 3. 引入button组件,在组件中使用时是用`van-button`使用 import { Button } from "vant"; Vue.use(Button);// 更集中 import { Tabbar, TabbarItem } from 'vant'; let list01 = [Tabbar, TabbarItem] list01.forEach(item=>[Vue.use(item) ]) // 等价于:分散的写法 // import { Tabbar, TabbarItem } from 'vant'; // Vue.use(Tabbar); // Vue.use(TabbarItem);
/src/components/FooterPage.vue
<template><div><van-tabbar v-model="active" active-color="#1baeae" :route="true"><van-tabbar-item icon="home-o" to="/IndexView">首页</van-tabbar-item><van-tabbar-item icon="search" dot to="/ClassifyView"><span>分类</span><template #icon="props"><i class="iconfont icon-fenlei"></i></template></van-tabbar-item><van-tabbar-item icon="shopping-cart-o" badge="5" to="/CartView">购物车</van-tabbar-item><van-tabbar-item icon="user-o" badge="20" to="/MyView">我的</van-tabbar-item></van-tabbar></div> </template> <script> export default {data() {return {active: 0,};}, }; </script>
- 用[].forEach()
- 改Tabbar图标选中颜色样式
/src/components/FooterPage.vue
<template><div><van-tabbar v-model="active" active-color="#1baeae"></van-tabbar></div> </template>
- 用自定义图标
-
/src/components/FooterPage.vue
<template><div><i class="iconfont icon-fenlei"></i></div> </template><style lang="less" scoped> @import url("../assets/icon.less"); </style>
-
- App组件中使用,但一些页面不用Tabbar组件显示
/src/App.vue
<template><div id="app"><router-view /><FooterPage></FooterPage></div> </template> <script> import FooterPage from "./components/FooterPage.vue"; export default {components: {FooterPage,}, }; </script>
- 用路由的mate属性控制App中的Tabbar的显隐
/src/router/index.js
const routes = [{path: "/",redirect: "/IndexView",//让`/#/`可以跳转到`/#/IndexView`//component: IndexView,},{path: "*",//让`/#/未定义路径`可以跳转到`/#/IndexView`redirect: "IndexView",},{path: "/IndexView",name: "IndexView",component: IndexView,meta: {isShowFooter: true,//在这个meta.isShowFooter为true的,显示App.vue中的导航栏。},},{path: "/ClassifyView",name: "ClassifyView",component: ClassifyView,meta: {isShowFooter: true,},},{path: "/CartView",name: "CartView",component: CartView,meta: {isShowFooter: true,},},{path: "/MyView",name: "MyView",component: MyView,meta: {isShowFooter: true,},},{path: "/LoginView",name: "LoginView",component: LoginView,// meta: {// isShowFooter: false,//或不写;// },}, ];const router = new VueRouter({routes, });
/src/App.vue
<template><div id="app"><router-view /><FooterPage v-show="flag"></FooterPage></div> </template> <script> import FooterPage from "./components/FooterPage.vue"; export default {data() {return {flag: true,};},watch: {$route: {handler(newValue) {console.log(`newValue-->`, newValue);this.flag = newValue?.meta?.isShowFooter || false;},immediate: true,},},components: {FooterPage,}, }; </script>
- 开启van-tabbar标签的路由模式,让van-tabbar自动随着路由路径的变化而切换当前选中的van-tabbar-item标签。
/src/components/FooterPage.vue
<template><div><van-tabbar v-model="active" active-color="#1baeae" :route="true"></van-tabbar></div> </template>
- 最终代码
/src/App.vue
最终代码<template><div id="app"><router-view /><FooterPage v-show="flag"></FooterPage></div> </template> <script> import FooterPage from "./components/FooterPage.vue"; export default {data() {return {flag: true,};},watch: {$route: {handler(newValue) {console.log(`newValue-->`, newValue);this.flag = newValue?.meta?.isShowFooter || false;//在这个this.$route.meta.isShowFooter为true的,显示App.vue中的导航栏。},immediate: true,},},components: {FooterPage,}, }; </script><style lang="less" scoped> // #app { // font-family: Avenir, Helvetica, Arial, sans-serif; // -webkit-font-smoothing: antialiased; // -moz-osx-font-smoothing: grayscale; // text-align: center; // color: #2c3e50;// nav { // padding: 30px; // a { // font-weight: bold; // color: #2c3e50; // &.router-link-exact-active { // color: #42b983; // } // } // } // } </style>
/src/router/index.js
最终代码import Vue from "vue"; import VueRouter from "vue-router"; import IndexView from "../views/IndexView.vue";Vue.use(VueRouter);const ClassifyView = () =>import(/* webpackChunkName: "ClassifyView" */ "../views/ClassifyView.vue"); const CartView = () =>import(/* webpackChunkName: "CartView" */ "../views/CartView.vue"); const MyView = () =>import(/* webpackChunkName: "MyView" */ "../views/MyView.vue"); const LoginView = () =>import(/* webpackChunkName: "LoginView" */ "../views/LoginView.vue"); const routes = [{path: "/",redirect: "/IndexView",//让`/#/`可以跳转到`/#/IndexView`//component: IndexView,},{path: "*",//让`/#/未定义路径`可以跳转到`/#/IndexView`redirect: "IndexView",},{path: "/IndexView",name: "IndexView",component: IndexView,meta: {isShowFooter: true,//在这个meta.isShowFooter为true的,显示App.vue中的导航栏。},},{path: "/ClassifyView",name: "ClassifyView",component: ClassifyView,meta: {isShowFooter: true,},},{path: "/CartView",name: "CartView",component: CartView,meta: {isShowFooter: true,},},{path: "/MyView",name: "MyView",component: MyView,meta: {isShowFooter: true,},},{path: "/LoginView",name: "LoginView",component: LoginView,// meta: {// isShowFooter: false,//或不写;// },}, ];const router = new VueRouter({routes, });export default router;
/src/components/FooterPage.vue
最终代码<template><div><van-tabbar v-model="active" active-color="#1baeae" :route="true"><van-tabbar-item icon="home-o" to="/IndexView">首页</van-tabbar-item><van-tabbar-item icon="search" dot to="/ClassifyView"><span>分类</span><template #icon><i class="iconfont icon-fenlei"></i></template></van-tabbar-item><van-tabbar-item icon="shopping-cart-o" badge="5" to="/CartView">购物车</van-tabbar-item><van-tabbar-item icon="user-o" badge="20" to="/MyView">我的</van-tabbar-item></van-tabbar></div> </template><script> export default {data() {return {active: 0,};}, }; </script><style lang="less" scoped> @import url("../assets/icon.less"); </style>
自定义图标
-
/src/components/FooterPage.vue
<template><div><i class="iconfont icon-fenlei"></i></div> </template><style lang="less" scoped> @import url("../assets/icon.less"); </style>
-
/src/assets/icon.less
@font-face {font-family: "iconfont";/* Project id 3141501 */src: url('//at.alicdn.com/t/font_3141501_ftrvn4vtda5.woff2?t=1642133344053') format('woff2'),url('//at.alicdn.com/t/font_3141501_ftrvn4vtda5.woff?t=1642133344053') format('woff'),url('//at.alicdn.com/t/font_3141501_ftrvn4vtda5.ttf?t=1642133344053') format('truetype'); }.iconfont {font-family: "iconfont" !important;font-size: 16px;font-style: normal;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;font-size:22px; }.icon-gouwucheman:before {content: "\e600"; }.icon-user:before {content: "\e63c"; }.icon-fenlei:before {content: "\e612"; }
滚动修改样式
-
样式一般用class代替,用一个变量来控制是否添加一个类名。
<template><div class="home-root"><div :class="['the-header', flag ? 'is-active' : '']">新峰商城</div></div> </template><script> export default {data() {return {flag: false,};}, }; </script><style lang="less" scoped> .home-root {.the-header {opacity: 0.2;&.is-active {opacity: 1;}} } </style>
-
一般使用DOMElement.addEventListener()与DOMElement.removeEventListener()操作事件的绑定与解绑。
- 主要原因是DOM2级事件可以绑定多个。
- 用DOM0级,只能绑定一个,可能会对其它组件中绑定的事件造成影响。
- 一般函数方法在methods中进行定义,允许在vue组件的一些生命周期中可以调用到。
- methods中的方法,可以被DOMElement.addEventListener()与DOMElement.removeEventListener()操作事件的绑定与解绑。
- 在生命周期中定义的方法,一般很难可以被重复调用。
- methods中的方法,可以被DOMElement.addEventListener()与DOMElement.removeEventListener()操作事件的绑定与解绑。
- 一般在created()为window之类的全局变量绑定一个方法。
- 如果涉及到DOM,可以在mounted()中绑定。
- 在destroyed()为绑定的事件进行解绑,防止内存一直占用,DOM删除不了,造成内存泄露。
- 事件绑定与解绑说明
-
DOM0级事件绑定与解绑
-
DOM0级事件绑定方式所绑定的事件,可以直接在生命周期中定义
<script> export default {data() {return {flag: false,};},created() {console.log(`window-->`, window);window.onscroll = () {let html = document.documentElement || document.body;console.log(`111-->`, 111);if (html.scrollTop > 100) {this.flag = true;} else {this.flag = false;}};},destroyed() {window.onscroll = null}, }; </script>
-
-
DOM2级事件的绑定与解绑
-
DOM0级事件绑定方式所绑定的事件,一般不能在生命周期中定义。而要在mothods中进行定义。
- 以便在绑定与解绑时,都能访问到同一个事件。
<script> export default {data() {return {flag: false,};},created() {console.log(`window-->`, window);//创建组件的时候向事件池中添加方法--DOM已经存在window.addEventListener("scroll", this.showHeader);},methods: {showHeader() {let html = document.documentElement || document.body;console.log(`111-->`, 111);if (html.scrollTop > 100) {this.flag = true;} else {this.flag = false;}},},destroyed() {window.removeEventListener("scroll", this.showHeader);}, }; </script>
-
-
- 主要原因是DOM2级事件可以绑定多个。
-
例子完整版
<template><div class="home-root"><div :class="['the-header', flag ? 'is-active' : '']">新峰商城</div><div class="the-body"><h1>11111</h1><h1>11111</h1><h1>11111</h1></div></div> </template><script> export default {data() {return {flag: false,};},created() {console.log(`window-->`, window);// window.onscroll = () => {};//创建组件的时候向事件池中添加方法--DOM已经存在window.addEventListener("scroll", this.showHeader);},methods: {showHeader() {let html = document.documentElement || document.body;console.log(`111-->`, 111);if (html.scrollTop > 100) {this.flag = true;} else {this.flag = false;}},},destroyed() {window.removeEventListener("scroll", this.showHeader);}, }; </script><style lang="less" scoped> .home-root {.the-header {width: 100%;height: 50px;background-color: #1baeae;text-align: center;color: #fff;font-size: 20px;line-height: 50px;// position: fixed;position: sticky;top: 0;left: 0;opacity: 0.2;&.is-active {opacity: 1;}}.the-body {height: 2000px;} } </style>
进阶参考
- 新蜂App–项目预览
- vant框架–vant2023最新框架-vant4适用于vue3
- vant框架–vant3适用于vue2
- vue可以用框架有哪些?-vue框架–总结主要使用方向