一直显示?点击任意区域即可关闭

记录一些常用的代码片段

11-0503:4898108
使用 Ctrl + F 快速搜索代码片段

UnoCSS 常用配置

ts
// uno.config.ts
export default defineConfig({
  rules: [['fade-up-animation', { animation: 'fade-up 0.6s 0.3s backwards' }]],
  shortcuts: [
    { 'flex-center': 'flex items-center justify-center' },
    { 'flex-between': 'flex items-center justify-between' },
  ],
  theme: {
    // phone:hidden 表示 @media (min-width: 640px)
    // lt-phone:hidden 表示 @media (max-width: 639.9px)
    // at-pad:hidden 表示 @media (min-width: 768px) and (max-width: 1023.9px)
    breakpoints: {
      phone: '640px',
      pad: '768px',
      notebook: '1024px',
      desktop: '1280px',
      tv: '1536px',
    },
  },
  presets: [
    // 默认预设
    presetUno(),
    // 开启属性模式
    presetAttributify(),
    // 图标预设 https://icones.js.org/collection/ri
    presetIcons({
      scale: 1.2,
      autoInstall: false,
      extraProperties: {
        display: 'inline-block',
        'vertical-align': 'middle',
      },
    }),
  ],
});

UniApp 请求封装

ts
import { isHttp } from './utils';

type Data<T> = {
  // 后端返回的通用响应结构
  code: number;
  data: T;
  message: string;
};

export const http = <T>(options: UniApp.RequestOptions) => {
  options.url = isHttp(options.url) ? options.url : `${import.meta.env.VITE_BASE_URL}${options.url}`;
  return new Promise<Data<T>>((resolve, reject) => {
    uni.request({
      // 拦截器配置内容
      ...options,
      success(res) {
        // 成功响应
        handleResponse(res, resolve, reject);
      },
      fail(err) {
        handleError(err, reject);
      },
    });
  });
};

// resolve和reject不返回任何值,但通知promise更改状态
const handleResponse = <T>(
  res: UniApp.RequestSuccessCallbackResult,
  resolve: (value: Data<T>) => void,
  reject: (reason?: any) => void,
) => {
  const { data: result, statusCode } = res;
  // 分离了验证状态码逻辑
  if (isSuccessStatusCode(statusCode)) {
    resolve(result as Data<T>);
    // 登录失败
  } else if (statusCode === 401) {
    // ...清除用户登录信息
    // 跳转至登录页面
    uni.navigateTo({ url: '/login' });
    reject(res);
  } else {
    // 分离了报错状态码逻辑
    showErrorToast(res.data as Data<T>);
    reject(res);
  }
};

const handleError = (err: UniApp.GeneralCallbackResult, reject: (reason?: any) => void) => {
  uni.showToast({
    icon: 'none',
    title: '网络可能开小差了~',
  });
  reject(err);
};

const isSuccessStatusCode = (code: number) => {
  return code >= 200 && code < 300;
};

const showErrorToast = <T>(data: Data<T>) => {
  uni.showToast({
    icon: 'none',
    title: data.message || '请求错误',
  });
};
ts
import { http } from './request';
import type { ExamplePageParams, ExamplePageResult } from './type';

/**
 * 获取驿站列表
 * @returns
 */
export function getExampleList(data?: ExamplePageParams) {
  return http<ExamplePageResult>({
    method: 'GET',
    url: '/example/page',
    data,
  });
}
ts
/**
 * 判断字符串是否 http:// 或者 https 开头
 */
export function isHttp(str: string): boolean {
  return /^https?:\/\//.test(str);
}
ts
export interface PageParam {
  pagesize?: number;
  page?: number;
}

export interface PageResult<T> {
  list: T[];
  total: number;
}

export interface ExamplePageParams extends PageParam {
  /**
   * 关键词
   */
  keyword?: string;
}

export interface ExamplePageItem {
  label: string;
  value: string;
}

export type ExamplePageResult = PageResult<Required<ExamplePageItem>>;

CSS 骨架屏

在需要骨架屏的元素上添加 loading="true" 属性即可,如 vue 可以使用 v-bind:loading="loading"

css
*[loading='true'] > div:not([loading='true']) {
  background-image: linear-gradient(90deg, #f0f2f5 25%, #e6e8eb 37%, #f0f2f5 63%) !important;
  background-size: 400% 100% !important;
  animation: skeleton-loading 1.4s infinite ease !important;
  border: none !important;
  min-height: 30px;
}
*[loading='true'] > div:not([loading='true']) > * {
  display: none !important;
}
@keyframes skeleton-loading {
  0% {
    background-position: 100% 50%;
  }
  100% {
    background-position: 0 50%;
  }
}