├── src ├── store │ ├── actions.ts │ ├── mutations.ts │ ├── getters.ts │ ├── index.ts │ └── modules │ │ └── app.ts ├── pages │ ├── index │ │ ├── App.vue │ │ ├── views │ │ │ ├── tutorial │ │ │ │ ├── index.vue │ │ │ │ ├── Hello.vue │ │ │ │ ├── Dismantling.vue │ │ │ │ └── Dismantling2.vue │ │ │ └── Home.vue │ │ ├── main.ts │ │ └── router │ │ │ └── index.ts │ └── second │ │ ├── views │ │ ├── About.vue │ │ └── Home.vue │ │ ├── main.ts │ │ ├── App.vue │ │ └── router │ │ └── index.ts ├── types │ ├── page.params.d.ts │ ├── api.params.d.ts │ └── http.response.d.ts ├── assets │ └── logo.png ├── shims-vue.d.ts ├── config │ ├── app.config.ts │ └── constant.d.ts ├── utils │ ├── type.parser.ts │ ├── index.ts │ └── request.ts └── components │ └── HelloWorld.vue ├── .eslintignore ├── babel.config.js ├── public ├── favicon.png ├── assets │ └── imgs │ │ ├── dismantling.gif │ │ └── dismantling2.gif ├── model │ └── motorcycle │ │ ├── disdk.jpeg │ │ ├── nomer.jpeg │ │ ├── rezina_3.jpeg │ │ ├── protector_2.jpeg │ │ └── motorcycle.mtl └── index.html ├── jest.config.js ├── .editorconfig ├── .gitignore ├── global.d.ts ├── .prettierrc.js ├── tests └── unit │ └── example.spec.ts ├── config └── build.js ├── .npmrc ├── tsconfig.json ├── LICENSE ├── .github └── workflows │ └── build.yml ├── README.md ├── package.json ├── .eslintrc.js └── vue.config.js /src/store/actions.ts: -------------------------------------------------------------------------------- 1 | export default {}; 2 | -------------------------------------------------------------------------------- /src/store/mutations.ts: -------------------------------------------------------------------------------- 1 | export default {}; 2 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /dist/** 2 | /docs/** 3 | /node_modules/** 4 | 5 | -------------------------------------------------------------------------------- /src/pages/index/App.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['@vue/cli-plugin-babel/preset'] 3 | }; 4 | -------------------------------------------------------------------------------- /public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/funnyzak/threejs-tutorial/HEAD/public/favicon.png -------------------------------------------------------------------------------- /src/types/page.params.d.ts: -------------------------------------------------------------------------------- 1 | export declare interface IPageParams { 2 | id?: number; 3 | } 4 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/funnyzak/threejs-tutorial/HEAD/src/assets/logo.png -------------------------------------------------------------------------------- /src/pages/index/views/tutorial/index.vue: -------------------------------------------------------------------------------- 1 | 4 | ; 5 | -------------------------------------------------------------------------------- /src/types/api.params.d.ts: -------------------------------------------------------------------------------- 1 | export declare interface IContentsParams { 2 | page: number; 3 | perPage: number; 4 | } 5 | -------------------------------------------------------------------------------- /public/assets/imgs/dismantling.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/funnyzak/threejs-tutorial/HEAD/public/assets/imgs/dismantling.gif -------------------------------------------------------------------------------- /public/assets/imgs/dismantling2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/funnyzak/threejs-tutorial/HEAD/public/assets/imgs/dismantling2.gif -------------------------------------------------------------------------------- /public/model/motorcycle/disdk.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/funnyzak/threejs-tutorial/HEAD/public/model/motorcycle/disdk.jpeg -------------------------------------------------------------------------------- /public/model/motorcycle/nomer.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/funnyzak/threejs-tutorial/HEAD/public/model/motorcycle/nomer.jpeg -------------------------------------------------------------------------------- /public/model/motorcycle/rezina_3.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/funnyzak/threejs-tutorial/HEAD/public/model/motorcycle/rezina_3.jpeg -------------------------------------------------------------------------------- /public/model/motorcycle/protector_2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/funnyzak/threejs-tutorial/HEAD/public/model/motorcycle/protector_2.jpeg -------------------------------------------------------------------------------- /src/pages/second/views/About.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/store/getters.ts: -------------------------------------------------------------------------------- 1 | const getters = { 2 | device: (state: any) => state.app.device, 3 | status: (state: any) => state.app.status 4 | }; 5 | export default getters; 6 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: '@vue/cli-plugin-unit-jest/presets/typescript-and-babel', 3 | transform: { 4 | '^.+\\.vue$': 'vue-jest' 5 | } 6 | }; 7 | -------------------------------------------------------------------------------- /src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | declare module '*.vue' { 3 | import type { DefineComponent } from 'vue'; 4 | const component: DefineComponent<{}, {}, any>; 5 | export default component; 6 | } 7 | -------------------------------------------------------------------------------- /src/pages/index/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue'; 2 | import App from './App.vue'; 3 | import router from './router'; 4 | import store from '@/store'; 5 | 6 | createApp(App).use(store).use(router).mount('#app'); 7 | -------------------------------------------------------------------------------- /src/pages/second/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue'; 2 | import App from './App.vue'; 3 | import router from './router'; 4 | import store from '@/store'; 5 | 6 | createApp(App).use(store).use(router).mount('#app'); 7 | -------------------------------------------------------------------------------- /src/config/app.config.ts: -------------------------------------------------------------------------------- 1 | // App 名称 2 | export const appName: string = 'APP Name'; 3 | 4 | // baseURl 5 | export const baseURL: string = ''; 6 | 7 | export const staticBaseURL: string = 'https://static.domain.com'; 8 | 9 | // 加密Key 10 | export const apiKey: string = 'c340176a-99a0-4f275a1d8'; 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | # need install => EditorConfig for VS Code 3 | root = true 4 | 5 | [*.{js,jsx,ts,tsx,vue}] 6 | indent_style = space 7 | indent_size = 2 8 | end_of_line = lf 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | max_line_length = 100 12 | 13 | [*.md] 14 | trim_trailing_whitespace = true 15 | -------------------------------------------------------------------------------- /src/store/index.ts: -------------------------------------------------------------------------------- 1 | import app from './modules/app'; 2 | import getters from './getters'; 3 | import actions from './actions'; 4 | import mutations from './mutations'; 5 | 6 | import { createStore } from 'vuex'; 7 | 8 | export default createStore({ 9 | state: {}, 10 | mutations, 11 | actions, 12 | getters, 13 | modules: { 14 | app 15 | } 16 | }); 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | /public/tmp 5 | .eslintcache 6 | 7 | # local env files 8 | .env.local 9 | .env.*.local 10 | 11 | # Log files 12 | npm-debug.log* 13 | yarn-debug.log* 14 | yarn-error.log* 15 | pnpm-debug.log* 16 | 17 | # Editor directories and files 18 | .idea 19 | .vscode 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /global.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.png'; 2 | declare module '*.gif'; 3 | declare module '*.jpg'; 4 | declare module '*.jpeg'; 5 | declare module '*.svg'; 6 | declare module '*.css'; 7 | declare module '*.less'; 8 | declare module '*.scss'; 9 | declare module '*.sass'; 10 | declare module '*.styl'; 11 | declare module '*.txt'; 12 | declare module '*.html'; 13 | declare module '*.hbs'; 14 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | // https://prettier.io/docs/en/options.html 2 | module.exports = { 3 | // 尾后逗号 4 | trailingComma: 'none', 5 | 6 | tabWidth: 2, 7 | // 结尾分号 8 | semi: true, 9 | // Use single quotes instead of double quotes. 10 | singleQuote: true, 11 | // Change when properties in objects are quoted. 12 | quoteProps: 'consistent', 13 | bracketSpacing: true, 14 | bracketSameLine: true 15 | }; 16 | -------------------------------------------------------------------------------- /tests/unit/example.spec.ts: -------------------------------------------------------------------------------- 1 | import { shallowMount } from '@vue/test-utils'; 2 | import HelloWorld from '@/components/HelloWorld.vue'; 3 | 4 | describe('HelloWorld.vue', () => { 5 | it('renders props.msg when passed', () => { 6 | const msg = 'new message'; 7 | const wrapper = shallowMount(HelloWorld, { 8 | props: { msg } 9 | }); 10 | expect(wrapper.text()).toMatch(msg); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /src/utils/type.parser.ts: -------------------------------------------------------------------------------- 1 | import { staticBaseURL } from '@/config/app.config'; 2 | 3 | /** 4 | * 转换静态地址 5 | * @param url 接口返回的地址 6 | * @returns 7 | */ 8 | export const parseStaticUrl = (url: string): string => { 9 | if (!url || url === null || url === '') return ''; 10 | return url.startsWith('/') 11 | ? staticBaseURL + url 12 | : url.startsWith('@') 13 | ? staticBaseURL + url.substring(1) 14 | : url; 15 | }; 16 | -------------------------------------------------------------------------------- /src/config/constant.d.ts: -------------------------------------------------------------------------------- 1 | export const HTTP_STATUS = { 2 | SUCCESS: 200, 3 | CLIENT_ERROR: 400, 4 | AUTHENTICATE: 401, 5 | FORBIDDEN: 403, 6 | NOT_FOUND: 404, 7 | SERVER_ERROR: 500, 8 | BAD_GATEWAY: 502, 9 | SERVICE_UNAVAILABLE: 503, 10 | GATEWAY_TIMEOUT: 504 11 | }; 12 | 13 | // 定义可使用的Request方法 14 | export type RequestMethod = 15 | | 'OPTIONS' 16 | | 'GET' 17 | | 'HEAD' 18 | | 'POST' 19 | | 'PUT' 20 | | 'DELETE' 21 | | 'TRACE' 22 | | 'CONNECT'; 23 | -------------------------------------------------------------------------------- /src/types/http.response.d.ts: -------------------------------------------------------------------------------- 1 | // 内容返回数据 2 | export declare interface IContentResponse { 3 | city: string; 4 | summary: string; 5 | author: string; 6 | source: string; 7 | top: boolean; 8 | recommend: boolean; 9 | hot: boolean; 10 | color: boolean; 11 | linkUrl?: string; 12 | addDate: string; 13 | id: number; 14 | } 15 | 16 | // 内容列表返回数据 17 | export declare interface IContentsResponse { 18 | totalCount: number; 19 | contents: Array; 20 | } 21 | -------------------------------------------------------------------------------- /src/pages/second/views/Home.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 20 | -------------------------------------------------------------------------------- /config/build.js: -------------------------------------------------------------------------------- 1 | const { run } = require('runjs'); 2 | const processArgs = require('minimist')(process.argv.slice(2)); 3 | 4 | // const { argv } = require('process') 5 | // console.log(processArgs, argv) 6 | 7 | const mode = processArgs.mode ? processArgs.mode : 'build'; 8 | 9 | const runService = () => { 10 | if (processArgs._.length > 1) { 11 | const action = processArgs._[0]; 12 | run(`npx vue-cli-service ${mode} --action=${action} --name=${processArgs._[1]}`); 13 | } else { 14 | run(`npx vue-cli-service ${mode}`); 15 | } 16 | }; 17 | 18 | runService(); 19 | -------------------------------------------------------------------------------- /src/store/modules/app.ts: -------------------------------------------------------------------------------- 1 | import { Module } from 'vuex'; 2 | 3 | interface IState { 4 | device: string; 5 | status: string; 6 | } 7 | 8 | const module: Module = { 9 | namespaced: true, 10 | state: { 11 | status: process.env.NODE_ENV, 12 | device: 'desktop' 13 | }, 14 | mutations: { 15 | TOGGLE_DEVICE: (state, device) => { 16 | state.device = device; 17 | } 18 | }, 19 | actions: { 20 | toggleDevice({ commit }, device) { 21 | commit('TOGGLE_DEVICE', device); 22 | } 23 | } 24 | }; 25 | 26 | export default module; 27 | -------------------------------------------------------------------------------- /src/pages/index/views/Home.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 28 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | # 根据需要设置 2 | 3 | # registry=https://registry.npm.taobao.org 4 | # disturl=https://npm.taobao.org/dist 5 | # sass_binary_site=https://npm.taobao.org/mirrors/node-sass/ 6 | # phantomjs_cdnurl=https://npm.taobao.org/mirrors/phantomjs/ 7 | # electron_mirror=https://npm.taobao.org/mirrors/electron/ 8 | # chromedriver_cdnurl=https://npm.taobao.org/mirrors/chromedriver 9 | # operadriver_cdnurl=https://npm.taobao.org/mirrors/operadriver 10 | # selenium_cdnurl=https://npm.taobao.org/mirrors/selenium 11 | # node_inspector_cdnurl=https://npm.taobao.org/mirrors/node-inspector 12 | # fsevents_binary_host_mirror=http://npm.taobao.org/mirrors/fsevents/ -------------------------------------------------------------------------------- /src/pages/second/App.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 31 | -------------------------------------------------------------------------------- /src/pages/second/router/index.ts: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'; 2 | import Home from '../views/Home.vue'; 3 | 4 | const routes: Array = [ 5 | { 6 | path: '/', 7 | name: 'Home', 8 | component: Home 9 | }, 10 | { 11 | path: '/about', 12 | name: 'About', 13 | // route level code-splitting 14 | // this generates a separate chunk (about.[hash].js) for this route 15 | // which is lazy-loaded when the route is visited. 16 | component: () => import(/* webpackChunkName: "about" */ '../views/About.vue') 17 | } 18 | ]; 19 | 20 | const router = createRouter({ 21 | history: createWebHashHistory(), 22 | routes 23 | }); 24 | 25 | export default router; 26 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "esnext", 5 | "strict": true, 6 | "jsx": "preserve", 7 | "importHelpers": true, 8 | "moduleResolution": "node", 9 | "experimentalDecorators": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "sourceMap": true, 14 | "baseUrl": ".", 15 | "types": ["webpack-env", "jest"], 16 | "paths": { 17 | "@/*": ["src/*"] 18 | }, 19 | "lib": ["esnext", "dom", "dom.iterable", "scripthost"] 20 | }, 21 | "include": [ 22 | "global.d.ts", 23 | "src/**/*.ts", 24 | "src/**/*.tsx", 25 | "src/**/*.vue", 26 | "tests/**/*.ts", 27 | "tests/**/*.tsx" 28 | ], 29 | "exclude": ["node_modules"] 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Leon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export function rangeArray(size: number) { 2 | let _array: Array = []; 3 | for (let i = 0; i < size; i++) { 4 | _array[i] = i; 5 | } 6 | return _array; 7 | } 8 | 9 | export const queryString = (params?: Record): string => { 10 | if (!params || params === null) { 11 | return ''; 12 | } 13 | return ( 14 | '?' + 15 | Object.keys(params) 16 | .map((k) => encodeURIComponent(k) + '=' + encodeURIComponent(params[k])) 17 | .join('&') 18 | ); 19 | }; 20 | 21 | /** 22 | * 将http转为https 23 | * @param url 链接 24 | */ 25 | export const parse2Https = (url: string) => { 26 | if (!url) return; 27 | return url.startsWith('https') ? url : url.replace('http', 'https'); 28 | }; 29 | 30 | export const parseDate = function (date: string) { 31 | var t = Date.parse(date); 32 | if (typeof t === 'number') { 33 | return new Date(Date.parse(date.replace(/-/g, '/'))); 34 | } else { 35 | return new Date(); 36 | } 37 | }; 38 | 39 | export function parseWeekday(sDate: any) { 40 | var dt = typeof sDate === 'string' ? new Date(sDate.replace(/-/g, '/')) : sDate; 41 | var a = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']; 42 | return a[dt.getDay()]; 43 | } 44 | -------------------------------------------------------------------------------- /src/pages/index/router/index.ts: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'; 2 | import Home from '../views/Home.vue'; 3 | import TutorialIndex from '../views/tutorial/index.vue'; 4 | import TutorialHello from '../views/tutorial/Hello.vue'; 5 | import TutoialDismantling from '../views/tutorial/Dismantling.vue'; 6 | import TutoialDismantling2 from '../views/tutorial/Dismantling2.vue'; 7 | 8 | const routes: Array = [ 9 | { 10 | path: '/', 11 | name: 'Home', 12 | component: Home 13 | }, 14 | { 15 | path: '/tutorial', 16 | name: 'Tutoria', 17 | component: TutorialIndex, 18 | redirect: '/tutorial/hello', 19 | children: [ 20 | { 21 | path: 'hello', 22 | name: '正方体', 23 | component: TutorialHello 24 | }, 25 | { 26 | path: 'dismantling', 27 | name: '固定模型拆分效果', 28 | component: TutoialDismantling 29 | }, 30 | { 31 | path: 'dismantling2', 32 | name: '动态模型拆分效果', 33 | component: TutoialDismantling2 34 | } 35 | ] 36 | } 37 | ]; 38 | 39 | const router = createRouter({ 40 | history: createWebHashHistory(), 41 | routes 42 | }); 43 | 44 | export default router; 45 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | tags: # 当我们提交代码为tag 是以'v'开头的时候才会触发自动部署到服务端 如 git push tag v0.1.0 6 | - 'v*' 7 | # Allows you to run this workflow manually from the Actions tab 8 | workflow_dispatch: 9 | jobs: 10 | release: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Check out Git repository 14 | uses: actions/checkout@v2 15 | - name: Install Node.js, NPM and Yarn 16 | uses: actions/setup-node@v2 17 | with: 18 | node-version: '16.3.0' 19 | - name: Restore Npm Cache 20 | uses: actions/cache@v2 21 | with: 22 | path: ~/.npm 23 | key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} 24 | restore-keys: | 25 | ${{ runner.os }}-node- 26 | - name: Install && Build 27 | working-directory: ./ 28 | run: | 29 | npm install 30 | npm run build 31 | - name: Deploy GitHubPage 32 | uses: JamesIves/github-pages-deploy-action@4.1.5 33 | with: 34 | ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }} 35 | branch: gh-pages # The branch the action should deploy to. 36 | folder: dist 37 | - name: Archive Dist 38 | uses: papeloto/action-zip@v1 39 | with: 40 | files: dist/ 41 | recursive: false 42 | dest: ${{ env.DIST_ARCHIVE_NAME }}.zip 43 | - name: Release 44 | uses: softprops/action-gh-release@v1 45 | if: startsWith(github.ref, 'refs/tags/') 46 | with: 47 | files: | 48 | ${{ env.DIST_ARCHIVE_NAME }}.zip 49 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 13 | <%= htmlWebpackPlugin.options.title %> 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 27 | 30 | 33 | 34 | 35 | 36 | 43 |
44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ThreeJS Tutorial 2 | 3 | [![action][ci-image]][ci-url] 4 | [![license][license-image]][repository-url] 5 | [![GitHub last commit][last-commit-image]][repository-url] 6 | [![GitHub commit activity][commit-activity-image]][repository-url] 7 | 8 | 基于 ThreeJS 做的 一些演示案例。 9 | 10 | [所有示例快速预览。][github-pages-url] 11 | 12 | ## 预览 13 | 14 | - [模型自动拆分展示/爆炸效果](https://funnyzak.github.io/threejs-tutorial/#/tutorial/dismantling2) 15 | ![效果预览](https://raw.githubusercontent.com/funnyzak/threejs-tutorial/dev/public/assets/imgs/dismantling2.gif) 16 | - [模型自动拆分展示/爆炸效果](https://funnyzak.github.io/threejs-tutorial/#/tutorial/dismantling) 17 | ![效果预览](https://raw.githubusercontent.com/funnyzak/threejs-tutorial/dev/public/assets/imgs/dismantling.gif) 18 | 19 | ## 使用 20 | 21 | ```bash 22 | # 安装依赖 23 | npm install 24 | 25 | # 默认启动(所有) 26 | npm run serve 27 | 28 | # 全部构建(所有) 29 | npm run build 30 | 31 | # 仅启动**second**页 32 | npm run serve:module second 33 | 34 | # 仅构建**second**页 35 | npm run build:module second 36 | 37 | # Lint 格式化/检查 38 | npm run eslint 39 | 40 | # 运行 jest 测试 41 | npm run test:unit 42 | ``` 43 | 44 | ## 参考 45 | 46 | - [threejs](https://github.com/mrdoob/three.js/tree/master) 47 | - [threejs-model-viewer](https://adjam93.github.io/threejs-model-viewer/#) 48 | 49 | ## License 50 | 51 | MIT License © 2021 [funnyzak](https://github.com/funnyzak) 52 | 53 | [ci-image]: https://img.shields.io/github/actions/workflow/status/funnyzak/threejs-tutorial/build.yml 54 | [ci-url]: https://github.com/funnyzak/threejs-tutorial/actions 55 | [license-image]: https://img.shields.io/github/license/funnyzak/threejs-tutorial.svg?style=flat-square 56 | [repository-url]: https://github.com/funnyzak/threejs-tutorial 57 | [github-pages-image]: https://img.shields.io/github/pages/funnyzak/threejs-tutorial.svg?style=flat-square 58 | [github-pages-url]: https://funnyzak.github.io/threejs-tutorial/ 59 | [commit-activity-image]: https://img.shields.io/github/commit-activity/m/funnyzak/threejs-tutorial?style=flat-square 60 | [last-commit-image]: https://img.shields.io/github/last-commit/funnyzak/threejs-tutorial?style=flat-square 61 | -------------------------------------------------------------------------------- /src/pages/index/views/tutorial/Hello.vue: -------------------------------------------------------------------------------- 1 | 4 | 74 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "threejs-tutorial", 3 | "description": "some threejs tutorial", 4 | "version": "0.2.0", 5 | "private": true, 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/funnyzak/threejs-tutorial.git" 9 | }, 10 | "keywords": [ 11 | "vue", 12 | "typescript", 13 | "webpack" 14 | ], 15 | "author": "funnyzak ", 16 | "license": "ISC", 17 | "bugs": { 18 | "url": "https://github.com/funnyzak/threejs-tutorial/issues" 19 | }, 20 | "homepage": "https://github.com/funnyzak/threejs-tutorial#readme", 21 | "scripts": { 22 | "serve": "cross-env node ./config/build.js --mode=serve", 23 | "build": "cross-env node ./config/build.js --mode=build", 24 | "serve:module": "cross-env node ./config/build.js --mode=serve module", 25 | "build:module": "cross-env node ./config/build.js --mode=build module", 26 | "test:unit": "vue-cli-service test:unit", 27 | "eslint": "eslint --fix --cache .", 28 | "lint": "vue-cli-service lint" 29 | }, 30 | "dependencies": { 31 | "@tweenjs/tween.js": "^18.6.4", 32 | "axios": "^0.23.0", 33 | "core-js": "^3.6.5", 34 | "minimist": "^1.2.5", 35 | "three": "^0.135.0", 36 | "vue": "^3.0.0", 37 | "vue-class-component": "^8.0.0-0", 38 | "vue-router": "^4.0.0-0", 39 | "vuex": "^4.0.0-0" 40 | }, 41 | "devDependencies": { 42 | "@types/jest": "^24.0.19", 43 | "@typescript-eslint/eslint-plugin": "^4.18.0", 44 | "@typescript-eslint/parser": "^4.18.0", 45 | "@vue/cli-plugin-babel": "~4.5.0", 46 | "@vue/cli-plugin-eslint": "~4.5.0", 47 | "@vue/cli-plugin-router": "~4.5.0", 48 | "@vue/cli-plugin-typescript": "~4.5.0", 49 | "@vue/cli-plugin-unit-jest": "~4.5.0", 50 | "@vue/cli-plugin-vuex": "~4.5.0", 51 | "@vue/cli-service": "~4.5.0", 52 | "@vue/compiler-sfc": "^3.0.0", 53 | "@vue/eslint-config-airbnb": "^5.0.2", 54 | "@vue/eslint-config-typescript": "^7.0.0", 55 | "@vue/test-utils": "^2.0.0-0", 56 | "cross-env": "^7.0.3", 57 | "eslint": "^6.8.0", 58 | "eslint-plugin-import": "^2.20.2", 59 | "eslint-plugin-vue": "^7.20.0", 60 | "git-revision-webpack-plugin": "^3.0.6", 61 | "lint-staged": "^9.5.0", 62 | "prettier": "2.4.1", 63 | "runjs": "^4.4.2", 64 | "sass": "^1.26.5", 65 | "sass-loader": "^8.0.2", 66 | "typescript": "~4.1.5", 67 | "vue-eslint-parser": "^7.11.0", 68 | "vue-jest": "^5.0.0-0", 69 | "webpack-bundle-analyzer": "^4.5.0" 70 | }, 71 | "gitHooks": { 72 | "pre-commit": "lint-staged" 73 | }, 74 | "lint-staged": { 75 | "*.{js,jsx,vue,ts,tsx}": [ 76 | "prettier --write", 77 | "eslint --fix --cache", 78 | "vue-cli-service lint", 79 | "git add" 80 | ], 81 | "*.{md,html,json,css,less,scss,sass}": [ 82 | "prettier --write", 83 | "git add" 84 | ] 85 | }, 86 | "browserslist": { 87 | "production": [ 88 | ">0.2%", 89 | "not dead", 90 | "not op_mini all" 91 | ], 92 | "development": [ 93 | "last 2 chrome version", 94 | "last 2 firefox version", 95 | "last 2 safari version" 96 | ] 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true 5 | }, 6 | extends: ['@vue/airbnb', '@vue/typescript/recommended'], 7 | plugins: ['@typescript-eslint'], 8 | globals: { 9 | window: true 10 | }, 11 | parser: 'vue-eslint-parser', 12 | parserOptions: { 13 | ecmaVersion: 2020, 14 | parser: '@typescript-eslint/parser', 15 | sourceType: 'module' 16 | }, 17 | overrides: [ 18 | { 19 | files: ['**/__tests__/*.{j,t}s?(x)', '**/tests/unit/**/*.spec.{j,t}s?(x)'], 20 | env: { 21 | jest: true 22 | } 23 | } 24 | ], 25 | rules: { 26 | // 代码长度 27 | 'max-len': [ 28 | 'error', 29 | { code: 1000, ignoreComments: true, ignoreUrls: true, ignoreTemplateLiterals: true } 30 | ], 31 | 'semi': ['error', 'always'], 32 | 'comma-dangle': ['error', 'never'], 33 | 'func-names': 'off', 34 | 'import/no-unresolved': 'off', 35 | 'import/no-extraneous-dependencies': 'off', 36 | 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 37 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 38 | 'no-plusplus': 'off', 39 | 'camelcase': 'off', 40 | 'import/extensions': 'off', 41 | 'no-use-before-define': 'off', 42 | 'no-var-requires': 'off', 43 | 'import/no-commonjs': 'off', 44 | 'no-continue': 'off', 45 | 'no-param-reassign': 'off', 46 | // 控制逗号前后的空格 47 | 'comma-spacing': [2, { before: false, after: true }], 48 | // 控制逗号在行尾出现还是在行首出现 49 | // http://eslint.org/docs/rules/comma-style 50 | 'comma-style': [2, 'last'], 51 | // 圈复杂度 52 | 'complexity': [2, 12], 53 | // 文件末尾强制换行 54 | 'eol-last': 2, 55 | // 方法表达式是否需要命名 56 | 'func-names': 0, 57 | 'no-alert': 0, //禁止使用alert confirm prompt 58 | 'no-array-constructor': 2, //禁止使用数组构造器 59 | 'no-bitwise': 0, //禁止使用按位运算符 60 | 'no-caller': 1, //禁止使用arguments.caller或arguments.callee 61 | 'no-catch-shadow': 2, //禁止catch子句参数与外部作用域变量同名 62 | 'no-class-assign': 2, //禁止给类赋值 63 | 'no-cond-assign': 2, //禁止在条件表达式中使用赋值语句 64 | 'no-const-assign': 2, //禁止修改const声明的变量 65 | 'no-constant-condition': 2, //禁止在条件中使用常量表达式 if(true) if(1) 66 | 'no-dupe-keys': 2, //在创建对象字面量时不允许键重复 {a:1,a:1} 67 | 'no-dupe-args': 2, //函数参数不能重复 68 | 'no-duplicate-case': 2, //switch中的case标签不能重复 69 | 'no-else-return': 2, //如果if语句里面有return,后面不能跟else语句 70 | 'quote-props': ['warn', 'consistent'], 71 | // 定义未使用 72 | 'no-unused-vars': 'off', 73 | // 禁止使用 for..in for..of 74 | 'no-restricted-syntax': 1, 75 | // 禁止标识符下划线 76 | 'no-underscore-dangle': 'off', 77 | // 导入多次 78 | 'import/no-duplicates': 0, 79 | 'import/prefer-default-export': 0, 80 | // 禁止promise 使用async 81 | 'no-async-promise-executor': 0, 82 | // image元素必须有alt标签 83 | 'jsx-a11y/alt-text': 0, 84 | // 变量作用域 85 | 'no-shadow': 'off', 86 | // 不允许嵌套的三元表达式 87 | 'no-nested-ternary': 'off', 88 | 'no-await-in-loop': 'off', 89 | 'class-methods-use-this': 'off', 90 | 'prefer-promise-reject-errors': ['error', { allowEmptyReject: true }], 91 | // 对象/数组 解构 92 | 'prefer-destructuring': [ 93 | 'error', 94 | { 95 | array: true, 96 | object: true 97 | }, 98 | { 99 | enforceForRenamedProperties: false 100 | } 101 | ], 102 | 'no-unused-expressions': ['off', { allowShortCircuit: true }], 103 | '@typescript-eslint/no-unused-vars': 'off', 104 | '@typescript-eslint/no-shadow': 'error', 105 | '@typescript-eslint/no-var-requires': 'off', 106 | '@typescript-eslint/explicit-module-boundary-types': 'off' 107 | } 108 | }; 109 | -------------------------------------------------------------------------------- /src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 92 | 93 | 105 | 106 | 107 | 123 | -------------------------------------------------------------------------------- /src/utils/request.ts: -------------------------------------------------------------------------------- 1 | import axios, { 2 | AxiosRequestConfig, 3 | AxiosResponse, 4 | AxiosRequestHeaders, 5 | AxiosInstance, 6 | Method 7 | } from 'axios'; 8 | import { queryString } from '@/utils'; 9 | 10 | export type RequestBefore = (config: AxiosRequestConfig) => AxiosRequestConfig; 11 | export type ResponseHook = (response: AxiosResponse) => any; 12 | 13 | export default class AxiosRequest { 14 | requestConfig: AxiosRequestConfig; 15 | 16 | requestBefore?: RequestBefore; 17 | 18 | responseHook?: ResponseHook; 19 | 20 | constructor( 21 | requestConfig?: AxiosRequestConfig, 22 | requestBefore?: RequestBefore, 23 | responseHook?: ResponseHook 24 | ) { 25 | this.requestConfig = requestConfig && requestConfig !== null ? requestConfig : this.defaultConfig(); 26 | this.requestBefore = requestBefore; 27 | this.responseHook = responseHook; 28 | } 29 | 30 | defaultConfig(): AxiosRequestConfig { 31 | return { 32 | baseURL: '', 33 | timeout: 36000000, 34 | withCredentials: true 35 | }; 36 | } 37 | 38 | requestContentTypeHeader(contentType?: string): AxiosRequestHeaders { 39 | return !contentType ? {} : { 'content-type': contentType }; 40 | } 41 | 42 | createInstance(): AxiosInstance { 43 | const service = axios.create(this.requestConfig); 44 | 45 | service.interceptors.request.use( 46 | (config: AxiosRequestConfig) => { 47 | config = this.requestBefore && this.requestBefore !== null ? this.requestBefore(config) : config; 48 | 49 | const headers: AxiosRequestHeaders = config.headers ? config.headers : {}; 50 | headers['X-Requested-With'] = 'XMLHttpRequest'; 51 | config.headers = headers || {}; 52 | 53 | return config; 54 | }, 55 | (error: any) => Promise.reject(new Error('请求超时')) 56 | ); 57 | 58 | service.interceptors.response.use( 59 | (response: AxiosResponse) => new Promise((resolve, reject) => { 60 | if (response.status === 200) { 61 | if (this.responseHook && this.responseHook !== null) { 62 | return resolve(this.responseHook(response)); 63 | } 64 | return resolve(response.data); 65 | } 66 | switch (response.status) { 67 | case 401: 68 | return reject(new Error('无此权限')); 69 | case 403: 70 | return reject(new Error('禁止访问')); 71 | case 404: 72 | return reject(new Error('接口不存在')); 73 | case 500: 74 | return reject(new Error('接口发送了异常')); 75 | case 504: 76 | return reject(new Error('代理接口服务不可用')); 77 | case 502: 78 | return reject(new Error('接口代理出错')); 79 | default: 80 | return reject(new Error('请求失败')); 81 | } 82 | }), 83 | (error: any) => Promise.reject(error) 84 | ); 85 | return service; 86 | } 87 | 88 | request( 89 | url: string, 90 | method: Method, 91 | params?: Record, 92 | data?: any, 93 | contentType?: string 94 | ) { 95 | return this.createInstance().request({ 96 | url, 97 | method, 98 | params: queryString(params), 99 | headers: this.requestContentTypeHeader(contentType), 100 | data 101 | }); 102 | } 103 | 104 | get( 105 | url: string, 106 | params?: Record, 107 | contentType?: string 108 | ): Promise> { 109 | return this.request(url, 'GET', params, null, contentType); 110 | } 111 | 112 | del( 113 | url: string, 114 | params?: Record, 115 | contentType?: string 116 | ): Promise> { 117 | return this.request(url, 'DELETE', params, null, contentType); 118 | } 119 | 120 | post( 121 | url: string, 122 | params?: Record, 123 | data?: any, 124 | contentType?: string 125 | ): Promise> { 126 | return this.request(url, 'POST', params, data, contentType); 127 | } 128 | 129 | put( 130 | url: string, 131 | params?: Record, 132 | data?: any, 133 | contentType?: string 134 | ): Promise> { 135 | return this.request(url, 'PUT', params, data, contentType); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /public/model/motorcycle/motorcycle.mtl: -------------------------------------------------------------------------------- 1 | # Blender MTL File: 'motorcycle.blend' 2 | # Material Count: 22 3 | 4 | newmtl Material.001 5 | Ns 359.999993 6 | Ka 1.000000 1.000000 1.000000 7 | Kd 0.800000 0.800000 0.800000 8 | Ks 0.500000 0.500000 0.500000 9 | Ke 0.000000 0.000000 0.000000 10 | Ni 1.450000 11 | d 1.000000 12 | illum 2 13 | 14 | newmtl Material.002 15 | Ns 40.812148 16 | Ka 1.000000 1.000000 1.000000 17 | Kd 0.008076 0.008076 0.008076 18 | Ks 0.000000 0.000000 0.000000 19 | Ke 0.000000 0.000000 0.000000 20 | Ni 1.450000 21 | d 1.000000 22 | illum 1 23 | map_Kd protector_2.jpeg 24 | 25 | newmtl Material.003 26 | Ns 349.173557 27 | Ka 1.000000 1.000000 1.000000 28 | Kd 0.800000 0.800000 0.800000 29 | Ks 0.631313 0.631313 0.631313 30 | Ke 0.000000 0.000000 0.000000 31 | Ni 1.450000 32 | d 1.000000 33 | illum 2 34 | map_Kd nomer.jpeg 35 | 36 | newmtl Material.004 37 | Ns 48.600219 38 | Ka 1.000000 1.000000 1.000000 39 | Kd 0.800000 0.800000 0.800000 40 | Ks 0.000000 0.000000 0.000000 41 | Ke 0.000000 0.000000 0.000000 42 | Ni 1.450000 43 | d 1.000000 44 | illum 1 45 | map_Kd rezina_3.jpeg 46 | 47 | newmtl Material.005 48 | Ns 250.000000 49 | Ka 1.000000 1.000000 1.000000 50 | Kd 0.800000 0.800000 0.800000 51 | Ks 0.500000 0.500000 0.500000 52 | Ke 0.000000 0.000000 0.000000 53 | Ni 1.450000 54 | d 1.000000 55 | illum 2 56 | 57 | newmtl Material.006 58 | Ns 4.999492 59 | Ka 1.000000 1.000000 1.000000 60 | Kd 0.083532 0.035709 0.022448 61 | Ks 0.186869 0.186869 0.186869 62 | Ke 0.000000 0.000000 0.000000 63 | Ni 1.450000 64 | d 1.000000 65 | illum 2 66 | 67 | newmtl None 68 | Ns 499.999983 69 | Ka 1.000000 1.000000 1.000000 70 | Kd 0.800000 0.800000 0.800000 71 | Ks 0.800000 0.800000 0.800000 72 | Ke 0.000000 0.000000 0.000000 73 | Ni 1.450000 74 | d 1.000000 75 | illum 2 76 | 77 | newmtl bak 78 | Ns 745.867762 79 | Ka 1.000000 1.000000 1.000000 80 | Kd 0.800000 0.143573 0.030582 81 | Ks 0.262626 0.262626 0.262626 82 | Ke 0.000000 0.000000 0.000000 83 | Ni 1.450000 84 | d 1.000000 85 | illum 2 86 | 87 | newmtl bak.001 88 | Ns 451.203952 89 | Ka 1.000000 1.000000 1.000000 90 | Kd 0.559602 0.102903 0.022869 91 | Ks 0.212121 0.212121 0.212121 92 | Ke 0.000000 0.000000 0.000000 93 | Ni 1.450000 94 | d 1.000000 95 | illum 2 96 | 97 | newmtl black_paint 98 | Ns 325.706574 99 | Ka 1.000000 1.000000 1.000000 100 | Kd 0.018849 0.018849 0.018849 101 | Ks 0.267677 0.267677 0.267677 102 | Ke 0.000000 0.000000 0.000000 103 | Ni 1.450000 104 | d 1.000000 105 | illum 2 106 | 107 | newmtl black_plastic 108 | Ns 159.192953 109 | Ka 1.000000 1.000000 1.000000 110 | Kd 0.028779 0.027354 0.035214 111 | Ks 0.358586 0.358586 0.358586 112 | Ke 0.000000 0.000000 0.000000 113 | Ni 1.450000 114 | d 1.000000 115 | illum 2 116 | 117 | newmtl brown_skin 118 | Ns 167.355443 119 | Ka 1.000000 1.000000 1.000000 120 | Kd 0.178863 0.062150 0.024090 121 | Ks 0.459596 0.459596 0.459596 122 | Ke 0.000000 0.000000 0.000000 123 | Ni 1.450000 124 | d 1.000000 125 | illum 2 126 | 127 | newmtl chrome 128 | Ns 566.294237 129 | Ka 1.000000 1.000000 1.000000 130 | Kd 0.800000 0.800000 0.800000 131 | Ks 0.419192 0.419192 0.419192 132 | Ke 0.000000 0.000000 0.000000 133 | Ni 1.450000 134 | d 1.000000 135 | illum 3 136 | 137 | newmtl diskl 138 | Ns 337.338018 139 | Ka 1.000000 1.000000 1.000000 140 | Kd 0.800000 0.800000 0.800000 141 | Ks 0.388889 0.388889 0.388889 142 | Ke 0.000000 0.000000 0.000000 143 | Ni 1.450000 144 | d 1.000000 145 | illum 3 146 | map_Kd disdk.jpeg 147 | 148 | newmtl fara 149 | Ns 359.999993 150 | Ka 1.000000 1.000000 1.000000 151 | Kd 0.800000 0.800000 0.800000 152 | Ks 0.500000 0.500000 0.500000 153 | Ke 0.000000 0.000000 0.000000 154 | Ni 1.450000 155 | d 1.000000 156 | illum 2 157 | 158 | newmtl gold_paint 159 | Ns 56.346278 160 | Ka 1.000000 1.000000 1.000000 161 | Kd 0.233016 0.057328 0.030672 162 | Ks 0.439394 0.439394 0.439394 163 | Ke 0.000000 0.000000 0.000000 164 | Ni 1.450000 165 | d 1.000000 166 | illum 3 167 | 168 | newmtl greu_plastic 169 | Ns 77.160501 170 | Ka 1.000000 1.000000 1.000000 171 | Kd 0.049550 0.049550 0.049550 172 | Ks 0.186869 0.186869 0.186869 173 | Ke 0.000000 0.000000 0.000000 174 | Ni 1.450000 175 | d 1.000000 176 | illum 2 177 | 178 | newmtl hild.001 179 | Ns 359.999993 180 | Ka 1.000000 1.000000 1.000000 181 | Kd 0.800000 0.800000 0.800000 182 | Ks 0.500000 0.500000 0.500000 183 | Ke 0.000000 0.000000 0.000000 184 | Ni 1.450000 185 | d 1.000000 186 | illum 2 187 | 188 | newmtl metall 189 | Ns 31.246822 190 | Ka 1.000000 1.000000 1.000000 191 | Kd 0.420025 0.420025 0.420025 192 | Ks 0.348485 0.348485 0.348485 193 | Ke 0.000000 0.000000 0.000000 194 | Ni 1.450000 195 | d 1.000000 196 | illum 3 197 | 198 | newmtl new_black 199 | Ns 56.346278 200 | Ka 1.000000 1.000000 1.000000 201 | Kd 0.018820 0.015783 0.015033 202 | Ks 0.439394 0.439394 0.439394 203 | Ke 0.000000 0.000000 0.000000 204 | Ni 1.450000 205 | d 1.000000 206 | illum 2 207 | 208 | newmtl red_paint 209 | Ns 478.752190 210 | Ka 1.000000 1.000000 1.000000 211 | Kd 0.800000 0.043090 0.043090 212 | Ks 0.368687 0.368687 0.368687 213 | Ke 0.000000 0.000000 0.000000 214 | Ni 1.450000 215 | d 1.000000 216 | illum 2 217 | 218 | newmtl yelow_plastic 219 | Ns 220.615270 220 | Ka 1.000000 1.000000 1.000000 221 | Kd 0.673849 0.316938 0.035752 222 | Ks 0.318182 0.318182 0.318182 223 | Ke 0.000000 0.000000 0.000000 224 | Ni 1.450000 225 | d 1.000000 226 | illum 2 227 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const fs = require('fs'); 3 | const processArgs = require('minimist')(process.argv.slice(2)); 4 | 5 | const resolve = (dir) => path.resolve(__dirname, dir); 6 | 7 | // 入口页面基础配置 8 | const pageBaseConfig = { 9 | root: resolve('src/pages'), 10 | entry: 'main.ts', 11 | template: 'public/index.html', 12 | filename: 'index.html' 13 | }; 14 | 15 | // https://www.npmjs.com/package/webpack-bundle-analyzer 16 | const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); 17 | // https://www.npmjs.com/package/git-revision-webpack-plugin 18 | const GitRevisionPlugin = require('git-revision-webpack-plugin'); 19 | 20 | const gitRevisionPlugin = new GitRevisionPlugin({ 21 | branch: true 22 | }); 23 | 24 | const package = require('./package.json'); 25 | 26 | const gitInfo = { 27 | VERSION: gitRevisionPlugin.version(), 28 | COMMITHASH: gitRevisionPlugin.commithash(), 29 | BRANCH: gitRevisionPlugin.branch() 30 | }; 31 | 32 | // 模板参数,应用 template html 33 | // 可在html 使用如: <%=webpackConfig.externals.gitInfo.BRANCH%> 34 | const templateParameters = { 35 | nowTimeString: new Date().toISOString(), 36 | // package.json信息 37 | package, 38 | // 进程信息 39 | process: { 40 | env: process.env 41 | }, 42 | // git信息 43 | gitInfo 44 | }; 45 | 46 | // multi-page 模式, 获取所有page 47 | const getPages = () => { 48 | // 同步读取pages下的文件 49 | const files = fs.readdirSync(pageBaseConfig.root); 50 | const pages = {}; 51 | 52 | for (let i = 0; i < files.length; i++) { 53 | const pageInfo = { name: files[i] }; 54 | pageInfo.path = path.join(pageBaseConfig.root, pageInfo.name); 55 | 56 | if (fs.lstatSync(pageInfo.path).isFile()) { 57 | continue; 58 | } 59 | 60 | // 如果没有入口文件,则跳过 61 | pageInfo.entry = path.join(pageInfo.path, pageBaseConfig.entry); 62 | if (!fs.existsSync(pageInfo.entry)) { 63 | continue; 64 | } 65 | 66 | // 如果对应page下有index模板,则使用该模板,否则使用默认 67 | const templatePath = path.join(pageInfo.path, 'index.html'); 68 | const template = fs.existsSync(templatePath) ? templatePath : pageBaseConfig.template; 69 | 70 | pages[pageInfo.name] = { 71 | entry: pageInfo.entry, 72 | template, 73 | filename: pageInfo.name === 'index' ? 'index.html' : `${pageInfo.name}.html`, 74 | title: pageInfo.name 75 | }; 76 | } 77 | return pages; 78 | }; 79 | 80 | /** 81 | * 如果以单模块启动,则只构建单页面 82 | */ 83 | let entryPages = getPages(); 84 | if (processArgs.action === 'module' && processArgs.name && entryPages[processArgs.name]) { 85 | const tmpPage = {}; 86 | tmpPage[processArgs.name] = entryPages[processArgs.name]; 87 | entryPages = tmpPage; 88 | } 89 | 90 | module.exports = { 91 | pages: entryPages, 92 | // 使用相对路径 93 | publicPath: '', 94 | // 将 lint 错误输出为编译警告 95 | lintOnSave: 'warning', 96 | // 输出文件夹 97 | outputDir: 'dist', 98 | // 放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录。 99 | assetsDir: 'static', 100 | // 指定生成的 index.html 的输出路径 (相对于 outputDir)。也可以是一个绝对路径。 101 | indexPath: 'index.html', 102 | // 文件名hash 103 | filenameHashing: true, 104 | // 生产环境不生成sourcemap 105 | productionSourceMap: false, 106 | // 设置生成的 HTML 中 334 | 366 | -------------------------------------------------------------------------------- /src/pages/index/views/tutorial/Dismantling2.vue: -------------------------------------------------------------------------------- 1 | 29 | 368 | 402 | --------------------------------------------------------------------------------