最新公告
  • 欢迎您光临网站无忧模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Vue3 全家桶 + TS+ Vite2 + element-plus 搭建简洁时尚的博客网站实战及踩坑记

    正文概述 掘金(天明夜尽)   2021-05-07   402

    Vue3 全家桶 + TS+ Vite2 + element-plus 搭建简洁时尚的博客网站实战及踩坑记

    五一期间,花了 3 天时间,边学 Vue3 和 Vite2,边重构自己的项目,终于都用 Vue3 + TypeScript + Vite2 + Vuex4 + Vue-Router4 + element-plus 重构完啦!

    终于完成一项心心念念的 2021 年度目标了 ✌️

    项目地址:

    Vue3 全家桶 + TS+ Vite2 + element-plus 搭建简洁时尚的博客网站实战及踩坑记

    效果

    效果图:

    • pc 端

    Vue3 全家桶 + TS+ Vite2 + element-plus 搭建简洁时尚的博客网站实战及踩坑记

    • 移动端

    Vue3 全家桶 + TS+ Vite2 + element-plus 搭建简洁时尚的博客网站实战及踩坑记

    完整效果请看:

    功能

    已经完成功能

    • 登录
    • 注册
    • 文章列表
    • 文章归档
    • 标签
    • 关于
    • 点赞与评论
    • 留言
    • 历程
    • 文章详情(支持代码语法高亮)
    • 文章详情目录
    • 移动端适配
    • github 授权登录

    前端主要技术

    所有技术都是当前最新的。

    • vue:^3.0.5
    • typescript : ^4.1.3
    • element-plus: ^1.0.2-beta.41
    • vue-router : ^4.0.6
    • vite: ^2.2.3
    • vuex: ^4.0.0
    • axios: ^0.21.1
    • highlight.js: ^10.7.2
    • marked:^2.0.3

    1. 初化化项目

    用 vite-app 创建项目

    yarn create vite-app <project-name>
    
    # 或者
    npm init vite-app <project-name>
    

    然后按照提示操作即可!

    进入项目,安装依赖

    cd <project-name>
    
    yarn # 或 npm i
    

    运行项目

    yarn dev 
    

    打开浏览器 http://localhost:3000 查看

    2. 引入 TypeScript

    在创建项目的时候可以 TypeScript 的,如果你选择了 TypeScript ,可以忽略第 2 个步骤。

    加入 ts 依赖

    yarn add --dev typescript
    

    在 项目根目录下创建 TypeScript 的配置文件 tsconfig.json

    {
      "compilerOptions": {
        // 允许从没有设置默认导出的模块中默认导入。这并不影响代码的输出,仅为了类型检查。
        "allowSyntheticDefaultImports": true,
        
        // 解析非相对模块名的基准目录
        "baseUrl": ".",
    
        "esModuleInterop": true,
    
        // 从 tslib 导入辅助工具函数(比如 __extends, __rest等)
        "importHelpers": true,
    
        // 指定生成哪个模块系统代码
        "module": "esnext",
    
        // 决定如何处理模块。
        "moduleResolution": "node",
    
        // 启用所有严格类型检查选项。
        // 启用 --strict相当于启用 --noImplicitAny, --noImplicitThis, --alwaysStrict, 
        // --strictNullChecks和 --strictFunctionTypes和--strictPropertyInitialization。
        "strict": true,
    
        // 生成相应的 .map文件。
        "sourceMap": true,
    
        // 忽略所有的声明文件( *.d.ts)的类型检查。
        "skipLibCheck": true,
    
        // 指定ECMAScript目标版本 
        "target": "esnext",
        
        // 要包含的类型声明文件名列表
        "types": [
    
        ],
    
        "isolatedModules": true,
    
        // 模块名到基于 baseUrl的路径映射的列表。
        "paths": {
          "@/*": [
            "src/*"
          ]
        },
        // 编译过程中需要引入的库文件的列表。
        "lib": [
          "ESNext",
          "DOM",
          "DOM.Iterable",
          "ScriptHost"
        ]
      },
      "include": [
        "src/**/*.ts",
        "src/**/*.tsx",
        "src/**/*.vue",
        "tests/**/*.ts",
        "tests/**/*.tsx"
      ],
      "exclude": [
        "node_modules"
      ]
    }
    

    在 src 目录下新加 shim.d.ts 文件

    /* eslint-disable */
    import type { DefineComponent } from 'vue'
    
    declare module '*.vue' {
      const component: DefineComponent<{}, {}, any>
      export default component
    }
    

    把 main.js 修改成 main.ts

    在根目录,打开 Index.html

    <script type="module" src="/src/main.js"></script>
    修改为:
    <script type="module" src="/src/main.ts"></script>
    

    3. 引入 eslint

    安装 eslint prettier 依赖

    @typescript-eslint/parser @typescr ipt-eslint/eslint-plugin 为 eslint 对 typescript 支持。

    yarn add --dev eslint prettier eslint-config-prettier eslint-plugin-prettier eslint-plugin-vue @typescript-eslint/parser @typescr ipt-eslint/eslint-plugin
    

    在根目录下建立 eslint 配置文件: .eslintrc.js

    module.exports = {
      parser: 'vue-eslint-parser',
      parserOptions: {
        parser: '@typescript-eslint/parser',
        ecmaVersion: 2020,
        sourceType: 'module',
        ecmaFeatures: {
          jsx: true
        }
      },
      extends: [
        'plugin:vue/vue3-recommended',
        'plugin:@typescript-eslint/recommended',
        'prettier/@typescript-eslint',
        'plugin:prettier/recommended'
      ],
      rules: {
        '@typescript-eslint/ban-ts-ignore': 'off',
        '@typescript-eslint/explicit-function-return-type': 'off',
        '@typescript-eslint/no-explicit-any': 'off',
        '@typescript-eslint/no-var-requires': 'off',
        '@typescript-eslint/no-empty-function': 'off',
        'vue/custom-event-name-casing': 'off',
        'no-use-before-define': 'off',
        // 'no-use-before-define': [
        //   'error',
        //   {
        //     functions: false,
        //     classes: true,
        //   },
        // ],
        '@typescript-eslint/no-use-before-define': 'off',
        // '@typescript-eslint/no-use-before-define': [
        //   'error',
        //   {
        //     functions: false,
        //     classes: true,
        //   },
        // ],
        '@typescript-eslint/ban-ts-comment': 'off',
        '@typescript-eslint/ban-types': 'off',
        '@typescript-eslint/no-non-null-assertion': 'off',
        '@typescript-eslint/explicit-module-boundary-types': 'off',
        '@typescript-eslint/no-unused-vars': [
          'error',
          {
            argsIgnorePattern: '^h$',
            varsIgnorePattern: '^h$'
          }
        ],
        'no-unused-vars': [
          'error',
          {
            argsIgnorePattern: '^h$',
            varsIgnorePattern: '^h$'
          }
        ],
        'space-before-function-paren': 'off',
        quotes: ['error', 'single'],
        'comma-dangle': ['error', 'never']
      }
    };
    

    建立 prettier.config.js

    module.exports = {
      printWidth: 100,
      tabWidth: 2,
      useTabs: false,
      semi: false, // 未尾逗号
      vueIndentScriptAndStyle: true,
      singleQuote: true, // 单引号
      quoteProps: 'as-needed',
      bracketSpacing: true,
      trailingComma: 'none', // 未尾分号
      jsxBracketSameLine: false,
      jsxSingleQuote: false,
      arrowParens: 'always',
      insertPragma: false,
      requirePragma: false,
      proseWrap: 'never',
      htmlWhitespaceSensitivity: 'strict',
      endOfLine: 'lf'
    }
    

    4. vue-router、vuex

    npm install vue-router@4 vuex
    

    4.1 vuex

    在根目录下创建 store/index.ts

    import { InjectionKey } from 'vue'
    import { createStore, Store } from 'vuex'
    
    export interface State {
      count: number
    }
    
    export const key: InjectionKey<Store<State>> = Symbol()
    
    export const store = createStore<State>({
      state() {
        return {
          count: 0
        }
      },
      mutations: {
        increment(state) {
          state.count++
        }
      }
    })
    

    main.ts 修改

    import { createApp } from 'vue'
    import { store, key } from './store'
    import App from './App'
    import './index.css'
    
    const app = createApp(App)
    
    app.use(store, key)
    
    app.mount('#app')
    

    components/HelloWord.vue 修改

    <template>
      <h1>{{ msg }}</h1>
      <button @click="inCrement"> count is: </button>
      <p>{{ count }}</p>
    </template>
    
    <script>
      import { defineComponent, computed } from 'vue'
      import { useStore } from 'vuex'
      import { key } from '../store'
    
      export default defineComponent({
        name: 'HelloWorld',
        props: {
          msg: {
            type: String,
            default: ''
          }
        },
        setup() {
          const store = useStore(key)
    
          const count = computed(() => store.state.count)
    
          return {
            count,
            inCrement: () => store.commit('increment')
          }
        }
      })
    </script>
    

    4.2 vue-router

    在 src 目录下建立 router/index.ts,内容如下:

    import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
    import HelloWorld from "../components/HelloWorld.vue";
    
    const routes: Array<RouteRecordRaw> = [
        {
            path: "/",
            name: "HelloWorld",
            component: HelloWorld,
        },
        {
            path: "/about",
            name: "About",
            // route level code-splitting
            // this generates a separate chunk (about.[hash].js) for this route
            // which is lazy-loaded when the route is visited.
            component: () =>
                import(/* webpackChunkName: "About" */ "../components/About.vue")
        }
    ];
    
    const router = createRouter({
        history: createWebHistory(process.env.BASE_URL),
        routes,
    });
    
    export default router;
    

    再新建一个 components/About.vue 文件,内容如下:

    <template>
      <img
        
        src="../assets/logo.png"
      />
      <h1>{{ msg }}</h1>
    </template>
    
    <script lang="ts">
    import { defineComponent } from 'vue'
    
    export default defineComponent({
      name: 'About',
      data() {
        return {
          msg: 'Hello Vue 3.0 + Vite!'
        }
      },
      setup() {}
    })
    </script>
    

    再修改 main.ts

    import { createApp } from 'vue'
    import { store, key } from './store'
    import router from "./router";
    import App from './App'
    import './index.css'
    
    const app = createApp(App)
    
    app.use(store, key)
    app.use(router)
    app.mount('#app')
    

    再访问 http://localhost:3000/

    Vue3 全家桶 + TS+ Vite2 + element-plus 搭建简洁时尚的博客网站实战及踩坑记

    和 http://localhost:3000/about 即可

    Vue3 全家桶 + TS+ Vite2 + element-plus 搭建简洁时尚的博客网站实战及踩坑记

    5. 加入 Element Plus

    5.1 安装 element-plus

    全局安装

    npm install element-plus --save
    

    5.2 引入 Element Plus

    你可以引入整个 Element Plus,或是根据需要仅引入部分组件。我们先介绍如何引入完整的 Element。

    完整引入

    在 main.js 中写入以下内容:

    import { createApp } from 'vue'
    import ElementPlus from 'element-plus';
    import router from "./router";
    import 'element-plus/lib/theme-chalk/index.css';
    import App from './App.vue';
    import './index.css'
    
    const app = createApp(App)
    app.use(ElementPlus)
    app.use(router)
    app.mount('#app')
    

    以上代码便完成了 Element Plus 的引入。需要注意的是,样式文件需要单独引入。


    按需引入

    借助 babel-plugin-component,我们可以只引入需要的组件,以达到减小项目体积的目的。

    首先,安装 babel-plugin-component:

    npm install babel-plugin-component -D
    

    然后,将 .babelrc 修改为:

    {
      "plugins": [
        [
          "component",
          {
            "libraryName": "element-plus",
            "styleLibraryName": "theme-chalk"
          }
        ]
      ]
    }
    

    接下来,如果你只希望引入部分组件,比如 Button 和 Select,那么需要在 main.js 中写入以下内容:

    import { createApp } from 'vue'
    import { store, key } from './store';
    import router from "./router";
    import { ElButton, ElSelect } from 'element-plus';
    import App from './App.vue';
    import './index.css'
    
    const app = createApp(App)
    app.component(ElButton.name, ElButton);
    app.component(ElSelect.name, ElSelect);
    
    /* or
     * app.use(ElButton)
     * app.use(ElSelect)
     */
    
    app.use(store, key)
    app.use(router)
    app.mount('#app')
    app.mount('#app')
    

    更详细的安装方法请看 快速上手。

    5.3 全局配置

    在引入 Element Plus 时,可以传入一个全局配置对象。

    该对象目前支持 size 与 zIndex 字段。size 用于改变组件的默认尺寸,zIndex 设置弹框的初始 z-index(默认值:2000)。按照引入 Element Plus 的方式,具体操作如下:

    完整引入 Element:

    import { createApp } from 'vue'
    import ElementPlus from 'element-plus';
    import App from './App.vue';
    
    const app = createApp(App)
    app.use(ElementPlus, { size: 'small', zIndex: 3000 });
    

    按需引入 Element:

    import { createApp } from 'vue'
    import { ElButton } from 'element-plus';
    import App from './App.vue';
    
    const app = createApp(App)
    app.config.globalProperties.$ELEMENT = option
    app.use(ElButton);
    

    按照以上设置,项目中所有拥有 size 属性的组件的默认尺寸均为 'small',弹框的初始 z-index 为 3000。

    5.4 配置 vite.config.ts

    其中 proxy 和 alias 是和 vue-cli 区别比较大的地方。

    import { defineConfig } from 'vite'
    import vue from '@vitejs/plugin-vue'
    import styleImport from 'vite-plugin-style-import'
    import path from 'path'
    
    // https://vitejs.dev/config/
    export default defineConfig({
      plugins: [
        vue(),
        styleImport({
          libs: [
            {
              libraryName: 'element-plus',
              esModule: true,
              ensureStyleFile: true,
              resolveStyle: (name) => {
                return `element-plus/lib/theme-chalk/${name}.css`;
              },
              resolveComponent: (name) => {
                return `element-plus/lib/${name}`;
              },
            }
          ]
        })
      ],
    
      /**
       * 在生产中服务时的基本公共路径。
       * @default '/'
       */
      base: './',
      /**
      * 与“根”相关的目录,构建输出将放在其中。如果目录存在,它将在构建之前被删除。
      * @default 'dist'
      */
      // outDir: 'dist',
      server: {
        // hostname: '0.0.0.0',
        host: "localhost",
        port: 3001,
        // // 是否自动在浏览器打开
        // open: true,
        // // 是否开启 https
        // https: false,
        // // 服务端渲染
        // ssr: false,
        proxy: {
          '/api': {
            target: 'http://localhost:3333/',
            changeOrigin: true,
            ws: true,
            rewrite: (pathStr) => pathStr.replace('/api', '')
          },
        },
      },
      resolve: {
        // 导入文件夹别名
        alias: {
          '@': path.resolve(__dirname, './src'),
          views: path.resolve(__dirname, './src/views'),
          components: path.resolve(__dirname, './src/components'),
          utils: path.resolve(__dirname, './src/utils'),
          less: path.resolve(__dirname, "./src/less"),
          assets: path.resolve(__dirname, "./src/assets"),
          com: path.resolve(__dirname, "./src/components"),
          store: path.resolve(__dirname, "./src/store"),
          mixins: path.resolve(__dirname, "./src/mixins")
        },
      }
    })
    
    

    踩到坑

    npm run dev 打包时不报错,但是在 npm run build 时却报错了,build 的时候会把 node_modules 里面的文件也编译,所以挺多 element-plus 的类型文件报错了。

    tsconfig.json 里面的 includeexclude 修改一下就不会了,配置如下

    {
      "compilerOptions": {
        "target": "esnext",
        "module": "esnext",
        "moduleResolution": "node",
        "strict": true,
        "jsx": "preserve",
        "sourceMap": true,
        // 忽略 this 的类型检查, Raise error on this expressions with an implied any type.
        "noImplicitThis": false,
        "resolveJsonModule": true,
        "esModuleInterop": true,
        "lib": ["esnext", "dom"],
        "types": ["vite/client"]
      },
      "include": ["/src/**/*.ts", "/src/**/*.d.ts", "/src/**/*.tsx", "/src/**/*.vue"],
      // ts 排除的文件
      "exclude": ["node_modules"]
    }
    

    Vue3 + vite2 打包出来的文件和原来 vue2 版的差别也挺大的,由原来 2.5M 直接变成了 1.8M ,amazing!

    Vue3 全家桶 + TS+ Vite2 + element-plus 搭建简洁时尚的博客网站实战及踩坑记

    最后

    Vue3 全家桶 + TS+ Vite2 + element-plus 搭建简洁时尚的博客网站实战及踩坑记

    项目代码大多都是 2 年前的,还有很多可以优化的地方,这次重构的过程没对原来的样式和代码做什么改动,没那么多时间,加上我懒 ?

    这次就升级了主要框架与相应的 ui 库,过了一遍 Vue3 中的 API,发现很多 Vue3 中新的 API 都用不上,主要是要熟练一下 Vue3 和 Vite2 项目搭建,这假期也算有所收获。

    具体项目源码请看:

    至此,一个基于 Vue3 全家桶 + Vite2 + TypeScript + Element Plus 的开发环境已经搭建完毕,现在就可以编写代码了,各个组件的使用方法请参阅它们各自的文档。

    不得不说 Vue3 + Element Plus + Vite + TypeScript 是真的香!

    推荐一个 Vue3 相关的资料汇总: Vue3 的学习教程汇总、源码解释项目、支持的 UI 组件库、优质实战项目,相信你会挖到矿哦!

    参考文章:vue3 + vite + typescript + eslint + jest 项目配置实践

    推荐阅读

    • TypeScript 中提升幸福感的 10 个高级技巧

    欢迎关注公众号: “全栈修炼”,回复 “电子书” 即可以获得 300 本技术精华书籍哦,猫哥 wx:CB834301747


    下载网 » Vue3 全家桶 + TS+ Vite2 + element-plus 搭建简洁时尚的博客网站实战及踩坑记

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元