Просмотр исходного кода

🎨 修改图片组件背景细节

快乐的梦鱼 1 месяц назад
Родитель
Сommit
b7fac5497a

+ 4 - 4
src/common/scss/global/base.scss

@@ -13,16 +13,16 @@
 
 .position {
 	&-relative {
-		position: relative;
+		position: relative!important;
 	}
 	&-absolute {
-		position: absolute;
+		position: absolute!important;
 	}
 	&-fixed {
-		position: fixed;
+		position: fixed!important;
 	}
 	&-sticky {
-		position: sticky;
+		position: sticky!important;
 	}
 }
 .d {

+ 53 - 7
src/components/basic/Image.vue

@@ -6,12 +6,16 @@
     :class="innerClass"
     @click="handleClick"
   >
+    <view v-if="showBackgroundEffect" :style="(backgroundEffectStyle as any)">
+    </view>
+    <view v-if="showBackgroundEffect" :style="(backgroundEffectStyle2 as any)">
+    </view>
     <image 
       :style="{
-        width: style.width,
-        height: style.height,
+        width: precentOrFull(style.width),
+        height: precentOrFull(style.height),
       }"
-      :mode="($attrs.mode as any)"
+      :mode="(mode as any)"
       :lazyLoad="$attrs.lazyLoad"
       :fadeShow="$attrs.fadeShow"
       :webp="$attrs.webp"
@@ -69,6 +73,10 @@ export interface ImageProps {
    * 是否显示灰色占位,默认是
    */
   showGrey?: boolean,
+  /**
+   * 在填充模式下是否显示背景模糊样式,默认是
+   */
+  showBackgroundEffect?: boolean,
   width?: string|number,
   height?: string|number,
   /**
@@ -92,17 +100,20 @@ export interface ImageProps {
    */
   touchable?: boolean,
   /**
-   * 图片是否有圆角
+   * 图片是否有圆型(50%圆角)
+   * @default false
    */
   round?: boolean,
   /**
-   * 当round为true的圆角大小,默认是50%
+   * 圆角大小
+   * @default 0
    */
   radius?: string|number,
   /**
    * 内部样式
    */
   innerStyle?: object;
+  mode?: 'aspectFill' | 'aspectFit' | 'widthFix' | 'heightFix' | 'top' | 'bottom' | 'left' | 'right' | 'center',
   innerClass?: string,
 }
 
@@ -120,14 +131,17 @@ const props = withDefaults(defineProps<ImageProps>(), {
   showLoading: () => propGetThemeVar('ImageShowLoading', true),
   showFailed: () => propGetThemeVar('ImageShowFailed', true),
   showGrey: () => propGetThemeVar('ImageShowGrey', false),
+  showBackgroundEffect: () => propGetThemeVar('ImageShowBackgroundEffect', true),
   loading: false,
   loadingColor: () => propGetThemeVar('ImageLoadingColor', 'border.default'),
   loadingSize: () => propGetThemeVar('ImageLoadingSize', 50),
   touchable: false,
   round: () => propGetThemeVar('ImageRound', false),
-  radius: () => propGetThemeVar('ImageRadius', '50%'),
+  radius: () => propGetThemeVar('ImageRadius', ''),
 })
 const emit = defineEmits([ 'click' ]);
+const showBackgroundEffect = computed(() => props.showBackgroundEffect && props.mode === 'aspectFit');
+
 
 const isErrorState = ref(false);
 const isLoadState = ref(true);
