preface

I recently tried a combination of Vue and TS. I feel vue is not as angular2 friendly for TS, but I prefer TS between TS and JS. Es6 is a lot easier to use, so let me explain how to use TS +vue in detail. Ts +vue plugins will be much less, but certainly with vue support for TS plugins will also be more and more current project demo preview

The githubJQ plugin technical documentation will be updated continuously


Contents summary

  1. Vue CLI3 installation.
  2. Vue Config file configuration
  3. Set up the project structure file
  4. Use of routes
  5. Vue CLI startup and enabling Download TS vUe-supported plug-ins
  6. Use of TS AIXO
  7. Use of VUE X
  8. Image upload (batch upload) // Ts Element use
  9. Use of paging
  10. Rework the reassembly of buttons
  11. Rich text compiler

1. VueCLI 3.0

VueCLI 3.0 first installs Node. js on baidu

Installation:

Yarn NPM install -g@vue /cli # OR yarn global add @vue/cli #Copy the code

Create a project:

vue create my-project
# OR
vue ui
Copy the code

  1. The first is a template I created myself.
  2. The second one is the system default
  3. The third optional configuration

I’ve created one over here, so let’s pick the one in red

We choose this. Space bar is selected or not

Enter (default agreed)

Press Enter and select Package. json to see what ts we selected and then sass syntax check esl

Then press Enter to download the final CLI project. Wait patiently

Let’s download it

Enter the Vue UICopy the code

Welcome to Vue Li3.0 graphical interface, take your time and look at our project file structure

2. Configure vue config files


Here is the structure of our file

Node_modules // Node_modules // node_modules // node_modules // node_modules // node_modules // node_modules // node_modules // node_modules // Router // Route file shims-tx. D // Compatible with JSX Shims-vue. D // compatible with vue Store //vuex total file 4. pakeage.js // file (we can see all the dependencies in it, you can also download node_modules according to this) 5. We also lack a vue.config.js sibling to pakeage.jsCopy the code
A bonus for our party
// vue.config.js module.exports = {// options... // When using HTML5 history.pushState routing; // When building a multi-page application using the Pages option. BaseUrl :"", // Directory of production environment build files generated when vue-cli-service build is run. Note that the target directory is cleared before building (passing --no-clean at build time turns this behavior off). OutputDir :"webApp", // The directory where generated static resources (js, CSS, img, fonts) are placed (relative to outputDir). AssetsDir :"assets", // Specify the output path of the generated index.html (as opposed to outputDir). It could be an absolute path. IndexPath :"index.html", // By default, generated static resources include hash in their filename for better cache control. However, this also requires that the HTML for index be automatically generated by the Vue CLI. If you cannot use index HTML generated by the Vue CLI, you can turn off file name hashing by setting this option to false. FilenameHashing :true, // multi-page pages:undefined, // compile warning lintOnSave:false, // Whether to use the Vue build with the runtime compiler. Setting this to true allows you to use the template option in Vue components, but this will add an extra 10KB or so to your application. RuntimeCompiler :false, // by default babel-loader ignores all files in node_modules. If you want to explicitly translate a dependency through Babel, you can list it in this option. TranspileDependencies :[], // If you don't need the source map for production, set it to false to speed up production builds. ProductionSourceMap: false, / / set in the generated HTML < link rel = "stylesheet" > and < script > tag crossorigin attributes. Note that this option only affects tags injected by the HTML-webpack-plugin at build time - tags written directly into the template (public/index.html) are not affected. Crossorigin :undefined, // Enable Subresource Integrity (SRI) on the <link rel="stylesheet"> and <script> tags in the generated HTML. Enabling this option provides additional security if the files you build are deployed on a CDN. Note that this option only affects tags injected by the HTML-webpack-plugin at build time - tags written directly into the template (public/index.html) are not affected. Also, preload Resource Hints is disabled when SRI is enabled because of a bug in Chrome that causes files to be downloaded twice. Integrity :false, // Reverse proxy devServer:{// devServer:{// proxy: {// '/ API ': {// target: '1', // ws: true, // changeOrigin: true // } // } // } } }Copy the code

The basic project construction of VUE + TS is complete

3. Project construction

First look at a wave of completed project presentations (webstorminsidetsImport not supportedvueIt’s for all those with OCDvscodeSupport is better)

