赞
踩
pnpm i -D sass
// 引入公共样式与变量 // 引入公共样式方式1
import '@/style/index.scss'
export default defineConfig({
// 引入公共样式方式2
css: {
preprocessorOptions: {
scss: {
additionalData: `
@import "@/style/reset.scss";
@import "@/style/mixin.scss";
@import "@/style/variables.scss";
`,
},
},
},
})
@import './reset.scss'; @import './variables.scss'; @import './mixin.scss'; html, body, #app { height: 100%; color: #333333; font-family: Arial, Helvetica, 'STHeiti STXihei', 'Microsoft YaHei', Tohoma, sans-serif; background-color: $background-color; } .app-container { padding-bottom: 50px; } #__vconsole { display: none; } .fixIphonex { padding-bottom: $safe-bottom !important; &::after { content: ''; position: fixed; bottom: 0 !important; left: 0; height: calc(#{$safe-bottom} + 1px); width: 100%; background: #ffffff; } } /* 适配iphonex */ @supports (bottom: env(safe-area-inset-bottom)) { .app-container { padding-bottom: calc(env(safe-area-inset-bottom) + 50px); // 这里是重点 } .bottom-button-box { bottom: env(safe-area-inset-bottom); // 这里是重点 &:after { content: ''; height: env(safe-area-inset-bottom); // 这里是重点 position: absolute; top: 100%; left: 0; right: 0; background-color: #fff; } } }
// mixin // 清除浮动 @mixin clearfix { &:after { content: ""; display: table; clear: both; } } // 多行隐藏 @mixin textoverflow($clamp:1) { display: block; overflow: hidden; text-overflow: ellipsis; -o-text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: $clamp; /*! autoprefixer: ignore next */ -webkit-box-orient: vertical; } //flex box @mixin flexbox($jc:space-between, $ai:center, $fd:row, $fw:nowrap) { display: flex; display: -webkit-flex; flex: 1; justify-content: $jc; -webkit-justify-content: $jc; align-items: $ai; -webkit-align-items: $ai; flex-direction: $fd; -webkit-flex-direction: $fd; flex-wrap: $fw; -webkit-flex-wrap: $fw; }
/** * Eric Meyer's Reset CSS v2.0 (http://meyerweb.com/eric/tools/css/reset/) * http://cssreset.com */ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, menu, nav, output, ruby, section, summary, time, mark, audio, video, input { margin: 0; padding: 0; border: 0; font-size: 100%; font-weight: normal; vertical-align: baseline; } /* HTML5 display-role reset for older browsers */ article, aside, details, figcaption, figure, footer, header, menu, nav, section { display: block; } body { line-height: 1; } blockquote, q { quotes: none; } blockquote:before, blockquote:after, q:before, q:after { content: none; } table { border-collapse: collapse; border-spacing: 0; } /* custom */ a { text-decoration: none; -webkit-backface-visibility: hidden; } li { list-style: none; } ::-webkit-scrollbar { width: 5px; height: 5px; } ::-webkit-scrollbar-track-piece { background-color: rgba(0, 0, 0, 0.2); -webkit-border-radius: 6px; } ::-webkit-scrollbar-thumb:vertical { height: 5px; background-color: rgba(125, 125, 125, 0.7); -webkit-border-radius: 6px; } ::-webkit-scrollbar-thumb:horizontal { width: 5px; background-color: rgba(125, 125, 125, 0.7); -webkit-border-radius: 6px; } html, body { width: 100%; height: 100%; } body { -webkit-text-size-adjust: none; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); }
// variables
$background-color: #f8f8f8;
$theme-color: #07b0b8;
$safe-bottom: constant(safe-area-inset-bottom);
$safe-bottom: env(safe-area-inset-bottom);
<template> <div> App <div class="rrrr">rrrr</div> </div> </template> <script setup lang="ts" name='App'> import { } from 'vue' console.log("meta.env", import.meta.env) </script> <style lang="scss" scoped> .rrrr { color: $theme-color; } </style>
// 声明自己定义的 vue组件
declare module '*.vue' {
import type { DefineComponent } from 'vue';
const vueComponent: DefineComponent<{}, {}, any>;
export default vueComponent;
}
import type { RouteRecordRaw} from 'vue-router' import { createRouter, createWebHistory } from 'vue-router' import Layout from '@/views/layout/index.vue' const routes: Array<RouteRecordRaw> = [ { path: '/', name: 'Home', redirect: '/home', meta: { title: '首页', keepAlive: false }, component: Layout, children: [ { path: '/home', name: 'Home', component: () => import('@/views/home/index.vue'), meta: { title: '首页', keepAlive: false, showTab: true } }, { path: '/about', name: 'About', component: () => import('@/views/about/index.vue'), meta: { title: '关于', keepAlive: false, showTab: true } }, { path: '/test', name: 'Test', component: () => import('@/views/test/index.vue'), meta: { title: '测试', keepAlive: false, showTab: true } }, { path: '/mine', name: 'Mine', component: () => import('@/views/mine/index.vue'), meta: { title: '我的', keepAlive: false, showTab: true } }, { path: '/noTab', name: 'NoTab', component: () => import('@/views/noTab/index.vue'), meta: { title: '没有Tab', keepAlive: false, showTab: false } }, ] } ] const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes }) export default router
<template> <div class="layout"> <div class="layout-content" :class="[route.meta.showTab ? 'showTab' : 'noShowTab']"> <keep-alive v-if="route.meta.keepAlive"> <router-view></router-view> </keep-alive> <router-view v-else></router-view> </div> <div class="layout-footer" v-if="route.meta.showTab"> <TabBar :tabbars="tabbars" v-model="activeRoute" @change="handleChange" /> </div> </div> </template> <script setup lang="ts" name="LayoutIndex"> import TabBar from "@/components/TabBar.vue" import { useRoute } from 'vue-router' import type { ITabList } from '@/components/TabBar.vue' import { reactive, watch, ref } from 'vue' const route = useRoute() console.log(route.meta) const tabbars: Array<ITabList> = reactive([ { title: '首页', to: '/home', icon: 'home-o' }, { title: '关于', to: '/about', icon: 'label-o' }, { title: '测试', to: '/test', icon: 'star-o' }, { title: '我的', to: '/mine', icon: 'user-o' } ]) const activeRoute = ref(0) watch(activeRoute, (v) => { console.log('tab value v-model:', v) }) const handleChange = (v: number) => { console.log('tab value @change:', v) } watch(route, (v) => { console.log('route', v.name) }) </script> <style lang="scss" scoped> .layout { background: #fff; width: 100%; height: 100%; .layout-content { background: #d5d5d5; } .showTab { height: calc(100% - 50px); overflow-y: scroll; } .noShowTab { height: 100%; overflow-y: scroll; } } </style>
<script setup lang="ts"> import { computed,defineProps ,defineEmits } from 'vue' import type { PropType } from 'vue'; export interface ITabList { title: string // 标题 to: string // url路径 icon: string // 图标 } const props = defineProps({ tabbars: { type: Array as PropType<ITabList[]>, default: () => [] }, active: Number }) const emit = defineEmits(['change', 'update:active']) const active = computed({ get: () => props.active, set: (val) => { emit('update:active', val) emit('change', val) } }) </script> <template> <van-tabbar v-model="active" route fixed> <van-tabbar-item v-for="item in tabbars" :to="item.to" :icon="item.icon" :key="item.to"> {{ item.title }} </van-tabbar-item> </van-tabbar> </template>
pnpm i vant@next -S
import 'vant/lib/index.css';
import { Tabbar,TabbarItem } from 'vant';
const app = createApp(App)
app.use(Tabbar);
app.use(TabbarItem);
<template>
<router-view />
</template>
<script setup lang="ts" name='App'>
import { } from 'vue'
console.log("meta.env", import.meta.env)
</script>
<style lang="scss" scoped>
#app {
height: 100%;
width: 100%;
}
</style>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。