image2.0.0

项目说明

该项目为web单页面应用,核心功能为显示时间。

技术栈使用 pnpmViteVue3typescripttailwindgithub/api

功能需求

  • 显示时间
  • 显示随机壁纸
  • 每日热词录入

非功能需求

  • 移动端自适应
  • 查看日前时间详细属性

页面对比

新项目预览
旧项目预览

旧页面
image
新页面
image

开发记录

Vscode Extension

  • Vue 3 Pack
  • Vue Extension Pack
  • Tailwind CSS Extension Pack

alias设置

'@'默认生效、其他路径需要同时配置vite和typescript才生效,配置完最好重启ide

1.配置vite.config文件

{
resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
      '#': path.resolve(__dirname, './src/views'),
      '$': path.resolve(__dirname, './src/components'),
    },
  }
}

2.配置tsconfig.json文件

{
 "compilerOptions": {
    "paths": {
      "/@/*": ["src/*"],
      "/#/*": ["src/views/*"],
      "/$/*": ["src/components/*"]
    }
  },
}

script setup

<script setup lang="ts">
  import { reactive, watchEffect, computed, ref } from 'vue';
  import gitPut from '$/gitPut.vue'; // 组件引入即可直接使用,不需要componet注册
  //    以下变量都可以在template中使用
  const menu = [...routes];     //非动态绑定
  const menuShow = ref(false);  //动态绑定,set/get时需要使用menuShow.value
  const state = reactive({  //动态绑定。类似store/state,维护一组参数
       imgUrl: '',
       now: Date.now(),
       twDate: computed(() => new TwDate(state.now)),
       /*使用computed替代filter*/
       weekMix: computed(() => state.twDate.getWeekEn() + '|' + state.twDate.getWeekZh()),
       seasonMix: computed(() => state.twDate.getSeasonEn() + '|' + state.twDate.getSeasonZh()),
  })
  //  watchEffect,  区别于watch只监听一个变量
  watchEffect(() => {
    //  可以定义所有变量监听,此处只监听了state.now
    state.localStr = new TwDate(state.now).toLocaleString();
  });
<script/>

Vue3 Hooks

最大区别就是取消了destroyed 改为 unMounted

创建hook.tslog工具

import {
  onBeforeMount,
  onMounted,
  // onBeforeUpdate,
  // onUpdated,
  onBeforeUnmount,
  onUnmounted,
  // onDeactivated,
  // onActivated,
  // onRenderTracked,
  // onRenderTriggered
} from 'vue';

const HOOK_LIST: Map<string, any> = new Map([
  ['BeforeMount', onBeforeMount],
  ['Mounted', onMounted],
  // ['BeforeUpdate', onBeforeUpdate],
  // ['Updated', onUpdated],
  ['BeforeUnmount', onBeforeUnmount],
  ['Unmounted', onUnmounted],
  // ['Deactivated', onDeactivated],
  // ['Activated', onActivated]
  // ['RenderTracked', onRenderTracked],
  // ['RenderTriggered', onRenderTriggered]
]);

/**
 * @description    Hook 日志与回调
 * @param cb
 */
export default (
  cb:
    | {
        afterBeforeMount: () => void;
        afterMounted: () => void;
        afterUnmounted: () => void;
        afterBeforeUnmount: () => void;
      }
    | any
) => {
  HOOK_LIST.forEach((hook, key) => {
    hook(() => {
      console.log(`#Hook////${key}`);
      let afterCb = cb?.[`after${key}`];
      afterCb && afterCb();
    });
  });
};

使用hook.ts

<script setup lang="ts">
  import hook from '@/common/hook';
  import { reactive } from 'vue';
  const state = reactive({
       now: Date.now()
  })
  //  timeInterval
  let timer = setInterval(() => {
    state.now = Date.now();
  }, 800);
  //  test hook
  hook({
    afterUnmounted: () => {
      clearInterval(timer);
      timer = 0;
    },
  });

Class Date Extend

