Front
From the creation of a simple browser navigation Home Page Project, this essay contains the following content:
- vite
- vue3
- vuex4
- vue-router next
Preview effect It helps to clarify these contents, which are limited to space and not easy to narrate. Because the logic of the project is simple, and only a few APIs are used, I just write this small project to be addicted to handle, so I can start with the corresponding title. If you just want to learn the API around vue, this article will bring you limited knowledge.
Initialize project
Initialize the vue3 project with vite. What is vite? Vite is a Web building tool. During the development process, the browser ES Module is imported to provide services for your code, and the generation environment is bundled with Rollup for packaging.
characteristic:
- Lightning fast start of cold server
- Dynamic instant thermal module replacement (HMR)
- True on demand compilation
Features vite supports to date:
- Bare Module Resolving
- Hot Module Replacement
- TypeScript
- CSS / JSON Importing
- Asset URL Handling
- PostCSS
- CSS Modules
- CSS Pre-processors
- JSX
- Web Assembly
- Inline Web Workers
- Custom Blocks
- Config File
- HTTPS/2
- Dev Server Proxy
- Production Build
- Modes and Environment Variables
npm init vite-app aweshome npm install npm run dev npm run build
The resulting directory structure is similar to using Vue cli:
│ .npmignore │ a.txt │ index.html │ package.json ├─public │ favicon.ico └─src │ App.vue │ index.css │ main.js ├─assets │ logo.png └─components HelloWorld.vue
Can be created in the project root directory vite.config.js To configure Vite:
module.exports = { // Import alias // These entries can be exact request - > request mapping * (precise, no wildcard syntax) // It can also be request path - > FS directory mapping. *When using directory mapping // Key * * must start and end with a slash** alias: { // 'react': '@pika/react', // 'react-dom': '@pika/react-dom' // '/@foo/': path.resolve(__dirname, 'some-special-dir'), }, // Configure Dep optimization behavior optimizeDeps: { // exclude: ['dep-a', 'dep-b'], }, // The ability to convert Vue custom blocks. vueCustomBlockTransforms: { // i18n: src => `export default Comp => { ... }`, }, // Configure custom proxy rules for the development server. proxy: { // proxy: { // '/foo': 'http://localhost:4567/foo', // '/api': { // target: 'http://jsonplaceholder.typicode.com', // changeOrigin: true, // rewrite: path => path.replace(/^\/api/, ''), // }, // }, }, // ... }
More configurations can be found in Github.
In addition, you can now use vitepress Build a document or blog instead of the original vuepress.
vue-router next
npm i vue-router@next
src/router/index.js
import from 'vue-router' import Home from '../components/home/Home.vue' import Cards from '../components/cards/Cards.vue' const router = createRouter({ history: createWebHistory(), routes: [ // route -> routes { path: '/', name: 'home', component: Home, }, { path: '/cards', name: 'cards', component: Cards, }, ], }) export default router
vue router next also adds dynamic routing to solve the problem of rule conflict. Have done authority management should have deep experience. More configurations can be found in Github.
vuex4
Use the same API as vuex3.
install
npm i vuex@next
Static data is stored in src/constants in the following forms:
export const vue = [ { title: 'vue', desc: 'Vue Is a progressive framework for building user interfaces', link: 'https://cn.vuejs.org/v2/guide/', img: import('../assets/images/vue.png'), // require -> import }, { title: 'vue Router', desc: 'Vue Router yes Vue.js The official routing manager.', link: 'https://router.vuejs.org/zh/', img: import('../assets/images/vue.png'), }, // ... ]
src/store/index.js
import from 'vuex' import from '../constants/docs' import from '../constants/tools' import from '../constants/asideData' import from '../constants/community' const store = createStore({ state: { asideData: [], mainData: [], }, mutations: { setAsideData(state, key) { const asideActions = { '2': tools, '3': docs, '4': community, } state.asideData = asideActions[key] }, setMainData(state, menuItemText) { const actions = new Map([ ['Front end tools', frontEndTools], ['Office tools', OfficeTools], ['vue', vue], ['react', react], ['Wechat development', wechat], ['Straddle frame', across], ['Compile build', compileBuild], ['Blog', blogs], ]) state.mainData = actions.get(menuItemText) }, }, actions: {}, modules: {}, }) export default store
main.js
Combined with the above vuex Vue router, we can see that the api of the core plug-ins of vue3 has been simplified.
import './index.css' import from 'vue' import store from './store' import App from './App.vue' import router from './router' const app = createApp(App) app.use(store) app.use(router) app.mount('#app')
sass
npm i sass
package.json > dependencies
{ "dependencies": { "vue": "^3.0.0-beta.15", "vue-router": "^4.0.0-alpha.13", "vuex": "^4.0.0-beta.2" }, "devDependencies": { "@vue/compiler-sfc": "^3.0.0-beta.15", "sass": "^1.26.8", "vite": "^1.0.0-beta.1" } }
components
This small project can be composed of only one page. vue in essence. I split it up for easy reading.
App.vue<template> <Header /> <main> <router-view></router-view> </main> <Footer /> </template> <script> import Header from './components/Header.vue' import Footer from './components/Footer.vue' export default { name: 'app', components: { Header, Footer, }, } </script> <style> main { flex: 1; } </style>components/cards/Aside.vue
<template> <aside> <ul> <li :index="item.index" v-for="item in this.$store.state.asideData" :key="item.index" ref="menuItem" @click="handleSelect(item.value)"> <i></i> <span>{{ item.value }}</span> </li> </ul> </aside> </template> <script> import store from '../../store' export default { setup(props, context) { return { handleSelect(value) { store.commit('setMainData', value) }, } }, } </script> <style lang="scss"> aside { flex: 1; background-color: rgb(238, 238, 238); height: 100%; li { display: flex; align-items: center; height: 56px; line-height: 56px; font-size: 14px; color: #303133; padding: 0 1.4rem; list-style: none; cursor: pointer; transition: border-color 0.3s, background-color 0.3s, color 0.3s; white-space: nowrap; &:hover { background-color: rgb(224, 224, 224); } } } @media screen and (max-width: 768px) { aside { display: none; &.active { display: block; } } } </style>components/cards/Cards.vue
<template> <div id="card-outer"> <Aside /> <section></section> </div> </template> <script> import Aside from './Aside.vue' import router from '../../router' export default { components: { Aside, }, } </script> <style lang="scss"> #card-outer { display: flex; align-content: stretch; height: 100%; & > section { flex: 8; } } .main-card { margin: 10px 0; cursor: pointer; .main-card-content { display: flex; align-items: center; img { width: 30px; height: 30px; margin-right: 10px; } .main-card-content-info { width: 90%; h3 { font-size: 14px; } p { font-size: 12px; color: #888ea2; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; width: 100%; line-height: 1.8; } } span { margin-left: 10px; text-decoration: none; &:nth-of-type(1) { font-size: 18px; font-weight: 700; color: #ffa502; white-space: nowrap; } &:nth-of-type(2) { font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } } } } </style>components/home/Home.vue
<template> <section id="search"> <div style="margin-bottom: 10px;"> <span size="mini" type="primary" v-for="(item, index) in source" @click="changeSource(item.name)" :key="index" :style="`background:$;border-color:$`" >{{ item.name }} </span> </div> <div :class="searchbarStyle.className"> <input :placeholder="searchbarStyle.placeholder" v-model="searchValue" clearable v-on:keyup.enter="submit" /> <button @click="submit" slot="append" icon="el-icon-search"> <i></i> </button> </div> </section> </template> <script> export default { data: () => ({ baseUrl: 'https://www.baidu.com/s?ie=UTF-8&wd=', searchValue: '', searchbarStyle: { className: 'baidu', placeholder: 'Baidu once, you will know', }, source: [ { name: 'Baidu', color: '#2932E1', }, { name: 'Sogou', color: '#FF6F17', }, { name: 'Bing', color: '#0c8484', }, { name: 'Google', color: '#4285F4', }, { name: 'NPM', color: '#EA4335', }, ], }), methods: { // You can use the options API in vue3 changeSource(name) { const actions = new Map([ [ 'Baidu', () => { this.baseUrl = 'https://www.baidu.com/s?ie=UTF-8&wd=' this.searchbarStyle = { className: 'baidu', placeholder: 'Baidu once, you will know', } }, ], [ 'Bing', () => { this.baseUrl = 'https://cn.bing.com/search?FORM=BESBTB&q=' this.searchbarStyle = { className: 'bing', placeholder: 'Bing Search', } }, ], [ 'Sogou', () => { this.baseUrl = 'https://www.sogou.com/web?query=' this.searchbarStyle = { className: 'sougou', placeholder: 'Sogou search', } }, ], [ 'Google', () => { this.baseUrl = 'https://www.google.com/search?q=' this.searchbarStyle = { className: 'google', placeholder: 'Google Search', } }, ], [ 'NPM', () => { this.baseUrl = 'https://www.npmjs.com/search?q=' this.searchbarStyle = { className: 'npm', placeholder: 'Search Packages', } }, ], ]) actions.get(name)() }, submit() { const url = this.baseUrl + this.searchValue window.open(url) }, }, } </script> <style lang="scss"> #search { display: flex; flex-direction: column; justify-content: center; align-content: stretch; margin: 0 auto; height: 40vh; width: 40%; & > div { display: flex; } } .search-sources { span { margin-right: 0.5rem; padding: 0.4rem 0.6rem; color: #fff; font-size: 14px; line-height: 14px; border-radius: 2px; &:hover { filter: contrast(80%); transition: 0.3s; } } } .searchbox { padding-left: 1rem; height: 2.6rem; border-radius: 6px; background-color: #fff; border: 1px #ccc solid; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); input { flex: 7; border: none; font-size: 1rem; } button { flex: 1; i { margin-right: 0; } } } $sources-color: ( baidu: #2932e1, bing: #0c8484, sougou: #ff6f17, google: #4285f4, npm: #ea4335, ); $source-list: baidu bing sougou google npm; @each $source in $source-list { .#{$source} { &:hover { border-color: map-get($sources-color, $source); box-shadow: 0 2px 4px map-get($sources-color, $source); transition: all 0.5s; } input { &:hover { border-color: map-get($sources-color, $source); } } } } @media screen and (max-width: 768px) { #search { width: 90%; } } </style>components/Header.vue
<template> <header> <ul> <li @click="handleSelect('home')"> <i></i> <span>home page</span> </li> <li @click="handleSelect('tools')"> <i></i> <span>tool</span> </li> <li @click="handleSelect('docs')"> <i></i> <span>file</span> </li> <li @click="handleSelect('community')"> <i></i> <span>community</span> </li> </ul> <MobileMenu /> </header> </template> <script> import MobileMenu from './MobileMenu.vue' import store from '../store' import router from '../router' export default { components: { MobileMenu, }, setup() { const handleSelect = item => { store.commit('setAsideData', item) if (item === 'home') { router.replace() } else { const actions = { tools: ['setMainData', 'Front end tools'], docs: ['setMainData', 'vue'], community: ['setMainData', 'Blog'], } store.commit(actions[item][0], actions[item][1]) router.replace() } } return { handleSelect, } }, } </script> <style lang="scss"> header { display: flex; height: 60px; align-content: stretch; padding: 0 9.5rem; } .nav { display: flex; align-items: center; align-content: stretch; li { padding: 0.5rem 0.75rem; &:hover { background-color: #f3f1f1; & span { color: #3273dc; } } } } @media screen and (max-width: 768px) { header { padding: 0; } } </style>components/MobileMenu.vue
<template> <section id="mobile-menu"> <div id="navbarBurger" data-target="navMenuMore" :class="" @click="sideToggle"> <span></span> <span></span> <span></span> </div> </section> </template> <script> export default { data: () => ({ active: false, }), methods: { sideToggle() { this.active = !this.active const classList = document.querySelectorAll('aside')[0].classList this.active ? classList.add('active') : classList.remove('active') }, }, } </script> <style lang="scss"> #mobile-menu { display: none; position: absolute; right: 0; top: 0; z-index: 999999; } @media screen and (max-width: 768px) { #mobile-menu { display: block; .navbar-burger { position: relative; color: #835656; cursor: pointer; height: 60px; width: 60px; margin-left: auto; span { background-color: #333; display: block; height: 1px; left: calc(50% - 8px); position: absolute; transform-origin: center; transition-duration: 86ms; transition-property: background-color, opacity, transform; transition-timing-function: ease-out; width: 16px; &:nth-child(1) { top: calc(50% - 6px); } &:nth-child(2) { top: calc(50% - 1px); } &:nth-child(3) { top: calc(50% + 4px); } } &.active { span { &:nth-child(1) { transform: translateY(5px) rotate(45deg); } &:nth-child(2) { opacity: 0; } &:nth-child(3) { transform: translateY(-5px) rotate(-45deg); } } } } } } </style>
last
When a process comes down, vite gives me the feeling of "fast". For the Vue peripheral, the API has made some simplification. If you have some knowledge of esm, it will be more conducive to organizing projects, and its readability is higher than that of vue2.x. There are also some problems, limited to space, which are not discussed in this paper. Do the project or go to vue2.x and its surroundings. In addition, I did not find the vue3 component library.