目录  
 vue3之vite创建h5项目之2 ( ) 1:安装sass 1-1 使用sass引入公共样式1  
    1-2 vite.config.ts 引入公共样式方式2 1-3样式文件 1-3-1 src / style / index.scss ( 适配iphonex等还有引入其他公共的样式 ) 1-3-2 src / style / mixin.scss ( 公共样式方法抽离 ) 1-3-3 src / style / reset.scss ( 重置样式 ) 1-3-4 src / style / variables.scss ( 定义的公共变量样式 ) 1-3-5 使用变量   
   2:声明组件 否则ts报红线 项目根目录 / env.d.ts 3:路由配置和layout组件配置 3-1 路径文件 router/index.ts 3-2 Layout组件 view / layout / index.vue 3-3 TabBar.vue 组件 src / components/ abBar.vue 3-4 使用到van组件库 3-5 App.vue 3-6 效果   
    
   
  
 
 vue3之vite创建h5项目之2 ( )  
 1:安装sass  
 
 1-1 使用sass引入公共样式1  
 1-1-1 main.ts 引入公共样式方式  
import  '@/style/index.scss' 
  
 1-2 vite.config.ts 引入公共样式方式2  
export  default  defineConfig ( { 
  
  css :  { 
    preprocessorOptions :  { 
      scss :  { 
        additionalData :  ` 
		  @import "@/style/reset.scss";
          @import "@/style/mixin.scss";
          @import "@/style/variables.scss";
           ` , 
      } , 
    } , 
  } , 
} ) 
  
 1-3样式文件  
 1-3-1 src / style / index.scss ( 适配iphonex等还有引入其他公共的样式 )  
@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; 
  } 
} 
@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; 
    } 
  } 
} 
  
 1-3-2 src / style / mixin.scss ( 公共样式方法抽离 )  
@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; 
  
  - webkit- box- orient:  vertical; 
} 
@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; 
} 
  
 1-3-3 src / style / reset.scss ( 重置样式 )  
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; 
} 
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 ; 
} 
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 ) ; 
} 
  
 1-3-4 src / style / variables.scss ( 定义的公共变量样式 )  
$background- color:  #f8f8f8; 
$theme- color:  #07b0b8; 
$safe- bottom:  constant ( safe- area- inset- bottom) ; 
$safe- bottom:  env ( safe- area- inset- bottom) ; 
  
 1-3-5 使用变量  
< 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> 
  
 2:声明组件 否则ts报红线 项目根目录 / env.d.ts  
declare module '*.vue'  { 
    import  type {  DefineComponent }  from  'vue' ; 
	const  vueComponent :  DefineComponent< { } ,  { } ,  any> ; 
	export  default  vueComponent; 
} 
  
 3:路由配置和layout组件配置  
 3-1 路径文件 router/index.ts  
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
  
 3-2 Layout组件 view / layout / index.vue  
< 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> 
  
 3-3 TabBar.vue 组件 src / components/ abBar.vue  
< script setup lang= "ts" > 
import  {  computed, defineProps , defineEmits }  from  'vue' 
import  type {  PropType }  from  'vue' ; 
export  interface  ITabList  { 
	title :  string 
	to :  string 
	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> 
  
 3-4 使用到van组件库  
安装:pnpm i vant@next -S main.ts   
import  'vant/lib/index.css' ; 
import  {  Tabbar, TabbarItem }  from  'vant' ; 
const  app =  createApp ( App) 
app. use ( Tabbar) ; 
app. use ( TabbarItem) ; 
  
 3-5 App.vue  
< 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> 
  
 3-6 效果