SRC // Current project assets // Static resources need to be packaged BeforeUpload // Single image upload component (Element based) Pagination // pagination plugin (Element based) reset // Reset button component tinyMceEditor / / rich text compiler (this is the key of ts support vue plug-in for we reached the party less current) uploadListImg / / batch image upload (element) based verification form validation/utils / / the current project public views HaveNot //404 page Layout // Project structure layout login // The current project login page Method // Static iteration store of current project vuex store of current project (don't use it for vuex, Typings //ts uses utils // to store other files (I have cookie files) app.vue // global routing page main.ts // to start js D // supports JSX shims-vue.d // supports vue vue-config //vue configuration vue-shimm.d. ts // Declare global methods (ts automatically fetching.d.ts files)Copy the code

Component components will be explained one by one, public methods will also be explained, first to download the current needs of the TS plug-in

Aixo 2. element 3. js-cookieCopy the code

Take a look at package.js and you can see that we are currently using dependencies

Then we go to download the current to dependency


Welfare article

How do you see if plug-ins can be used currently up tovue + tsProject (current)ts+vueStill less)TypeSearch

If you can search as shown below, you can judge that ts is supported


Download the current project dependencies

We open the current graphics management toolSelect and download (also download the currentts) That’s how you get the wholeaixoDownload well (all other plug-ins need to download 2)

The second is mainly innode_modulesThe inside of the@typesDefine it once before you can use itRouting page andvuePages don’t differ that much main.jsThere’s not much difference

app.vuefile

So let’s talk about thisvue-property-decoratorOtherwise the kids are going to have a hard time understanding this