@@ -136,7 +150,7 @@ const instance = getCurrentInstance();
 
 const style = computed(() => {
   const o : Record<string, any> = {
-    borderRadius: props.round ? themeContext.resolveThemeSize(props.radius) : '', 
+    borderRadius: props.round ? '50%' : themeContext.resolveThemeSize(props.radius), 
     backgroundColor: isErrorState.value || props.showGrey ? themeContext.resolveThemeColor('background.imageBox') : 'transparent',
     overflow: 'hidden',
     width: themeContext.resolveThemeSize(props.width),
@@ -145,8 +159,40 @@ const style = computed(() => {
   }
   return o;
 });
+const backgroundEffectStyle = computed(() => ({
+  position: 'absolute',
+  left: 0,
+  right: 0,
+  top: 0,
+  bottom: 0,
+  zIndex: 1,
+  backgroundPosition: 'center',
+  backgroundSize: 'cover',
+  backgroundImage: `url('${props.src || props.defaultImage}')`,
+  filter: 'blur(3px)',
+}))
+const backgroundEffectStyle2 = computed(() => ({
+  position: 'absolute',
+  left: 0,
+  right: 0,
+  top: 0,
+  bottom: 0,
+  zIndex: 1,
+  backgroundRepeat: 'no-repeat',
+  backgroundPosition: 'center',
+  backgroundSize: 'contain',
+  backgroundImage: `url('${props.src || props.defaultImage}')`,
+}))
 const realWidth = ref(0);
 
+function precentOrFull(value: string|number) {
+  if (typeof value === 'number')
+    return value;
+  if (typeof value === 'string' && value.endsWith('%'))
+    return '100%';
+  return value;
+}
+
 function handleClick() {
   if (props.clickPreview) {
     uni.previewImage({

+ 8 - 4
src/pages/article/details.vue

@@ -14,18 +14,21 @@
           >
             <swiper-item v-for="(item, key) in loader.content.value.images" :key="key">
               <view class="item">
-                <image 
+                <Image 
                   :src="item" 
-                  class="w-100 height-500 radius-base"
+                  width="100%"
+                  :height="500"
+                  :radius="15"
                   mode="aspectFill" 
                   @click="onPreviewImage(key)"
                 />
               </view>
             </swiper-item>
           </swiper>
-          <image 
+          <Image 
             v-else-if="loader.content.value.image"
-            class="w-100 radius-base"
+            width="100%"
+            :radius="15"
             :src="loader.content.value.image"
             mode="widthFix"
           />
@@ -89,6 +92,7 @@ import CommonContent, { GetContentListParams } from "@/api/CommonContent";
 import Box2LineImageRightShadow from "../parts/Box2LineImageRightShadow.vue";
 import AppCofig from "@/common/config/AppCofig";
 import LikeFooter from "../parts/LikeFooter.vue";
+import Image from "@/components/basic/Image.vue";
 
 const loader = useSimplePageContentLoader<
   GetContentDetailItem, 

+ 3 - 2
src/pages/discover.vue

@@ -64,7 +64,7 @@
               class="mr-2"
               @click="goImagesDetail(item.id)"
             >
-              <image 
+              <Image 
                 class="width-300 height-200 radius-base"
                 :src="item.image"
                 :style="{
@@ -161,6 +161,7 @@
 <script setup lang="ts">
 import { onShareTimeline, onShareAppMessage } from '@dcloudio/uni-app';
 import { useSimpleDataLoader } from '@/common/composeabe/SimpleDataLoader';
+import { useAuthStore } from '@/store/auth';
 import { useHomePageMiniCommonListGoMoreAndGoDetail } from './article/common/CommonContent';
 import { navTo } from '@/components/utils/PageAction';
 import Tabbar from '@/common/components/tabs/tabbar.vue';
@@ -170,7 +171,7 @@ import HomeTitle from './parts/HomeTitle.vue';
 import SimplePageContentLoader from '@/common/components/SimplePageContentLoader.vue';
 import NewsIndexContent from '@/api/news/NewsIndexContent';
 import Button from '@/components/basic/Button.vue';
-import { useAuthStore } from '@/store/auth';
+import Image from '@/components/basic/Image.vue';
 import Box2LineRightShadow from './parts/Box2LineRightShadow.vue';
 
 const authStore = useAuthStore();

+ 13 - 12
src/pages/home.vue

@@ -1,7 +1,8 @@
 <template>
   <view class="home-container page-home d-flex flex-col bg-base">
-    <image 
-      class="w-100 position-absolute"
+    <Image 
+      innerClass="position-absolute"
+      width="100%"
       src="https://mncdn.wenlvti.net/app_static/minnan/images/home/BackgroundBanner5.jpg"
       mode="widthFix"
     />
@@ -18,8 +19,8 @@
           <view class="more">
             <text>查看详情</text>
           </view>
-          <image 
-            class="footer"
+          <Image 
+            innerClass="footer"
             src="https://mncdn.wenlvti.net/app_static/minnan/images/home/MainBanner2.png"
             mode="widthFix"
           />
@@ -29,10 +30,10 @@
           <view  
             v-for="(tab, k) in subTabs" 
             :key="k"
-            class="d-flex flex-column align-center width-1-4 mt-2 mb-2"
+            class="d-flex flex-column justify-center align-center width-1-4 mt-2 mb-2"
             @click="tab.onClick"
           >
-            <image class="width-100" :src="tab.icon" mode="widthFix" :style="{ maxHeight: '100rpx' }" />
+            <Image width="65%" :src="tab.icon" mode="widthFix" :innerStyle="{ maxHeight: '100rpx' }" />
             <text class="color-second-text mt-2 size-base text-align-center">{{ tab.name }}</text>
           </view>
 
@@ -137,13 +138,11 @@
             >
               {{ tab.title }}
             </text> 
-            <image
-              class="w-100 height-250 radius-base"
+            <Image
+              width="100%"
+              :height="250"
+              :radius="15"
               :src="tab.thumbnail || tab.image || AppCofig.defaultImage"
-              :style="{
-                backgroundImage: `url('${tab.thumbnail || tab.image}')`,
-                backgroundSize: 'cover',
-              }"
               mode="aspectFit"
             />
           </view>
@@ -186,6 +185,7 @@ import Box1AudioPlay from '@/pages/parts/Box1AudioPlay.vue';
 import SimplePageContentLoader from "@/common/components/SimplePageContentLoader.vue";
 import HorizontalScrollText from '@/components/typography/HorizontalScrollText.vue';
 import { navHomePageMiniCommonListGo } from './article/common/CommonContent';
+import Image from '@/components/basic/Image.vue';
 
 const subTabs = [
   { 
@@ -536,6 +536,7 @@ onShareAppMessage(() => {
     .tag {
       top: 2rpx; 
       right: 2rpx;
+      z-index: 20;
     }
   }
   .main-banner-box {

+ 6 - 2
src/pages/inhert/inheritor/details.vue

@@ -74,8 +74,11 @@
               ]"
             />
           </view>
-          <image 
-            class="width-150 height-150 radius-base flex-shrink-0" 
+          <Image
+            width="150"
+            height="150"
+            radius="15"
+            innerClass="flex-shrink-0" 
             :src="content.image" mode="aspectFill"
           />
         </view>
@@ -136,6 +139,7 @@ import IntroBlock from "@/pages/article/common/IntroBlock.vue";
 import DetailTabPage from "@/pages/article/common/DetailTabPage.vue";
 import CommonListPage from "@/pages/article/common/CommonListPage.vue";
 import Parse from "@/components/display/parse/Parse.vue";
+import Image from "@/components/basic/Image.vue";
 
 async function load(id: number, tabsArray: Ref<TabControlItem[]>) {
   const d = await InheritorContent.getContentDetail(id);

+ 7 - 4
src/pages/inhert/village/details.vue

@@ -13,11 +13,13 @@
         :duration="1000"
       >
         <swiper-item v-for="(item, k) in data.images" :key="k">
-          <image 
-            class="w-100 height-500 radius-l-top" 
+          <Image 
+            width="100%"
+            height="500"
             :src="item" 
+            innerClass="radius-l-top"
             mode="aspectFill"
-            @click="onPreviewImage(k)"
+            @click="onPreviewImage(k as number)"
           />
         </swiper-item>
       </swiper>
@@ -56,7 +58,7 @@
             class="w-20 d-flex flex-column align-center"
             @click="goList(tag)"
           >
-            <image :src="tag.image" class="width-100 mt-2" mode="widthFix"></image>
+            <Image :src="tag.image" width="50" innerClass="mt-2" mode="widthFix" />
             <view class="text-align-center color-text-content size-ss">{{ tag.title }}</view>
           </view>
         </view>
@@ -127,6 +129,7 @@ import IntroBlock from '@/pages/article/common/IntroBlock.vue';
 import ImagesUrls from '@/common/config/ImagesUrls';
 import { onShareTimeline, onShareAppMessage } from '@dcloudio/uni-app';
 import Parse from '@/components/display/parse/Parse.vue';
+import Image from '@/components/basic/Image.vue';
 
 const EmptyImage = 'https://mncdn.wenlvti.net/app_static/minnan/EmptyImage.png';
 

+ 5 - 2
src/pages/introduction/character/details.vue

@@ -19,8 +19,10 @@
               ]"
             />
           </view>
-          <image 
-            class="width-150 height-150 radius-base flex-shrink-0" 
+          <Image
+            width="150"
+            height="150"
+            innerClass="radius-base flex-shrink-0" 
             :src="content.image" mode="aspectFill"
           />
         </view>
@@ -66,6 +68,7 @@ import RoundTags from "@/pages/parts/RoundTags.vue";
 import InheritorContent from "@/api/inheritor/InheritorContent";
 import IntroBlock from "@/pages/article/common/IntroBlock.vue";
 import DetailTabPage from "@/pages/article/common/DetailTabPage.vue";
+import Image from "@/components/basic/Image.vue";
 
 async function load(id: number, tabsArray: Ref<TabControlItem[]>) {
   const d = await InheritorContent.getContentDetail(id);

+ 6 - 11
src/pages/parts/Box2LineImageRightShadow.vue

@@ -10,18 +10,12 @@
     @click="$emit('click')"
   >
     <view class="d-flex flex-row w-100">
-      <image 
-        :class="[
-          wideImage ? 'width-250' : 'width-150', 
-          'height-150', 
-          'radius-base',
-          'flex-shrink-0',
-        ]"
+      <Image 
+        innerClass="flex-shrink-0"
+        :width="wideImage ? '250' : '150'"
+        :height="150"
+        :radius="15"
         :src="image"
-        :style="{
-          backgroundImage: `url('${image}')`,
-          backgroundSize: 'cover',
-        }"
         mode="aspectFit"
       />
       <view class="d-flex flex-col ml-3 flex-one width-500">
@@ -44,6 +38,7 @@
 <script setup lang="ts">
 import type { PropType } from 'vue';
 import RoundTags from './RoundTags.vue';
+import Image from '@/components/basic/Image.vue';
 
 defineProps({
   title: String,

+ 5 - 6
src/pages/parts/Box2LineLargeImageUserShadow.vue

@@ -14,14 +14,12 @@
     }"
     @click="$emit('click')"
   >
-    <image 
+    <NaImage 
       v-if="image" 
-      class="w-100 height-300 radius-base" 
+      width="100%"
+      :height="300"
+      :radius="15"
       :src="image" 
-      :style="{
-        backgroundImage: `url('${image}')`,
-        backgroundSize: 'cover',
-      }"
       mode="aspectFit" 
     />
     <image 
@@ -75,6 +73,7 @@
 <script setup lang="ts">
 import type { PropType } from 'vue';
 import RoundTags from './RoundTags.vue';
+import NaImage from '@/components/basic/Image.vue';
 
 const IconHeart = 'https://mncdn.wenlvti.net/app_static/minnan/images/discover/IconHeart.png';
 const IconChat = 'https://mncdn.wenlvti.net/app_static/minnan/images/discover/IconChat.png';

+ 4 - 5
src/pages/parts/ImageGrid.vue

@@ -11,12 +11,10 @@
         backgroundSize: 'cover',
       }"
     >
-      <image 
+      <Image 
         :src="imagekey ? v[imagekey] : v" 
-        :style="{ 
-          width: `100%`,
-          height: `100%`,
-        }"
+        width="100%"
+        height="100%"
         mode="aspectFit"
         @click="itemClick(v, k)"
       />
@@ -25,6 +23,7 @@
 </template>
 
 <script setup lang="ts">
+import Image from '@/components/basic/Image.vue';
 import type { PropType } from 'vue';
 
 const props = defineProps({	

+ 4 - 2
src/pages/parts/ImageSwiper.vue

@@ -9,9 +9,10 @@
   >
     <swiper-item v-for="(item, key) in images" :key="key">
       <view class="item">
-        <image
+        <Image
           :src="item"
-          class="w-100 radius-base"
+          width="100%"
+          :radius="15"
           mode="aspectFill"
           @click="onPreviewImage(key)"
         />
@@ -22,6 +23,7 @@
 
 <script setup lang="ts">
 import { useSwiperImagePreview } from '@/common/composeabe/SwiperImagePreview';
+import Image from '@/components/basic/Image.vue';
 import type { PropType } from 'vue';
 
 const props = defineProps({