Quick Start
- Project source code: https://github.com/Wscats/vue-cli
This project comprehensively uses the new features of Vue3.0, which is suitable for novice learning
- Based on the Composition API, i.e. function based API, the transformation is carried out. With Vue Cli, the priority is to experience the characteristics of Vue3
- Using singleton object mode for component communication
- Use axios library for network request and weui library for UI interface
# Installation dependency npm install # Open the localhost:8080 view page in the browser, and hot update in real time npm run serve # Project release npm run build
It is recommended to cooperate with Visual Studio Code and Vue 3 Snippets Code plug-ins eat ψ ( ̄  ̄  ̄) ψ.
Dependencies
The following are the dependencies applied to the project, @ vue / composition API and vue module let vue 2.0 experience the new features of vue 3.0 first. axios is a tool library to help us send network requests to get data. weui is a basic style library consistent with wechat's original vision, which is convenient for us to quickly build project pages.
"@vue/composition-api": "^0.3.4", "axios": "^0.19.0", "core-js": "^3.4.3", "vue": "^2.6.10", "weui": "^2.1.3"
Directory Structure
├── src │ ├── App.vue # Component entry │ ├── assets # Resource directory │ ├── stores/index.js # State management │ ├── components # Component directory │ │ ├── Header.vue # Head assembly │ │ ├── Search.vue # Search box components │ │ ├── Panel.vue # List components │ ├── main.js # Project entry ├── public # template file ├── vue.config.js # Scaffold profile ├── screenshot # Program screenshots
Composition API
npm install @vue/composition-api --save
After downloading the @ Vue / Composition API plug-in with npm command, Vue.use(VueCompositionApi) needs to be called explicitly after the module is introduced, and the Composition API can be opened by referencing it in main.js according to the document.
// main.js import Vue from 'vue' import App from './App.vue' // 1. Introduce Composition API module import VueCompositionApi from '@vue/composition-api' Vue.config.productionTip = false // 2. Do not miss the explicit call to VueCompositionApi Vue.use(VueCompositionApi) new Vue({ render: h => h(App), }).$mount('#app')
npm install weui --save
We also use npm to install the weui module, and then introduce the basic style library of weui in main.js, so that we can use wechat basic style to build project pages globally.
// main.js import Vue from 'vue' import App from './App.vue' // Global introduction of basic style library of 'weui' import 'weui' import VueCompositionApi from '@vue/composition-api' Vue.config.productionTip = false Vue.use(VueCompositionApi) new Vue({ render: h => h(App), }).$mount('#app')
Go back to App.vue, keep the value of components attribute to empty the content of < template > template, delete the < style > template, and wait for the new component to be re introduced.
<template> <div id="app"> Hello World </div> </template> <script> export default { name: "app", components: {} }; </script>
In the src/components directory, create the first component, named Header.vue, and write the following code, Click to view the source code:
<template> <header :style="{ backgroundColor: color?color:defaultColor }">{{title}}</header> </template> <script> import { reactive } from "@vue/composition-api"; export default { // The parent component is passed in to change the property value of the header component props: { // Title title: String, // colour color: String }, setup() { const state = reactive({ defaultColor: "red" }); return { ...state }; } }; </script> <style scoped> header { height: 50px; width: 100%; line-height: 50px; text-align: center; color: white; } </style>
setup
Here we use a new property setup, which is the entry of a component. Let's use the new interface exposed by Vue3.0. It runs when the component is instantiated, and after the props property is defined, it is actually equivalent to the two lifecycles of beforeCreate and Created of Vue2.0. Setup returns an object, and all the returned property values In the single file component, it will cooperate with the content of < template > template to complete the binding between Model and View. In the future version, it should also support the return of JSX code fragments.
<template> <!-- View --> <div>{{name}}</div> </template> <script> import { reactive } from '@vue/composition-api' export default { setup() { const state = reactive({ name: 'Eno Yao' }); // return exposed to template return { // Model ...state } } } </script>
reactive
In the setup function, we adapt to the first new interface of Vue3.0, reactive. It mainly deals with your object and makes it become a responsive object after Proxy processing. It is similar to the data attribute of Vue2.0. It should be noted that the processed object is not equal to the original object, and the processed object belongs to the object of deep cloning.
const state = reactive({ name: 'Eno Yao' })
props
In Vue 2.0, we can use props property value to complete parent-child communication. Here we need to define props property to define the type of accepted value. Then we can use the first parameter of setup to obtain props.
export default { props: { // Title title: String, // colour color: String }, setup(props) { // Here you can use the props property value passed from the parent component } };
We can use the header component in App.vue. With props above, we can make the header component present different states according to the values passed in.
<template> <div id="app"> <!-- Reuse components and pass in props Value to make the component present the corresponding state --> <Header title="Eno" color="red" /> <Header title="Yao" color="blue" /> <Header title="Wscats" color="yellow" /> </div> </template> <script> import Header from "./components/Header.vue"; export default { name: "app", components: { Header, } }; </script>
context
The second parameter of the setup function is a context object, which contains some useful properties. These properties need to be accessed through this in Vue2.0. In vue3.0, accessing them becomes the following form:
setup(props, ctx) { console.log(ctx) // this cannot be accessed in the setup() function console.log(this) // undefined }
The following useful properties can be accessed:
- root
- parent
- refs
- attrs
- listeners
- isServer
- ssrContext
- emit
After completing the Header.vue above, we will write the Search.vue search box component, and continue to create a new Search.vue file under the src/components folder, Click to view the source code.
<template> <div :class="['weui-search-bar', {'weui-search-bar_focusing' : isFocus}]" id="searchBar"> <form class="weui-search-bar__form"> <div class="weui-search-bar__box"> <i class="weui-icon-search"></i> <input v-model="searchValue" ref="inputElement" type="search" class="weui-search-bar__input" id="searchInput" placeholder="search" required /> <a href="javascript:" class="weui-icon-clear" id="searchClear"></a> </div> <label @click="toggle" class="weui-search-bar__label" id="searchText"> <i class="weui-icon-search"></i> <span>search</span> </label> </form> <a @click="toggle" href="javascript:" class="weui-search-bar__cancel-btn" id="searchCancel">cancel</a> </div> </template> <script> import { reactive, toRefs, watch } from "@vue/composition-api"; import store from "../stores"; export default { // setup is equivalent to the 2.x version of the beforeCreate life cycle setup() { // The reactive() function takes a normal object and returns a responsive data object const state = reactive({ searchValue: "", // Two states of search box, focusing and unfocusing isFocus: false, inputElement: null }); // How to switch the state of search box const toggle = () => { // Let the input box that appears after clicking search focus automatically state.inputElement.focus(); state.isFocus = !state.isFocus; }; // Listen for search box values watch( () => { return state.searchValue; }, () => { // Store the input box to the status store center for component communication store.setSearchValue(state.searchValue); // window.console.log(state.searchValue); } ); return { // Convert each attribute on the state to responsive data in the form of ref ...toRefs(state), toggle }; } }; </script>
toRefs
We can see that we have used a lot of new attributes above. First, we will introduce toRefs. The function can convert the responsive object created by reactive() into a common object. However, each attribute node on this object is the responsive data of ref(). With the v-model instruction, we can complete the bidirectional binding of data, which is very efficient in development.
import { reactive, toRefs } from "@vue/composition-api"; export default { setup() { const state = reactive({ name: 'Eno Yao' }) } return { // If state is returned directly, the data will be nonresponsive, and MV will bind one way // ...state, // If the state is returned after the toRefs is wrapped, the data will be reactive, and the MVVM will be bound in two directions ...toRefs(state), }; }
template refs
The input box here has two states, one is the state with input box and the state without input box, so we need a Boolean value isFocus to control the state, encapsulate a toggle method, and let the isFocus value switch the true and false states.
const toggle = () => { // Inverse isFocus value state.isFocus = !state.isFocus; };
Then with the v-bind:class instruction, let the name of the weui search bar focusing class decide whether to appear or not according to the value of isFocus, so as to change the state of the search box.
<div :class="['weui-search-bar', {'weui-search-bar_focusing' : isFocus}]" id="searchBar">
v-model instruction is put into the search input box to receive the user's input information, which is convenient for the later to cooperate with the list component to execute the search logic, and ref attribute is also put in to obtain the element node of the < input / > tag. With the native method of state.inputElement.focus(), the cursor will automatically focus on the input box when switching the search box state, so as to enhance the user experience.
<input v-model="searchValue" ref="inputElement" />
watch
The watch() function is used to monitor the changes of some data items, so as to trigger some specific operations. Before use, you still need to import on demand, monitor the changes of searchValue, and then trigger the logic in the callback function, that is, monitor the search value entered by the user, and then touch the logic of the callback function to store the searchValue in the store object we created, which is later in the aspect Data communication with Panel.vue list component:
import { reactive, watch } from "@vue/composition-api"; import store from "../stores"; export default { setup() { const state = reactive({ searchValue: "", }); // Listen for search box values watch( () => { return state.searchValue; }, () => { // Store the input box to the status store center for component communication store.setSearchValue(state.searchValue); } ); return { ...toRefs(state) }; } };
state management
Here we maintain a piece of data to realize shared state management, that is to say, we create a new store.js to expose the searchValue value of the shared Panel and Search component of the store object. When the Search.vue component receives the searchValue retrieval value from the input box, it will be placed in the store object of store.js, and then the object will be injected into the Search component All components can share the value in the store object. In order to facilitate debugging, we also encapsulate setSearchValue and getSearchValue to operate the store object, so that we can track the change of state.
// store.js export default { state: { searchValue: "" }, // Set search box value setSearchValue(value) { this.state.searchValue = value }, // Get the value of the search box getSearchValue() { return this.state.searchValue } }
After completing the above Search.vue, we write the Panel.vue search box component, and continue to create a new Panel.vue file under the src/components folder, Click to view the source code.
<template> <div class="weui-panel weui-panel_access"> <div v-for="(n,index) in newComputed" :key="index" class="weui-panel__bd"> <a href="javascript:void(0);" class="weui-media-box weui-media-box_appmsg"> <div class="weui-media-box__hd"> <img class="weui-media-box__thumb" :src="n.author.avatar_url" alt /> </div> <div class="weui-media-box__bd"> <h4 class="weui-media-box__title" v-text="n.title"></h4> <p class="weui-media-box__desc" v-text="n.author.loginname"></p> </div> </a> </div> <div @click="loadMore" class="weui-panel__ft"> <a href="javascript:void(0);" class="weui-cell weui-cell_access weui-cell_link"> <div class="weui-cell__bd">View more</div> <span class="weui-cell__ft"></span> </a> </div> </div> </template> <script> import { reactive, toRefs, onMounted, computed } from "@vue/composition-api"; import axios from "axios"; import store from "../stores"; export default { setup() { const state = reactive({ // The number of pages page: 1, // Tabular data news: [], // Filter bad list data by the value of search box newComputed: computed(() => { // Determine whether the input box has entered filter criteria. If it does not return the original news array if (store.state.searchValue) { return state.news.filter(item => { if (item.title.indexOf(store.state.searchValue) >= 0) { return item; } }); } else { return state.news; } }), searchValue: store.state }); // Send ajax request to get list data const loadMore = async () => { // Get list data let data = await axios.get("https://cnodejs.org/api/v1/topics", { params: { // Number of topics per page limit: 10, // The number of pages page: state.page } }); // Overlay pages state.page += 1; state.news = [...state.news, ...data.data.data]; }; onMounted(() => { // Trigger the request when the first screen is loaded loadMore(); }); return { // Keep data responsive ...toRefs(state), // See more events loadMore }; } }; </script>
lifecycle hooks
The life cycle hook of Vue3.0 is different from the previous version. The new version is registered with the onXxx() function, and the corresponding modules of the life cycle need to be introduced locally:
import { onMounted, onUpdated, onUnmounted } from "@vue/composition-api"; export default { setup() { const loadMore = () => {}; onMounted(() => { loadMore(); }); onUpdated(() => { console.log('updated!') }) onUnmounted(() => { console.log('unmounted!') }) return { loadMore }; } };
Here is a comparison of the life cycle of the new and old versions:
- <s>beforeCreate</s> -> use setup()
- <s>created</s> -> use setup()
- beforeMount -> onBeforeMount
- mounted -> onMounted
- beforeUpdate -> onBeforeUpdate
- updated -> onUpdated
- beforeDestroy -> onBeforeUnmount
- destroyed -> onUnmounted
- errorCaptured -> onErrorCaptured
At the same time, the new version also provides two new life cycles to help us debug code:
- onRenderTracked
- onRenderTriggered
In the Panel list component, we register the onMounted life cycle, and trigger the request method loadMore to get data from the back end to the data layer. Here we use the axios network request library, so we need to install the module:
npm install axios --save
It encapsulates a request list data method. The interface points to the API provided by the Cnode official website. Since axios returns Promise, it can perfectly write asynchronous logic with async and await, and then trigger it with the onMounted life cycle, and bind the method to the view more button in the view layer to complete the first load of the list and click to view more The lazy loading function of.
// Send ajax request to get list data const loadMore = async () => { // Get list data let data = await axios.get("https://cnodejs.org/api/v1/topics", { params: { // Number of topics per page limit: 10, // The number of pages page: state.page } }); // Overlay pages state.page += 1; // Merge list data state.news = [...state.news, ...data.data.data]; }; onMounted(() => { // Trigger the request when the first screen is loaded loadMore(); });
computed
Next, we will use another attribute computed to calculate the attribute, which is very similar to the way Vue2.0 is used. We also need to import the module as needed:
import { computed } from '@vue/composition-api';
There are two types of calculation attributes: read-only and read-write
// Read only calculated properties let newsComputed = computed(() => news.value + 1) // Readable and writable let newsComputed = computed({ // Value function get: () => news.value + 2, // Assignment function set: val => { news.value = news.value - 3 } })
Here we use the readable and writable calculation attributes to process the list data. Remember our last component Search.vue? We can combine the search value entered by the user in the search box with the calculated calculation attribute to filter the useful list data for our users. So we first get the searchValue shared by the Search.vue search box from the shared instance of the store After that, we use the original string method indexOf and array method filter to filter the list data, and then return the new list data news computed, and render the new list data with the v-for instruction on the view layer, so that we can return the original list data news when there is no search box retrieval value, and return the new list data n when there is search box retrieval value ewsComputed.
import store from "../stores"; export default { setup() { const state = reactive({ // Original list data news: [], // Filter the new list data by the value of search box newsComputed: computed(() => { // Determine whether the input box has entered filter criteria. If it does not return the original news array if (store.state.searchValue) { return state.news.filter(item => { if (item.title.indexOf(store.state.searchValue) >= 0) { return item; } }); } else { return state.news; } }), searchValue: store.state }); } }
Project source code
If the articles and notes can give you a little help or inspiration, please don't be stingy with your praise and Star, your affirmation is the biggest driving force for me to move forward