@prop ({type: String, default: 'default Value'}) MSG: String; @model ('change') checked: Boolean @watch ('$route') onRouteChanged(route: any, oldRoute: Any) :void {this.$forceUpdate() ## refresh the current data} @provide / @inject ## parent @provide ('users') users = [{name: 'test', id: 0}] ## Inject('users') users; Const Log = (MSG) => {return createDecorator((component, key) => {console. Log ("# component ", component); console.log("#Key", key); //log console.log("#Msg", msg); //App }) } @Log('fullMessage get called') get fullMessage() { return `${this.message} from Typescript` }Copy the code

Check out the uE-property-decorator file in the decorator section, because I’m a bit of a fool.

Our project is generally inlayoutTake a look at this file in the folder

Layout Content appmain.vue // Current file for our main route index.ts // navbar.vue // Left navigation of current project newtab.vue // components defined by Prompt,vue // Layout. Vue // Total project file style. SCSS // CSS for current projectCopy the code

Look what we’ve introduced is a folder that will automatically get the index.ts and write es6 in index.ts

## 解 决 方 法ES6 (iF you have time, you can look at ES6) ## 解 决 方 法 {Navbar: Navbar, AppMain: AppMain, Prompt: Prompt} ##Copy the code

2.elementThe introduction of

1. Install dependencies first

2. The introduction of CSS

<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
Copy the code

3. Main. ts introduces the global

4. It’s ready to use

Copy and paste the code for Element

http://element.eleme.io/#/zh-CN/component/time-picker
Copy the code

It must be used on our sidepublicCommon variables, don’t use thatprivatePrivate variables (the following variables will not be found in the HTML above, although this does not give an error)

5. Rendering

3.aixoThe use of (ajax)

Graphical interface to download two one is used for compatibilitytstheEnclose the packageajaxcode

import Axios from 'axios';
import { Message } from 'element-ui';
import { getToken } from '@/views/utils/auth'; // token 不需要可以不要

const httpServer = (opts: any) => {
        const httpDefaultOpts = { // http默认配置
            method: opts.method,
            baseURL: 'https://xxxx.com',  // 测试
            url: opts.url,
            timeout: 100000,
            params: opts.params,
            data: opts.params,
            headers: opts.method == 'get' ? {
            'X-Requested-With': 'XMLHttpRequest',
            'Accept': 'application/json',
            'Content-Type': 'application/json; charset=UTF-8',
            'systoken': '',
            } : {
            'Content-Type': 'application/json;charset=UTF-8' ,
            'systoken': '',
            },
    };
        if (getToken()) {
        const token: any = getToken();
        httpDefaultOpts.headers.systoken = token;
    }
        if (opts.method == 'get') {
        delete httpDefaultOpts.data;
    } else {
        delete httpDefaultOpts.params;
    }
        const promise = new Promise(function(resolve, reject) {
        Axios(httpDefaultOpts).then(
        (res) => {
            if (res.data.code == -3) {
                resolve(res.data);
            } else {
                resolve(res.data);
            }
        },
        ).catch(
        (response) => {
            reject(response);
        },
        );
    });
        return promise;
};

export default httpServer;

Copy the code
import Http from '@/views/aixo/http'; / * * * total system character menu | according to the user ID for the character's menu * @ param userId user ID * / export const managxxxMenuUserId = (userId: any) => { return Http({ url: `/xxx/${userId}`, method: 'post', }); };Copy the code

use

1. The use of vueX

First we go to the GUI interface to download the current need to dependency (version number and axios need to be consistent do not know can go to usThe first chapterTake a look atFirst build 4 files, I a file a file to speak, the audience master patience

1.stateDocuments (do not understand can see firstvuexwebsite)

Here we put global variables in it (just to say that vuex is not used for vuex purposes, some items can not be used at all, of course not)

import { getToken, setToken, removeToken } from '@/views/utils/auth'
const state: any = {
    token: getToken(),
    imgUrl: 'https://api.uat.iyuedian.com/iyd-imall-manage/imall/v1/upload'
}
export default state
Copy the code

2.mutationsfile

So this file is submitted to change the value of the current state if you don’t know interface look at mooC

Export default mutations{## old method SET_TOKEN(state: any, data: any) { state.token = data }, } import {MutationTree} from 'vuex' ## mutations MutationTree<any> = { 'SET_TOKEN'( state: any, data: any ): void { state.token = data } }Copy the code

Vuex inside the source can be looked at

3.actionsfile

This file can perform the methods in the mutations file and any common methods can be placed in this file. Async defines a one-step function and always returns the actual value that is always a Promise object

import { sysUserLogin } from '@/views/interface/login'; import { getToken, setToken, removeToken } from '@/views/utils/auth'; import { ActionTree } from 'vuex'; import { Message } from 'element-ui'; const actions: ActionTree<any, any> = {/** * Login * @param param0 * @param userInfo Login information */ async Login({state, commit}, userInfo: any) { return new Promise((resolve, reject) => { sysUserLogin(userInfo).then((response: any) => { setToken(response.data.systoken); console.log(response.data.systoken); commit('SET_TOKEN', response.data.systoken); ## resolve(response); }).catch((error) => { reject(error); }); }); }, /** * deep copy * @param param0 * @param params */ async deep({state, commit}, params: any) {let obj = {}; obj = JSON.parse(JSON.stringify(params)); return obj; }}; export default actions;Copy the code

4.gettersfile

Getters can be defined as a store computed property that filters state and then returns it

Open mutations import {GetterTree} from 'vuex' const mutations: open mutations import {vuex} from 'vuex' const mutations: GetterTree<any,any> = { 'token'( state: any, ): any { return state.token } } export default mutationsCopy the code

vuexusevuex-class

@state imgUrl @action ('Login') Login; @Getter('Login') getterFoo; @Mutation('Login') mutationFoo; @state foo @getter bar @action baz @mutation qux created() {## console.log(this.imgurl); // -> this.store.state.imgUrl console.log(this.getterFoo(2)) // -> this.store.getters.Login this.Login({ value: true }).then() // -> this.store.dispatch('Login', { value: true }) this.mutationFoo({ value: true }) // -> this.store.commit('Login', { value: true }) }Copy the code

2. Photo uploads (and bulk photo uploads

Here we use the image of Element to upload. If you don’t understand, you can take a look at element components

Single picture upload

We want a better and easier way to use it

<template> <div> <el-upload class="avatar-uploader" :action="$store.state.imgurl "## :show-file-list="false" :on-success="handleAvatarSuccess" :before-upload="beforeAvatarUpload"> <img v-if="BeforeUploadImg" :src="BeforeUploadImg" class="avatar"> <i v-else class="el-icon-plus avatar-uploader-icon"></i> </el-upload> </div> </template> <script lang="ts"> import { Component, Vue, Model, Watch, Prop } from 'vue-property-decorator'; @component export default class BeforeUpload extends Vue {## initial @prop (String)BeforeUploadImg: String; Created ():void {} public handleAvatarSuccess(res:any, file:any) {## $emit('update:BeforeUploadImg',res.data[0].newfilename); } public beforeAvatarUpload(file:any) { // const isJPG = file.type === 'image/jpeg'; const isLt2M = file.size / 1024 / 1024 < 2; // if (! IsJPG) {// this.$message.error(' Upload avatar image only JPG format! '); // } if (! IsLt2M) {this.$message.error(' Upload avatar image size cannot exceed 2MB! '); } // return isJPG && isLt2M; return isLt2M; <BeforeUpload: beforeuploadimg. sync="BeforeUploadImg"></BeforeUpload>  # script import BeforeUpload from '@/components/beforeUpload/beforeUpload.vue'; import { Component, Vue, Model, Watch, Prop } from 'vue-property-decorator'; @Component({ components: {BeforeUpload,}}) export default class extends Vue {## public BeforeUploadImg: string = ''; }Copy the code

Batch image upload

We want a better and easier way to use it

<template> <div> <el-upload class="upload-demo" :action="$store.state.imgurl ":on-preview="handlePreview" :on-success="handleOnSuccess" :on-remove="handleRemove" :file-list="UploadListsImg" list-type="picture"> <el-button Size ="small" type="primary"> </el-button> <div slot="tip" class="el-upload__tip"> </div> </el-upload> </div> </template> <script lang="ts"> import {Component, Vue, Model, Watch, Prop } from 'vue-property-decorator'; @Component export default class UploadListImg extends Vue {// initial value @Prop(null)UploadListsImg:object[]; Created ():void {// tinymce.init ({})} /** * delete image * @param file delete image * @param fileList Delete image */ public handleRemove(file:any, fileList:any) { console.log(file, fileList); this.$emit('update:UploadListsImg',fileList) this.$emit('removeListImg',file) } public handlePreview(file:any) { console.log(file); } /** * add picture * @param Response return value * @param file current picture * @param fileList Current picture */ public handleOnSuccess(response:any, file:any, fileList:any){ file.url = response.data[0].newFileName; file.name = response.data[0].originalFilename; This.$emit('update:UploadListsImg',fileList)}} </script> ## HTML UploadListsImg is a list of images to be removed <UploadListImg: uploadListsimg. sync="UploadListsImg" @removelistimg ="removeListImg" style="width: 400px"></UploadListImg> ## script import UploadListImg from '@/components/uploadListImg/uploadListImg.vue'; import { Component, Vue, Model, Watch, Prop } from 'vue-property-decorator'; @Component({ components: { UploadListImg, } }) export default class Content extends Vue { public UploadListsImg: object[] = [ { name: 'food.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/qualit y/100' }, { name: 'food2.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/qualit y/100' } ]; public removeListImg: object[] = [] }Copy the code

3. Use of pagination

Paging is something we want to use more easily

<style scoped lang=" SCSS ">. T-pagination {width: 100%; overflow: hidden; } .t-pagination-content{ float: right; margin: 20px; } </style> <template> <div class="t-pagination"> <div class="t-pagination-content"> <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="currentPage4" :page-sizes="[10, 20, 30, 40, 100]" :page-size="pageSize" layout="total, sizes, prev, pager, next, jumper" :total="Paginationtotal"> </el-pagination> </div> </div> </template> <script lang="ts"> import Utils from '@/utils/utils' import { Component, Vue, Model, Prop, Watch } from 'vue-property-decorator'; @component export Default class Reset extends Vue {// props declaration @prop () private Paginationtotal! : number; private pageSize:number = 20; private currentPage4:number = 1; Created ():void {if (this.$route.query.pagenum) {this.CurrentPage4 = Number(Utils.deep(this.$route.query.pageNum)); this.pageSize = Number(Utils.deep(this.$route.query.pageSize)); }else { this.currentPage4 = 1; this.pageSize = 20; }} @watch ('$route') onRouteChanged(route: any, oldRoute: any) :void { if (route.query.pageNum) { this.currentPage4 = Number(Utils.deep(route.query.pageNum)) this.pageSize = Number(Utils.deep(route.query.pageSize)); }else { this.currentPage4 = 1; this.pageSize = 20; } private handleSizeChange(val:any) {let data:any = utils.deep (this.$route.query); [data. PageNum, data. PageSize] = [1, val] this. Start the console (data). The log (` each page ${val} re `); } private handleCurrentChange(val:any) { let data:any = Utils.deep(this.$route.query); Data.pagenum = val data.pagesize = this.pagesize this.start(data) console.log(' current page: ${val}re '); } private start(ret:any) { this.$store.dispatch('paramsUrl',ret).then((res:any) => { This.$route. push(' ${this.$route.path}${res} ')})}} </script> # HTML :Paginationtotal="Paginationtotal"></Pagination> # script import Pagination from '@/components/pagination/pagination.vue'; import { Component, Vue, Model, Watch, Provide } from 'vue-property-decorator'; @Component({ components: { Pagination } }) export default class Content extends Vue { Paginationtotal:number = 0; }Copy the code

4. Reassemble the buttons

All we need to do is reset the current page to the first page with 20 hops

<template> <el-button size="mini" @click="reset(searchReserved)"> reset </el-button> </template> <script lang="ts"> import { Component, Vue, Model, Prop } from 'vue-property-decorator'; @Component({}) export default class Reset extends Vue {// props declares paramsUrl as a defined method in the current vuEX @prop () private searchReserved! : object public reset (search: any) {/ search. PageNum, search. PageSize = [1] this.$store.dispatch('paramsUrl',search).then((res:any) => { this.$router.push(`${this.$route.path}${res}`) }) } } </script> ## HTML Usage <Reset :searchReserved="searchReserved"></Reset> ## script import Reset from '@/components/reset/reset.vue'; @Component({ components: { Reset } }) export default class Content extends Vue { searchReserved = {} }Copy the code

5. Rich text compiler

Rich text compilers, I think you should be familiar with, I recommend a baskettinyMceTo use the rich text compiler we are currently using in the projecttsAll support is not much, I found a lot to try, finally decided to usetinyMceDownload these two, with a lot of holes in the middle, and give us the code for out-of-the-box onlineIt’s faster to put the CDN on

It’s important to say that our static file is going to go under public and this one has to go in there, and this one has to go in there otherwise the page won’t eatThe file link

FormData <template> <div> <Editor :initial-value="EditorContent" @onChange="onChangeHandler" id="tinyMce" :init="editorInit"></Editor> </div> </template> <script lang="ts"> import 'tinymce/themes/modern/theme'; import Editor from '@tinymce/tinymce-vue'; import { Component, Vue, Model, Watch, Prop } from 'vue-property-decorator'; @Component({ components: {Editor}}) export default class Content extends Vue {HTML @prop (String) EditorContent: any; Public initialVal:any = "; public editorInit:any = { language_url: './static/zh_CN.js', language: 'zh_CN', selector: 'textarea', skin_url: './static/skins/lightgray', height: 300, // width:600, images_upload_url: 'https://api.uat.iyuedian.com/iyd-imall-manage/imall/v1/upload', plugins: 'link lists image code table colorpicker textcolor wordcount contextmenu', toolbar: 'bold italic underline strikethrough | fontsizeselect | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist | outdent indent blockquote | undo redo | link unlink image code | removeformat', images_upload_handler: function (blobInfo:any, success:any, failure:any) { let xhr:any, formData:any; xhr = new XMLHttpRequest(); xhr.withCredentials = false; xhr.open('POST', this.$store.state.imgUrl); xhr.onload = function() { if(xhr.status<200||xhr.status>=300){ failure(xhr.status); return; } let json = JSON.parse(xhr.responseText); if(json.code==0){ success(json.data[0].newFileName); } else { failure('HTTP Error: ' + json.msg); }}; formData = new FormData(); formData.append('file', blobInfo.blob(), blobInfo.filename()); xhr.send(formData); }, // images_upload_url: 'https://api.iyuedian.com/iyd-imall-manage/imall/v1/upload'} / / perform first created () : void {/ / tinyMce init ({})} / / monitor routing change @Watch('$route') onRouteChanged(route: any, oldRoute: Any) : void {enclosing $forceUpdate ()} / * * * * / rich text content change events public onChangeHandler (res: any, index: any tag: any) {/ / width Height small program does not support the replacing the let the HTML = res. Level. The content. the replace (" width ", "XXX") HTML = HTML. Replace (" height ", "yyy") / / Console. log(HTML) this.$emit('update:EditorContent', HTML)}} </script> ## HTML usage <Editor :EditorContent.sync="EditorContent"></Editor> ## script import Editor from '@/components/tinyMceEditor/tinyMceEditor.vue'; @Component({components: {Editor}}) export default class extends Vue { string = ''; }Copy the code

1.

use

summary

Basic plug-ins are about a problem can be added to the ABOVE QQ group

Seek to rely on the spectrum push (Beijing area) can leave a message I +. =