## 1\. Install vue-cli next
npm install --global @vue/cli@next
## 2\. When creating a project and creating a selection template, select "Manually select features", there are my options below, for reference only
vue create my-project-name
## If you already have a cli project is not TypeScript, cli can add a plug-
vue add typescript
My Vue CLI Option
Vue CLI v4.5.4
In 2.x, use the v-model equivalent binding on the assembly value
prop and input
events:
<child-component v-model="title" />
<!-- 语法糖 默认mode prop:value event:input-->
<child-component :value="title" @input="title = $event"/>
Using v-bind:sync
vue is a one-way data flow, in order to “two-way binding” props, it can be implemented with sync
<child-component :title.sync="title" />
<!-- 语法糖 -->
<child-component :title="title" @update:title="title = $event"/>
In the child component, the parent component is notified by the following method
this.$emit('update:title',value)
In 3.x, the custom component v-model
is passed modelValue
prop and accepts the thrown update:modelValue
event, which is very similar to sync
<child-component v-model="title" />
<!-- 语法糖 -->
<child-component :modelValue="title" @update:modelValue="title = $event"/>
v-model
If you need to change the parameter model
name, rather than a change in the assembly model
option, but a argument
pass tomodel
<child-component v-model:title="pageTitle" />
<!-- 简写: -->
<child-component :title="title" @update:title="title = $event" />
Therefore, we can directly change the 2.x sync to the current writing
<child-component :title.sync="title" />
<!-- 替换为 -->
<child-component v-model:title="title" />
And we can write multiple v-models for one subcomponent
<child-component v-model:title="pageTitle" v-model:content="content"/>
The change of v-for is mainly reflected in the key
above. When we use <template v-for>
it, the key value of the 2.x syntax cannot be added to the template
label, but must be added to the child node, and in 3.x, it can be added template
. And no need to add on the child nodekey
<!-- Vue 2.x -->
<template v-for="item in list">
<div :key="item.id">...</div>
...
</template>
<!-- Vue 3.x -->
<template v-for="item in list" :key="item.id">
<div>...</div>
<span>...</span>
</template>
In 2.0 v-for
, we bind ref in, and we $ref
get a ref array. In 3.x, the array will not be created automatically. We need to bind a function, process it and accept it ourselves
<div v-for="item in list" :ref="setItemRef"></div>
export default {
setup ( ) {
//itemRefs does not have to be an array: it can also be an object, and its ref will be set by the iterated key.
let itemRefs = [ ]
const setItemRef = el => {
itemRefs . push ( el )
}
return {
itemRefs ,
setItemRef
}
}
}
Finishing… (coming soon😄)
<template>
<div>
<p>Spaces Left: {{ spacesLeft }} out of {{ capacity }}</p>
<h2>Attending</h2>
<ul>
<li v-for="(name, index) in attending" :key="index">
{{ name }}
</li>
</ul>
<button @click="increaseCapacity()">Increase Capacity</button>
</div>
</template> <script>
// If using Vue 2 with Composition API plugin configured/ 在Vue2中使用 Composition API : import { ref, computed } from "@vue/composition-api";
import { ref, computed } from "vue";
export default {
setup() {
//Data responsive package data in objects to track changes
const capacity = ref ( 4 ) ;
const attending = ref ( [ "Tim" , "Bob" , "Joe" ] ) ;
//Computed property
const spacesLeft = computed ( ( ) => {
//Access the value of the responsive reference by calling .value
return capacity . Value - attending . Value . Length ;
} ) ;
// define method
function increaseCapacity ( ) {
//If you need to modify the variable if you want to modify the variable for the ref response type, you need to operate it
. value capacity . value ++ ;
}
// Make our template can access these objects and functions
return { capacity , attending , spacesLeft , increaseCapacity } ;
}
} ;
</ script >
import { reactive , computed , toRefs } from "vue" ;
export default {
setup ( ) {
//reactive accepts an object and returns a
reactive object const event = reactive ( {
capacity : 4 ,
attending : [ "Tim" , " Bob" , "Joe" ] ,
spacesLeft : computed ( ( ) => { return event .capacity - event . attending . length ; } )
} ) ;
function increaseCapacity ( ) {
// The reactive object returned by reactive does not need to use the value operation
event . capacity ++ ;
}
//...toRefs Deconstructs the object in the event , So that capacity or attending can be used directly in the template, without event.attending
return { ... toRefs ( event ) , increaseCapacity } ;
}
} ;
Finishing… (coming soon😄)
In setup, there is no way to get vue through this, we can get vue instance through getCurrentInstance
## By npm install
npm i vant@next -S
## By installing yarn
yarn add vant @ next
//vue.config.js
// eslint-disable-next-line @typescript-eslint/no-var-requires
const merge = require("webpack-merge");
// eslint-disable-next-line @typescript-eslint/no-var-requires
const tsImportPluginFactory = require("ts-import-plugin");
module.exports = {
chainWebpack: config => {
config.module
.rule("ts")
.use("ts-loader")
.tap(options => {
options = merge(options, {
transpileOnly: true,
getCustomTransformers: () => ({
before: [
tsImportPluginFactory({
libraryName: "vant",
libraryDirectory: "es",
style: true
})
]
}),
compilerOptions: {
module: "es2015"
}
});
return options;
});
}
};
## Installation depends
npm install postcss-px-to-
// vue.config.js
const pxtoviewport = require("postcss-px-to-viewport");
const autoprefixer = require("autoprefixer");
module . exports = {
css : {
loaderOptions : {
postcss : {
plugins : [
autoprefixer ( ) ,
pxtoviewport ( {
viewportWidth : 375 , // The width of the window corresponds to the width of our design draft, generally 750
minPixelValue : 1 , // Less than or equal to `1px` will not be converted to window units, you can also set to the value you want
unitPrecision : 3 , // Specify the number of decimal places for `px` to be converted to window unit values (not evenly divisible in many cases)
} )
]
}
}
}
}
Re-run, px changes to vw, ok✌~~
// plugins/vant.ts
import { App as VM } from "vue";
import { Button, List, Cell, Tabbar, TabbarItem } from "vant";
const plugins = [ Button , List , Cell , Tabbar , TabbarItem ] ;
export const vantPlugins = {
install: function(vm: VM) {
plugins.forEach(item => {
vm.component(item.name, item);
});
}
};
//main.ts use
import { createApp } from 'vue'
import { vantPlugins } from './plugins/vant'
createApp ( the App )
. . . // other configurations
. use ( vantPlugins )
. Mount ( '#app' )
//详见/src/theme/var.less
// Color Palette
@black: #000;
@white: #fff;
@gray-1: #f7f8fa;
@gray-2: #f2f3f5;
@gray-3: #ebedf0;
@gray-4: #dcdee0;
@gray-5: #c8c9cc;
@gray-6: #969799;
@gray-7: #646566;
@gray-8: #323233;
@red: #ee0a24;
@blue: #1989fa;
@orange: #ff976a;
@orange-dark: #ed6a0c;
@orange-light: #fffbe8;
@green: #07c160;
@green1:#4fc08d;
// Gradient Colors
@gradient-red: linear-gradient(to right, #ff6034, #ee0a24);
@gradient-orange: linear-gradient(to right, #ffd01e, ## ff8917 );
// Component C
//vue.config.js
module.exports = {
chainWebpack: config => {
config.module
.rule("ts")
.use("ts-loader")
.tap(options => {
options = merge(options, {
transpileOnly: true,
getCustomTransformers: () => ({
before: [
tsImportPluginFactory({
libraryName: "vant",
libraryDirectory: "es",
// --> 指定样式的路径
style: name => `${name}/style/less`
})
]
}),
compilerOptions: {
module: "es2015"
}
});
return options;
});
}
};
//vue.config.js
module.exports = {
...
css : {
loaderOptions : {
//Configure less theme
less : {
lessOptions : {
modifyVars : {
// Directly overwrite the variable
"text-color" : "#111" ,
"border-color" : "#eee" ,
// or It can be overwritten by less file (the file path is absolute)
hack : `true; @import "./src/theme/var.less";`
}
}
} ,
}
}
}
Reset the style sheet of the browser tabs. Because there are many types of browsers, the default styles of each browser are also different. For example, the button tabs have different styles in IE, Firefox, and Safari. So, by resetting the CSS properties of the button label, and then defining it uniformly, the same display effect can be produced. Before starting a project, create a reset.css, which can avoid many browser differences
/* http://meyerweb.com/eric/tools/css/reset/
v5.0.1 | 20191019
License: none (public domain)
*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, menu, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
main, menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, main, menu, nav, section {
display: block;
}
/* HTML5 hidden-attribute fix for newer browsers */
*[hidden] {
display: none;
}
body {
line-height: 1;
}
menu, ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
Pseudo-elements can also be used by default in most browsers. They are in the same form as pseudo-classes, and the compatibility of single-quotes (ie) is better. I use scss to write mixins. Others are similar to compilers.
/*单条border样式*/
@mixin border-1px ($color, $direction) {
position: relative;
border: none;
&::after{
content: '';
position: absolute;
background: $color;
@if $direction == left {
left: 0;
top: 0;
height: 100%;
width: 2px;
transform: scaleX(0.5);
transform-origin: left 0;
}
@if $direction == right {
right: 0;
top: 0;
height: 100%;
width: 2px;
transform: scaleX(0.5);
transform-origin: right 0;
}
@if $direction == bottom {
bottom: 0;
left: 0;
width: 100%;
height: 2px;
transform: scaleY(0.5);
transform-origin: 0 bottom;
}
@if $direction == top {
top: 0;
left: 0;
width: 100%;
height: 2px;
transform: scaleY(0.5);
transform-origin: 0 top;
}
}
}
/*四条border样式*/
@mixin all-border-1px ($color, $radius) {
position: relative;
border: none;
&::after{
content: '';
position: absolute;
top: 0;
left: 0;
border: 2px solid $color;
border-radius: $radius * 2;
-webkit-box-sizing: border-box;
box-sizing: border-box;
width: 200%;
height: 200%;
-webkit-transform: scale(0.5);
transform: scale(0.5);
-webkit-transform-origin: left top;
transform-origin: left top;
}
}
@import " @assets/style/mixin.scss " ; // import
.box {
@include all-border-1px ( #eeeeee , 0 ); // use
}
import { toRefs, reactive } from "vue";
import { useStore } from "vuex";
export default {
setup() {
const state = reactive({
name: ''
})
const store = useStore()
state.name = store.state.Name
return {
...toRefs(state)
}
}
};
Declared once, globally accessible, and the data that needs to be shared is declared in advance through provide in the root node of Vue App.vue. First create a store
// src/store/store.ts
const planList = Symbol()
export default {
planList,
}
Inject into outer components, such as provide in App.vue
// src/App.vue
<script lang="ts">
import Store from "./store/store"
import { defineComponent, provide, ref } from "@vue/composition-api"
export default defineComponent({
setup() {
provide(Store.planList, ref([]))
}
})
</script>
Inject acceptance within the required components
// src/views/Plan.vue
<script lang="ts">
import Store from "./store/store"
import { defineComponent, provide, ref } from "@vue/composition-api"
export default defineComponent({
setup() {
const planList = inject(Store.planList)
return {
planList
}
}
})
</script>
<router-view v-slot="{ Component }">
<keep-alive>
<component :is="Component" />
</keep-alive>
</router-view>
Set compileOnSave and sourceMap to false, if true, js and map files will be automatically generated when saving ts files
{
"compileOnSave": false,
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"experimentalDecorators": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"sourceMap": false,
"baseUrl": ".",
"types": [
"webpack-env"
],
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx"
],
"exclude": [
"node_modules"
]
}
module.exports = {
root: true,
env: {
node: true
},
extends: [
"plugin:vue/vue3-essential",
"eslint:recommended",
"@vue/typescript/recommended",
"@vue/prettier",
"@vue/prettier/@typescript-eslint"
],
parserOptions: {
ecmaVersion: 2020
},
rules: {
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off"
}
};
{
// By default, vscode enables the option to automatically set tabsize according to file type
" editor.detectIndentation " : false ,
// Reset tabsize
" editor.tabSize " : 2 ,
// #Automatically format every time you save
" editor .formatOnSave " : true ,
// #Fix the code in eslint format every time you save it
" eslint.autoFixOnSave " : true ,
// Add vue support
" eslint.validate " : [
" javascript ",
"javascriptreact",
{
"language": "vue",
"autoFix": true
}
],
// #Let prettier use eslint's code format for verification
" prettier.eslintIntegration " : true ,
// #Remove the semicolon at the end of the code
" prettier.semi " : false ,
// #Use quotes instead of double quotes
" prettier. singleQuote " : true ,
// #Add a space between the function (name) and the following parenthesis
" javascript.format.insertSpaceBeforeFunctionParenthesis " : true ,
// #This is selected according to the user's own habits
" vetur.format.defaultFormatter.html " : " js-beautify-html ",
// ## Let the js in vue format according to the ts format that comes with the editor
" vetur.format.defaultFormatter.js " : " vscode-typescript " ,
" vetur.format.defaultFormatterOptions " : {
" js-beautify- html " : {
" wrap_line_length " : 120 ,
" wrap_attributes " : " auto "
// #vue component html code formatting style
}
},
// format the stylus, to be installed's Manta Stylus Supremacy plug
" stylusSupremacy.insertColons " : false , // whether to insert a colon
" stylusSupremacy.insertSemicolons " : false , // whether to insert a semicolon
" stylusSupremacy.insertBraces " : false , // whether Insert braces
" stylusSupremacy.insertNewLineAroundImports " : false , // Whether to wrap after import
" stylusSupremacy.insertNewLineAroundBlocks " : false,
" explorer.confirmDelete " : false // Whether to wrap in the two selectors
}
Author: weizhanzhan
Demo: https://vue3-ts-template-h5.vercel.app/home
Source Code: https://github.com/weizhanzhan/vue3-ts-template-h5
#vue #vuejs #javascript