import dateEnum from './../enums/dateEnum';
export default class TwDate extends Date {
  //    返回当天是当年的第几天
  getDayInYear = () => {
    return (
      (Date.now() - new TwDate(new TwDate().getFullYear(), 0, 1, 0, 0, 0).getTime()) /
      (24 * 3600 * 1000)
    );
  };
  //    返回当前时刻是当天的第几毫秒
  getMillSecInDay = () => {
    const y = new TwDate().getFullYear();
    const m = new TwDate().getMonth();
    const d = new TwDate().getDate();
    return Date.now() - new TwDate(y, m, d, 0, 0, 0).getTime();
  };
  //    返回当天/当年占比
  getRatioYear = () => {
    return this.getDayInYear() / 365;
  };
  //    返回当天/当月占比
  getRatioMonth = () => {
    const y = new TwDate().getFullYear();
    const m = new TwDate().getMonth();
    return new TwDate().getDate() / new TwDate(y, m + 1, 0).getDate();
  };
  //    返回当天/当周占比
  getRatioWeek = () => {
    return (new TwDate().getDay() || 7) / 7;
  };
  //    返回当前时刻/当天占比
  getRatioDay = () => {
    return this.getMillSecInDay() / (24 * 3600 * 1000);
  };
  //    返回文本:周-En
  getWeekEn = () => {
    return dateEnum.WEEK_EN[new TwDate().getDay()];
  };
  //    返回文本:周-Zh
  getWeekZh = () => {
    return dateEnum.WEEK_ZH[new TwDate().getDay()];
  };
  //    返回文本:季节-En
  getSeasonEn = () => {
    return dateEnum.SEASON_EN[Math.floor(new TwDate().getMonth() / 3)];
  };
  //    返回文本:季节-Zh
  getSeasonZh = () => {
    return dateEnum.SEASON_ZH[Math.floor(new TwDate().getMonth() / 3)];
  };
}

随机图片地址

reference

unsplash:免费的高清摄影素材网站

  const api = 'https://unsplash.it';
  const randomId = Math.random() * 10;
  const width = 1920;
  const height = 1080;
  let url = `${api}/${width}/${height}?random=${parseInt(randomId.toString(), 10)}`;

P.S.
也可用利用api获取Bing壁纸,但因为要处理跨域放弃了。如果是独立部署的话可以考虑。

// const bingUrl = 'https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&mkt=zh-CN';

tailwind使用

因为目前使用的是quasar框架,其中也有一些原子类的样式,所以思维上还是能理解。

但不习惯api的话起手比较吃力,有一定门槛,对与团队推行还是有一定难度。

个人感觉作为项目落地的话未来可能会有使用上的瓶颈,作为个人开发的话我目前还是比较中意的,有种中庸之美。

github/api

每日热词需求由 github/issue 实现,即输入热词回车后将参数由github/api传递给github。
写入操作需要token验证,可以在github/开发者设置里创建。
因为token不可显性显示在代码中,所以对token采用非对称加密,每次请求要输入密钥,解码后获取token。

P.S.如果token直接暴露在代码中,该token会自动删除。

1.创建token,输入note即可,checkbox勾选repo即可
image
image
2.在github/repo/issue里创建新label,主要用于区分。
image
3.配置用户、项目 package.json

{
  "config": {
    "owner": "Mulander-J",
    "repo": "timeWaster",
    "label": "heart"
  }
}

4.使用api

import axios from 'axios';
import pkg from './../../package.json';

const { owner, repo, label } = pkg.config;
const url = `https://api.github.com/repos/${owner}/${repo}`;

export default class Api {
  static getIssueList = (since?: string): Promise<any> => {
    since = since ? '&since=' + since : '';
    return axios.get(`${url}/issues?filter=created&labels=${label + since}`);
  };
  static addIssue = (body: string, token: string): any => {
    return axios.post(`${url}/issues?access_token=${token}`, {
      labels: [label],
      title: 'TW/' + new Date().toLocaleDateString(),
      body,
    });
  };
}

打包及部署

打包前要根据仓库地址修改根目录属性

// [guide](https://vitejs.dev/config/)
export default defineConfig({
  base: '/timeWaster'
});

使用github-page部署,这里用到了gh-pages插件,两行命令直接部署。

{
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "serve": "vite preview",
    "predeploy": "vite build",
    "deploy": "gh-pages -d dist"
  },
  "devDependencies": {
    "gh-pages": "^3.1.0"
  },
}

结语

本意是紧跟潮流学点新东西,利用闲暇时间查资料等了一周,实际开发用了两天左右。

对于vue3没涉及具体业务还不清楚,对于vite的速度真的很喜欢。


Mulander
527 声望17 粉丝

人生不过一场空,我不灿烂谁灿烂