2020=-9-14,项目打包部署、图表、服务器端渲染、typescript

符国安
2023-12-01

内容:项目打包部署、图表、服务器端渲染、typescript

日期:2020-09-14`

一、项目打包部署

1.打包

npm run build

2.部署

(1)备份本地数据文件,然后在服务器上创建一个数据库,并导入已备份的数据库

(2)将接口项目上传到服务器,然后通过pm2把接口项目运行起来

(3)代理配置

把打包好的项目文件上传到服务器上,并配置域名进行解析

如果线上服务器用的是nginx,需要进行nginx代理转发配置,从而实现请求线上的接口地址。

nginx的网站配置文件中添加如下代理规则:

location ^~/uploads{
	proxy_pass http://服务器域名或ip地址:端口;
}
location /api/{
	proxy_pass http://服务器域名或ip地址:端口; 
}

二、图表

1.highcharts

官网:https://www.highcharts.com.cn/

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="http://cdn.highcharts.com.cn/highcharts/highcharts.js"></script>
</head>
<body>
    <div id="container" style="width: 600px;height:400px;"></div>
    <script>
        // 图表配置
        var options = {
            chart: {
                type: 'bar'                          //指定图表的类型,默认是折线图(line)
            },
            title: {
                text: '我的第一个图表'                 // 标题
            },
            xAxis: {
                categories: ['苹果', '香蕉', '橙子']   // x 轴分类
            },
            yAxis: {
                title: {
                    text: '吃水果个数'                // y 轴标题
                }
            },
            series: [{                              // 数据列
                name: '小明',                        // 数据列名
                data: [1, 0, 4]                     // 数据
            }, {
                name: '小红',
                data: [5, 7, 3]
            }]
        };
        // 图表初始化函数
        var chart = Highcharts.chart('container', options);
    </script>
</body>
</html>

2.echarts

官网:https://echarts.apache.org/

引入:https://cdn.jsdelivr.net/npm/echarts@4.9.0/dist/echarts.js

在vue中使用

安装echarts

npm i echarts --save

在页面组件中引入并使用

<template>
    <div>
        <div id="main" style="width: 600px;height:400px;"></div>
    </div>
</template>

<script>
import echarts from "echarts";
export default {
    data() {
        return {
            myChart: null
        };
    },
    mounted() {
        this.myChart = echarts.init(document.getElementById("main"));
        var option = {
            title: {
                text: "本周订单数量"
            },
            tooltip: {},
            legend: {
                data: ["数量"]
            },
            xAxis: {
                data: ["周一","周二","周三","周四","周五","周六","周日"]
            },
            yAxis: {},
            series: [
                {
                    name: "数量",
                    type: "line",
                    data: [5, 20, 36, 10, 66, 10, 20]
                }
            ]
        };
        // 使用刚指定的配置项和数据显示图表。
        this.myChart.setOption(option);
    }
};
</script>

<style></style>

3.百度地图

百度开放平台网址:http://lbsyun.baidu.com/

(1)注册成为开发者

(2)创建应用并获取秘钥

(3)在页面中使用

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script type="text/javascript" src="http://api.map.baidu.com/api?v=1.0&type=webgl&ak=你的秘钥"></script>
    <style type="text/css">
        html {
            height: 100%
        }

        body {
            height: 100%;
            margin: 0px;
            padding: 0px
        }

        #container {
            height: 100%
        }
    </style>
</head>

<body>
    <div id="container"></div>
    <script>
        var map = new BMapGL.Map("container"); // 创建地图实例 
        var point = new BMapGL.Point(113.634821,34.736549); // 创建点坐标 
        map.centerAndZoom(point, 15); // 初始化地图,设置中心点坐标和地图级别
        map.enableScrollWheelZoom(true);     //开启鼠标滚轮缩放\
        map.setMapType(BMAP_EARTH_MAP);      // 设置地图类型为地球模式
    </script>
</body>

</html>

三、服务器端渲染

1.ssr

(1)什么是服务端渲染 SSR

​ Vue.js 是构建客户端应用程序的框架。默认情况下,可以在浏览器中输出 Vue 组件,进行生成 DOM 和操作 DOM。然而,也可以将同一个组件渲染为服务器端的 HTML 字符串,将它们直接发送到浏览器,最后将这些静态标记"激活"为客户端上完全可交互的应用程序。

(2)为什么要使用服务端渲染

优势:

​ 更好的SEO优化

​ 渲染速度快

缺陷:

​ 开发条件受限,vue的某些生命周期钩子函数无法使用

​ 部署和构建有要求,在node环境下运行

​ 更多的服务器端负载

ssr本质就是将vue的语法功能延伸到服务器端,在服务器端渲染好节点内容,给客户端浏览器去编译。

(3)代码实现

创建一个文件,并进入到命令行中

(1)初始化node环境

npm init -y

(2)安装vue和ssr

npm i vue vue-server-renderer --save

(3)将vue模板内容编译成字符串

const Vue = require('Vue')
//实例化vue
const app = new Vue({
    data:{
        msg:'vue ssr 学习'
    },
    template:'<div>hello,{{ msg }}</div>'
})
//引入ssr
const renderer = require('vue-server-renderer').createRenderer();

renderer.renderToString(app,(err,html)=>{
    if(err) throw err;
    console.log(html)
})

(4)启动一个服务器,并展示编译后的字符串

const Vue = require('Vue')
const express = require('express')
const server = express();
//实例化vue
const app = new Vue({
    data:{
        msg:'vue ssr 学习'
    },
    template:'<div>hello,{{ msg }}</div>'
})
//引入ssr
const renderer = require('vue-server-renderer').createRenderer();

server.get('/index',(req,res)=>{
    renderer.renderToString(app,(err,html)=>{
        if(err) throw err;
        res.end(html)
    })
})

server.listen(3000,()=>{
    console.log('服务器运行在3000端口....')
})

(5)结合html文件和模板语法来实现ssr

const Vue = require('Vue')
const express = require('express')
const server = express();
const fs = require('fs')
//实例化vue
const app = new Vue({
    data:{
        msg:'vue ssr 学习'
    },
    template:'<div>hello,{{ msg }}</div>'
})
//引入ssr
const renderer = require('vue-server-renderer').createRenderer({
    template:fs.readFileSync('./index.html','utf-8')
});
let htmldata = {
    title:'vue-ssr服务端渲染-标题'
}
server.get('/index',(req,res)=>{
    renderer.renderToString(app,htmldata,(err,html)=>{
        if(err) throw err;
        res.end(html)
    })
})

server.listen(3000,()=>{
    console.log('服务器运行在3000端口....')
})

index.html内容

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{ title  }}</title>
</head>
<body>
    <!--vue-ssr-outlet-->
</body>
</html>

在index.html中一定要有 占位符,否则无法把内容展示在html中。

2.nuxt.js脚手架

(1)安装

npm i npx -g
npm i create-nuxt-app -g

(2)初始化项目

npx create-nuxt-app 项目名称
? Project name nuxtdemo
? Project description My superior Nuxt.js project
? Author name ming
? Choose the package manager Npm
? Choose UI framework None
? Choose custom server framework None (Recommended)
? Choose Nuxt.js modules Axios
? Choose linting tools Prettier
? Choose test framework None
? Choose rendering mode
> Universal (SSR)
Choose development tools jsconfig.json (Recommended for VS Code)

(3)运行项目

npm run dev

三、Typescript

官网:https://www.tslang.cn/

1.介绍

Typescript是Javascript的超集,由微软开发和开源。

通俗的理解为Javascript的一个特殊版本,其语法规范严谨,适用于开发大型项目。

2.搭建环境

(1)安装

npm i typescript -g

验证是否安装成功

tsc -v

(2)编译

①手动编译

创建一个index.ts,并在其中写一行普通的js代码

在命令行中,进入到指定的目录,执行命令tsc index.ts进行编译,在同级目录下会生成一个同名的js文件。

(2)自动编译(vscode)

生成ts配置文件

tsc --init

此时,就会在指定的目录下生成一个tsconfig.json的配置

{
"compilerOptions": {
    /* 基本选项 */
    "target": "es5",// 指定 ECMAScript 目标版本: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'
    "module": "commonjs",// 指定使用模块: 'commonjs', 'amd', 'system', 'umd' or 'es2015'
    "lib": [],// 指定要包含在编译中的库文件
    "allowJs": true,//允许编译 javascript 文件
    "checkJs": true,//报告javascript文件中的错误
    "jsx": "preserve",//指定jsx代码的生成: 'preserve', 'react-native', or 'react'
    "declaration": true,//生成相应的 '.d.ts' 文件
    "sourceMap": true, //生成相应的 '.map' 文件
    "outFile": "./",//将输出文件合并为一个文件
    "outDir": "./",//指定输出目录
    "rootDir": "./",//用来控制输出目录结构 --outDir.
    "removeComments": true,//删除编译后的所有的注释
    "noEmit": true,//不生成输出文件
    "importHelpers": true,//从tslib导入辅助工具函数
    "isolatedModules": true,//将每个文件做为单独的模块(与 'ts.transpileModule' 类似).
    /* 严格的类型检查选项 */
    "strict": true,//启用所有严格类型检查选项
    "noImplicitAny": true,//在表达式和声明上有隐含的any类型时报错
    "strictNullChecks": true,//启用严格的null检查
    "noImplicitThis": true,//当this表达式值为 any 类型的时候,生成一个错误
    "alwaysStrict": true,//以严格模式检查每个模块,并在每个文件里加入 'use strict'
    /* 额外的检查 */
    "noUnusedLocals": true,//有未使用的变量时,抛出错误
    "noUnusedParameters": true,//有未使用的参数时,抛出错误
    "noImplicitReturns": true,//并不是所有函数里的代码都有返回值时,抛出错误
    "noFallthroughCasesInSwitch": true,//报告switch语句的fallthrough错误。
    /* 模块解析选项 */
    "moduleResolution": "node",//选择模块解析策略:'node' (Node.js) or 'classic' (TypeScript pre-1.6)
    "baseUrl": "./",//用于解析非相对模块名称的基目录
    "paths": {},//模块名到基于 baseUrl 的路径映射的列表
    "rootDirs": [],//根文件夹列表,其组合内容表示项目运行时的结构内容
    "typeRoots": [],//包含类型声明的文件列表
    "types": [],//需要包含的类型声明文件名列表
    "allowSyntheticDefaultImports": true, //允许从没有设置默认导出的模块中默认导入。
    /* Source Map Options */
    "sourceRoot": "./",//指定调试器应该找到 TypeScript 文件而不是源文件的位置
    "mapRoot": "./",//指定调试器应该找到映射文件而不是生成文件的位置
    "inlineSourceMap": true,//生成单个 soucemaps 文件,而不是将 sourcemaps 生成不同的文件
    "inlineSources": true,//将代码与 sourcemaps 生成到一个文件中,要求同时设置了 --inlineSourceMap 或 --sourceMap 属性
    /* 其他选项 */
    "experimentalDecorators": true,//启用装饰器
    "emitDecoratorMetadata": true//为装饰器提供元数据的支持
  }
}

修改配置文件,“outDir”: "./"注释解开,具体目录地址可以自行设置

编写index.ts文件的内容

vscode 工具栏 > 终端 > 运行生成任务 > tsc:监视-tsconfig.json

这样,在index.ts文件,编写了内容,就会自动生成对应的js文件。

在根目录下创建一个index.html,并引入生成好的js文件

3.声明变量和数据类型

ts最大的特点就是进行严谨的数据类型验证,要求我们在声明一个变量时就定义好该变量的数据类型,且赋值的内容必须对应的数据类型保持一致。

(1)声明变量

语法格式:

var 变量名:数据类型名称;
var 变量名:数据类型名称 = 内容;

(2)数据类型

String、Number、Boolean、Function、Object、Array

在ts中定义数组

let 变量名 : Array<数组元素数据类型>;

示例代码:

// 原生js
// let arr = []
// let arr = new Array();
// ts方式
let arr : Array<String>;
// arr[0] = true;//如果给数组元素赋值了错误的数据类型,此时会出现警告

新增的数据类型:

①元组

语法格式:

let 变量名: [ 第一个元素的数据类型, 第N个元素的数据类型] = [ 元素1,元素N ]

此时元素的数据类型必须和设置好数据类型保持一致

②枚举

语法格式:

enum 变量名 { 值1,值N }

示例代码:

enum orderStatus { '已下单' = 1,'已发货','已收货' }
console.log(orderStatus.已收货)//会返回此内容在枚举中的索引位置

③any

// any 任意类型(不明确变量类型时),此时对res变量的赋值就和原生js没有区别了
let res : any;
res = 'hello'
res = 100
res = true

④void

void 一般用于函数,表示函数无返回值

⑤never

never类型表示的是那些永不存在的值的类型。

function error(message: string): never {
    throw new Error(message);
}

4.函数

ts中的函数相关知识和es6有很多相同之处

(1)函数定义

在ts中,定义一个函数,需要定义函数的返回值类型,如果没有返回值则类型为void,如果函数有参数的话,需要给参数也指定数据类型

格式:

function 函数名([参数名:参数的数据类型]):函数返回值的数据类型{...}

示例代码:

function getMsg():String{
	//return true;//此时函数的返回值应该是String,不能是其他类型
	return 'msg';
}

(2)函数参数

ts里的每个函数参数都是必须的

①默认参数

function checkPhone(phone:Number = 111111):Boolean{
     console.log(phone);
     return true;
}

②可选参数

可选的参数如果没有传递,在函数中仍然用到了这个参数,则它的值是undefined

function checkLogin(username:string,password?:string):Boolean{
    console.log(username)
    console.log(password)
    return true;
}

③剩余参数

替代传统的函数的arguments的作用

剩余参数需要是所有参数中的最后一位,不然就做不到剩余。

function getStr(str1:string,...str2:Array<any>){
    console.log(str1)
    console.log(str2)
}
getStr('小明',100,200,'500',888)

5.接口

如果传递的参数数量比较多或者是一个对象,那么这个函数的参数校验规则就无法实现校验

接口(interface)是类中的一个很重要的概念,它是对行为的抽象,而具体如何实现需要由类(class)去实现(implements)

接口定义

interface Person{
    name:String,
    age:Number
}
var p1 : Person;
p1 = {
    name:'小王',
    age:18
}

6.装饰器【重点】

装饰器是一种特殊的类型声明,它可以被附加类、方法、属性、参数上面,可以修改类的行为。

装饰器就是一个方法或者说是一个特殊函数,可以被注入到类、方法、属性、参数上。

装饰器分类:类装饰器、属性装饰器、方法装饰器、参数装饰器

装饰器也是es7的标准特性之一。

(1)类装饰器

类装饰器是在声明类之前(紧靠类的声明处),类装饰器应用于类的构造函数,可以监视、修改或者替换类定义。

①普通装饰器

声明装饰器:

function logClass(target:any):void{
    console.log(target)
    target.prototype.url = 'www.baidu.com'
}

调用装饰器:

@logClass //调用装饰器
class Animal{
    type:string = ''
}

在声明类之前,通过@装饰器名称来调用装饰器

②装饰器工厂(可以传递参数)

声明装饰器:

function logClass(params:any){
    return function(target:any){
        target.prototype.name = params;
    }
}

调用装饰器:

@logClass('汗血宝马') //调用装饰器并传递参数
class Animal{
    type:string = ''
}

(2)属性装饰器

声明装饰器

function logProperty(target:any,propertyName:string):void{
    console.log(target,111111111)
    console.log(propertyName,222222)
}

调用装饰器

class Animal{
    @logProperty
    type:string = ''
}

(3)方法装饰器

它可以被运用到方法的属性描述上,可以用来监视、修改、替换方法定义

运行时,需要传递三个参数

(1)对于静态类成员来说是类的构造函数,对于实例成员来说是类的原型对象

(2)成员(属性)的名字

(3)成员的属性描述

定义方法装饰器

function logAction(target:any,methodName:string,desc:any):void{
    console.log(target,1111111)
    console.log(methodName,22222)
    console.log(desc,33333)
}

使用方法装饰器

class Animal{
    type:string = ''
    @logAction
    run():void{
        console.log('running....')
    }
}

(4)参数装饰器

运行时会被当做函数调用,可以使用参数装饰器为类的原型增加一些元素数据,传入三个参数

(1)对于静态类成员来说是类的构造函数,对于实例成员来说是类的原型对象

(2)方法名字

(3)参数在函数参数列表中的索引

定义装饰器

function logParams(target:any,methodName:string,paramIndex:number):void{
    console.log(target,111111111)
    console.log(methodName,2222222)
    console.log(paramIndex,33333333)
}

使用装饰器

class Animal{
    type:string = ''
    run(n,@logParams m:number):void{
        console.log(m)
    }
}

四、新脚手架结合ts进行开发

1.定义class组件

创建一个页面组件,修改script代码

<script lang="ts">//lang=ts 表示使用ts语法
//引入类装饰器Component和Vue类
import { Component,Vue } from 'vue-property-decorator'
@Component({})
export default class Home extends Vue{
    
}
</script>

2.新语法

我们在定义data、生命周期、计算属性、事件方法、数据监听、组件引入都有一定的变化

在class组件中没有了data、methods

(1)定义初始变量

export default class Home extends Vue{
    str : string = "超级天王"//定义初始变量
}

(2)定义方法

export default class Home extends Vue{
    str : string = "超级天王"//定义初始变量
    changeStr():void{
        this.str = "中原一点红"
    }
}

(3)生命周期

mounted() {
	console.log("组件挂载完成")
}

生命周期直接在类中以函数的方式使用即可

(4)计算属性

没有了computed,直接写在前面并带上一个get

//计算属性
get newStr(){
	return '我是'+this.str;
}

3.组件通信

(1)父子组件

新脚手架中父子组件通信,需要使用Prop装饰器

父组件:

<template>
  <div class="about">
    <h1>This is an about page</h1>
	<!-- 使用子组件并传递数据 -->
    <v-child :gift="msg"></v-child>
  </div>
</template>
<script lang="ts">
import { Component,Vue } from 'vue-property-decorator'
//引入子组件
import vChild from './Child.vue';
//利用装饰器,注册子组件
@Component({
    components:{
        vChild
    }
})
export default class About extends Vue{
    msg:string = "父组件上的数据"
}
</script>

子组件:

子组件中要通过Prop装饰器来接收数据

<template>
  <div class="about">
    <h1>这是子组件</h1>
    <p>gift:{{ gift }}</p>
  </div>
</template>
<script lang="ts">
import { Component,Vue,Prop,Emit } from 'vue-property-decorator'
@Component({})
export default class Child extends Vue{
    // @Prop(String) readonly gift : string | undefined
    @Prop({
        type:String,
        required:true
    })
    gift : string | undefined
}
</script>

(2)子父组件

父组件:

在父组件中传递一个自定义事件

<v-child :gift="msg" @changeStr="changeMsg"></v-child>

并在父组件的类中定义对应的函数

export default class About extends Vue{
    msg:string = "父组件上的数据"
    changeMsg(str:string){
        console.log("父组件上的函数被子组件触发了..."+str)
    }
}

子组件:

在子组件中通过Emit装饰器来触发父组件的事件

<template>
  <div class="about">
    <h1>这是子组件</h1>
    <p>gift:{{ gift }}</p>
    <button @click="send">发送</button>
  </div>
</template>
<script lang="ts">
import { Component,Vue,Prop,Emit } from 'vue-property-decorator'
@Component({})
export default class Child extends Vue{
    // @Prop(String) readonly gift : string | undefined
    @Prop({
        type:String,
        required:true
    })
    gift : string | undefined
    @Emit("changeStr")//触发父组件的事件
    send(){
        return '子组件传递的数据';//传递数据给父组件
    }
}
</script>
 类似资料: