安装
1、下载安装nodejs稳定版本
2、使用npm全局安装typescript
npm i -g typescript
3、使用tsc对文件进行编译
tsc xxx.ts
// 实时监控ts文件变化
tsc -w
变量类型
// 定义数字
let a : number;
a = 10;
// 定义字符串
let b : string;
b = 'sss';
// 定义字面量
let str : "male" | "female";
str = "male";
str = "female";
let c : boolean | string;
c = true;
c = "s";
// 定义数组结构声明:1、类型[],2、Array<类型>
let arr : string[];
arr = ['a', 'b', 'c'];
let arr2 : number[];
arr2 = [1, 3, 5];
let arr3 : Array<boolean>;
arr3 = [true, false];
// 定义元祖:元祖就是固定长度的数组
let h : [string, string, number];
h = ['a', 'b', 10]
// 定义对象,设置对象结构的类型声明
let people : {name:string, age?:number, [propName:string]:any};
people = {name: 'aaa', age: 10}
people = {name: 'aaa', age: 10, address: '中国'}
// 定义函数,设置函数结构的类型声明
function sum(a:number, b:number):number{
return a + b;
}
console.log(sum(1, 2))
let fun : (a:number, b:number)=>number;
fun = function(a, b){
return a+b;
}
// 定义枚举
enum Gender{
Male,
Female
}
let person : {name:string, gender:Gender};
person = {
name : '',
gender: Gender.Female
}
console.log(person.gender === Gender.Female)
TS编译文件配置
tsconfig.json
{
// 包含或排除哪些目录下的ts文件,**表示任意目录,*表示任意文件
"include": ["./src/**/*"],
"exclude": [],
// 编译配置
"compilerOptions": {
// ts编译成es的版本
"target": "ES6",
// 指定要使用的模块化
"module": "system",
// 指定项目中要使用的库,一般不需要修改
// "lib": ["DOM"],
// 指定编译后文件所在的目录
"outDir": "./dist",
// 将全局作用域的所有代码合并为一个文件
// "outFile": "./dist/app.js",
// 是否对js文件进行编译,默认是false
"allowJs": false,
// 是否检查js代码是否符合规范,默认是false
"checkJs": true,
// 是否移除编译后的注释
"removeComments": false,
// 是否不生成编译后的文件。可以只检查
"noEmit": false,
"noEmitOnError": true,
// 所有严格检查的总开关
"strict": true,
// 是否使用严格模式,默认是false
"alwaysStrict": true,
// 不指定变量类型时,是否默认是any
"noImplicitAny": false,
// 类型不明的this检查
"noImplicitThis": true,
// 严格检查空值
"strictNullChecks": true
}
}
webpack打包
1、创建 02 空文件夹
2、初始化 package.json 文件
npm init -y
3、安装相关依赖
cnpm i -D webpack webpack-cli typescript ts-loader
cnpm i -D html-webpack-plugin
cnpm i -D webpack-dev-server
cnpm i -D clean-webpack-plugin
cnpm i -D @babel/core @babel/preset-env babel-loader core-js
4、创建相关配置文件
package.json
{
"name": "02",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"start": "webpack serve --open chrome.exe"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.17.2",
"@babel/preset-env": "^7.16.11",
"babel-loader": "^8.2.3",
"clean-webpack-plugin": "^4.0.0",
"core-js": "^3.21.0",
"html-webpack-plugin": "^5.5.0",
"ts-loader": "^9.2.6",
"typescript": "^4.5.5",
"webpack": "^5.68.0",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.7.4"
}
}
webpack.config.js
//引入一个包
const path = require('path');
// 引入 html-webpack-plugin 插件
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 引入 clean-webpack-plugin 插件
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
// webpack中的所有配置信息都应写在 module.exports中
module.exports = {
// 指定入口文件
"entry": "./src/index.ts",
// 指定打包文件所在目录
"output": {
path: path.resolve(__dirname, "dist"),
// 打包后文件的名称
filename: "app.js",
// webpack是否使用箭头函数
environment: {
arrowFunction: false
}
},
// mode: "development",
// 指定webpack打包时要使用的模块
"module": {
// 指定要加载的规则
rules: [
{
// 规则生效的文件
test: /\.ts$/,
use: [
{
loader: "babel-loader",
options: {
presets: [
[
"@babel/preset-env",
{
// 要兼容的目标浏览器
targets: {
"chrome": "88",
"ie": "11"
},
// 指定corejs的版本
"corejs": "3",
// 使用corejs方式:usage表示按需加载
"useBuiltIns": "usage"
}
]
]
}
},
{
loader: "ts-loader"
}
],
exclude: /node_modules/
}
]
},
plugins:[
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
// title: "自定义的title"
template: './src/index.html'
})
],
// 设置引用的模块
resolve: {
extensions: ['.ts', '.js']
}
}
tsconfig.json
{
"compilerOptions": {
"module": "ES2015",
"target": "ES2015",
"strict": true
}
}
5、创建业务代码
src/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>自定义的title</title>
</head>
<body>hello world</body>
</html>
src/index.ts
import {printHello} from './test'
printHello();
function sum (num1:number, num2:number):number{
return num1+num2;
}
console.log(sum(3,5))
const num = 30;
console.log(num);
console.log(Promise)
src/test.ts
function printHello(){
console.log('hello!')
}
export {printHello}
最后的项目结构如下
image.png
类
1、person.ts
// 定义类,主要包含2大部分:属性、方法
class Person{
// 实例属性
name:string = "孙悟空";
// 静态属性
static age:number = 18;
// 只读属性,无法修改
readonly address:string = "花果山";
// 只读静态属性,无法修改
static readonly task:string = "西天取经";
// 私有属性(public、protected、private)
private _height:number = 500;
// getHeight(){
// return this._height;
// }
// setHeight(height:number){
// this._height = height;
// }
get height(){
return this._height;
}
set height(height:number){
this._height = height;
}
// 定义实例方法
sayHello(){
console.log("hello 大家好!");
}
// 定义静态方法
static sayHello2(){
console.log("hello2 大家好!");
}
}
// 测试属性
const person = new Person();
console.log(person);
console.log(person.name);
console.log(Person.age);
// 测试方法
person.sayHello();
Person.sayHello2();
// 修改私有属性
// person.setHeight(100);
person.height = 100;
// console.log(person);
2、dog.ts
// 定义类,主要包含2大部分:属性、方法
class Dog{
name:string;
age:number;
// 构造函数
constructor(name:string, age:number){
this.name = name;
this.age = age;
}
// 定义实例方法
bark(){
console.log(this);
console.log("汪汪汪!!!");
}
}
const dog = new Dog("旺财", 3);
console.log(dog);
dog.bark();
3、interface.ts
// 接口: 包含属性结构和抽象方法,定义了规范
interface myInter{
name:string;
age:number;
sayHello():void;
}
class myClass implements myInter{
name:string;
age:number;
constructor(name:string, age:number){
this.name = name;
this.age = age;
}
sayHello(): void {
console.log("----------");
}
}
const my = new myClass("张三", 10);
console.log(my);
4、extends.ts
// 继承、抽象
// 父抽象类
abstract class Animal{
name:string;
age:number;
constructor(name:string, age:number){
this.name = name;
this.age = age;
}
// 抽象方法
abstract sayHello():void;
}
// 子类
class Cat extends Animal{
// 实现父类中的抽象方法
sayHello(): void {
console.log("喵喵喵喵!!!")
}
}
const cat = new Cat("小花", 3);
console.log(cat);
cat.sayHello();
5、T.ts
// 泛型:在定义函数或类时,如果遇到类型不明确就可以使用泛型
// 函数泛型
function fn<T>(a:T):T{
return a;
}
console.log(fn(10));
console.log(fn<string>("hello"));
function fn2<T, K>(a:T, b:K):T{
return a;
}
console.log(fn2<number, string>(10, "hello"));
// 接口泛型
interface Inter{
length:number;
}
class People implements Inter{
constructor(public length:number){}
}
function fn3<T extends Inter>(a:T):number{
return a.length;
}
console.log(fn3(new People(10)));
// 类泛型
class Computer<T>{
name: T;
age: number;
constructor(name:T, age:number){
this.name = name;
this.age = age;
}
}
const computer = new Computer<string>("联想", 3);
console.log(computer);
6、index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>自定义的title</title>
<script src="./dist/person.js"></script>
<script src="./dist/dog.js"></script>
<script src="./dist/extends.js"></script>
<script src="./dist/interface.js"></script>
<script src="./dist/T.js"></script>
</head>
<body>hello world</body>
</html>
7、tsconfig.json
{
"include": ["./src/**/*"],
"compilerOptions": {
"module": "ES2015",
"target": "ES2015",
"strict": true,
"outDir": "./dist",
"noEmitOnError": true
}
}
1.jpg
贪吃蛇项目
1、将webpack打包中的3个配置文件(package.json、tsconfig.json、webpack.config.js)拷贝到新文件夹中,并执行 cnpm i 安装依赖
2、安装新的依赖
cnpm i -D less less-loader css-loader style-loader
cnpm i -D postcss postcss-loader postcss-preset-env
3、项目结构如下
image.png
4、package.json
{
"name": "02",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"start": "webpack serve --open chrome.exe"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.17.2",
"@babel/preset-env": "^7.16.11",
"babel-loader": "^8.2.3",
"clean-webpack-plugin": "^4.0.0",
"core-js": "^3.21.0",
"css-loader": "^6.6.0",
"html-webpack-plugin": "^5.5.0",
"less": "^4.1.2",
"less-loader": "^10.2.0",
"postcss": "^8.4.6",
"postcss-loader": "^6.2.1",
"postcss-preset-env": "^7.3.1",
"style-loader": "^3.3.1",
"ts-loader": "^9.2.6",
"typescript": "^4.5.5",
"webpack": "^5.68.0",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.7.4"
}
}
5、tsconfig.json
{
"compilerOptions": {
"module": "ES2015",
"target": "ES2015",
"strict": false,
"noEmitOnError": true
}
}
6、webpack.config.js
//引入一个包
const path = require('path');
// 引入 html-webpack-plugin 插件
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 引入 clean-webpack-plugin 插件
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
// webpack中的所有配置信息都应写在 module.exports中
module.exports = {
// 指定入口文件
"entry": "./src/index.ts",
// 指定打包文件所在目录
"output": {
path: path.resolve(__dirname, "dist"),
// 打包后文件的名称
filename: "app.js",
// webpack是否使用箭头函数、const.(为了兼容IE等浏览器)
environment: {
arrowFunction: false,
const: false
}
},
// mode: "development",
// 指定webpack打包时要使用的模块
"module": {
// 指定要加载的规则
rules: [
{
// 规则生效的文件
test: /\.ts$/,
use: [
{
loader: "babel-loader",
options: {
presets: [
[
"@babel/preset-env",
{
// 要兼容的目标浏览器
targets: {
"chrome": "88",
"ie": "11"
},
// 指定corejs的版本
"corejs": "3",
// 使用corejs方式:usage表示按需加载
"useBuiltIns": "usage"
}
]
]
}
},
{
loader: "ts-loader"
}
],
exclude: /node_modules/
},
{
test: /\.less$/,
use: [
"style-loader",
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
[
"postcss-preset-env",
{
browsers: "last 2 versions"
}
]
]
}
}
},
"less-loader"
]
}
]
},
plugins:[
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
// title: "自定义的title"
template: './src/index.html'
})
],
// 设置引用的模块
resolve: {
extensions: ['.ts', '.js']
}
}
7、index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>贪吃蛇</title>
</head>
<body>
<div id="main">
<div id="stage">
<!-- 设置蛇 -->
<div id="snake">
<!-- 蛇的各部分 -->
<div>
</div>
</div>
<!-- 食物 -->
<div id="food">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
<div id="score-panel">
<div>
SCORE:<span id="score">0</span>
</div>
<div>
LEVEL:<span id="level">1</span>
</div>
</div>
</div>
</body>
</html>
8、index.ts
// 引入样式
import './style/index.less';
import GameControl from './modules/GameControl';
new GameControl();
9、src/style/index.less
// 设置变量
@bg-color: #b7d4a8;
// 清除默认样式
*{
margin: 0;
padding: 0;
// 改变盒子模型的计算方式
box-sizing: border-box;
}
body{
font: bold 20px "Courier";
}
// 设置主窗口的样式
#main{
width: 360px;
height: 420px;
background-color: @bg-color;
margin: 100px auto;
border: 10px solid black;
border-radius: 10px;
// 开启弹性盒模型
display: flex;
// 设置主轴的方向
flex-flow: column;
// 设置侧轴的对齐方式
align-items: center;
// 设置主轴的对齐方式
justify-content: space-around;
// 游戏舞台
#stage{
width: 304px;
height: 304px;
border: 2px solid black;
// 开启相对定位
position: relative;
// 设置蛇的样式
#snake{
&>div{
width: 10px;
height: 10px;
background-color: #000000;
border: 1px solid @bg-color;
// 开启绝对定位
position: absolute;
}
}
// 设置食物样式
#food{
position: absolute;
width: 10px;
height: 10px;
left: 40px;
top: 100px;
display: flex;
// 设置主轴为横轴,wrap表示会自动换行
flex-flow: row wrap;
justify-content: space-between;
align-content: space-between;
&>div{
width: 4px;
height: 4px;
background-color: black;
transform: rotate(45deg);
}
}
}
// 记分牌
#score-panel{
width: 300px;
display: flex;
// 设置主轴的对齐方式
justify-content: space-between;
}
}
10、src/modules/Foods.ts
// 定义食物类
class Food{
// 定义一个属性表示食物对应的div
element: HTMLElement;
constructor(){
// 获取页面中food元素,并赋值给element
this.element = document.getElementById('food')!;
}
// 获取食物x轴坐标的方法
get X(){
return this.element.offsetLeft;
}
// 获取食物y轴坐标的方法
get Y(){
return this.element.offsetTop;
}
// 随机修改食物位置
change(){
// 随机数,0-290之间且步长为10(蛇每次移动一格,10px)
// Math.round: 四舍五入。Math.random:0-1随机数(不包含0和1)
let top = Math.round(Math.random() * 29) * 10;
let left = Math.round(Math.random() * 29) * 10;
this.element.style.left = left+'px';
this.element.style.top = top+'px';
}
}
// const food = new Food();
// console.log(food.X, food.Y);
// setInterval(()=>{
// food.change();
// console.log(food.X, food.Y);
// }, 1000)
export default Food;
11、GameControl.ts
import Snake from "./Snake";
import Food from "./Food";
import ScorePanel from "./ScorePanel";
// 游戏控制器,控制其他的所有类
class GameControl {
// 蛇
snake: Snake;
// 食物
food: Food;
// 记分牌
scorePanel: ScorePanel;
// 存储蛇的移动方向,即键盘的按键方向
direction: string = "";
// 游戏是否结束
isLive: boolean = true;
constructor() {
this.snake = new Snake();
this.food = new Food();
this.scorePanel = new ScorePanel(10, 10);
this.init();
}
// 游戏的初始化方法,调用后游戏开始
init() {
// 绑定键盘按键按下事件
document.addEventListener("keydown", this.keydownHandler.bind(this));
this.run();
}
// 创建键盘按键按下的响应函数(ArrowUp、ArrowDown、ArrowLeft、ArrowRight)
keydownHandler(event: KeyboardEvent) {
this.direction = event.key;
}
// 根据direction控制蛇移动
run() {
let X = this.snake.X;
let Y = this.snake.Y;
switch (this.direction) {
case "ArrowUp":
case "Up":
Y -= 10;
break;
case "ArrowDown":
case "Down":
Y += 10;
break;
case "ArrowLeft":
case "Left":
X -= 10;
break;
case "ArrowRight":
case "Right":
X += 10;
break;
}
// 检查蛇是否吃到食物
this.checkEat(X, Y);
// 修改蛇的xy
try {
this.snake.X = X;
this.snake.Y = Y;
} catch (e) {
alert(e.message + " GAME OVER!");
this.isLive = false;
}
// 开启一个定时调用
this.isLive &&
setTimeout(
this.run.bind(this),
300 - (this.scorePanel.level - 1) * 30
);
}
// 检查蛇是否吃到食物
checkEat(X: number, Y: number) {
if (X === this.food.X && Y === this.food.Y) {
this.food.change();
this.scorePanel.addScore();
this.snake.addBody();
}
}
}
export default GameControl;
12、ScorePanel.ts
// 定义记分牌类
class ScorePanel{
score:number = 0;
level:number = 1;
scoreElem: HTMLElement;
levelElem: HTMLElement;
maxLevel:number;
upScore:number;
constructor(maxLevel:number=10, upScore:number=10){
this.scoreElem = document.getElementById('score')!;
this.levelElem = document.getElementById('level')!;
this.maxLevel = maxLevel;
this.upScore = upScore;
}
// 加分方法
addScore(){
this.score++;
this.scoreElem.innerHTML = this.score+'';
if(this.score % this.upScore === 0){
this.levelUp();
}
}
// 升级方法
levelUp(){
if(this.level < this.maxLevel){
this.level++;
this.levelElem.innerHTML = this.level+'';
}
}
}
// const score = new ScorePanel();
// setInterval(()=>{
// score.addScore();
// }, 500)
export default ScorePanel;
13、Snake.ts
class Snake{
// 表示蛇头
head:HTMLElement;
// 蛇的身体(包括蛇头)
bodies:HTMLCollection;
// 获取蛇的容器
element:HTMLElement;
constructor(){
this.element = document.getElementById('snake')!;
this.head = document.querySelector('#snake > div')!;
this.bodies = this.element.getElementsByTagName('div');
}
// 获取蛇头的坐标
get X(){
return this.head.offsetLeft;
}
get Y(){
return this.head.offsetTop;
}
// 设置蛇头的坐标
set X(value:number){
// 如果新值和旧值一样,不再修改
if(this.X === value){
return;
}
// 蛇是否撞墙
if(value < 0 || value > 290){
throw new Error("蛇撞墙了!");
}
// 蛇在水平移动时,不能掉头
if(this.bodies[1] && (this.bodies[1] as HTMLElement).offsetLeft === value){
if(value > this.X){
value = this.X - 10;
}else{
value = this.X + 10;
}
}
this.moveBody();
this.head.style.left = value+"px";
this.checkHeadBody();
}
set Y(value:number){
if(this.Y === value){
return;
}
// 蛇是否撞墙
if(value < 0 || value > 290){
throw new Error("蛇撞墙了!");
}
// 蛇在竖直移动时,不能掉头
if(this.bodies[1] && (this.bodies[1] as HTMLElement).offsetTop === value){
if(value > this.Y){
value = this.Y - 10;
}else{
value = this.Y + 10;
}
}
this.moveBody();
this.head.style.top = value+"px";
this.checkHeadBody();
}
// 蛇增加身体的方法
addBody(){
this.element.insertAdjacentHTML("beforeend", "<div></div>");
}
// 蛇移动身体
moveBody(){
// 将后边的身体设置为前边的身体
// 第3节等于第2节位置,第2节等于第1节位置,第1节等于蛇头的位置
for(let i=this.bodies.length-1; i>0; i--){
let X = (this.bodies[i-1] as HTMLElement).offsetLeft;
let Y = (this.bodies[i-1] as HTMLElement).offsetTop;
(this.bodies[i] as HTMLElement).style.left = X+"px";
(this.bodies[i] as HTMLElement).style.top = Y+"px";
}
}
// 检查蛇的头部与身体是否相撞
checkHeadBody(){
for(let i=1; i<this.bodies.length; i++){
let bd = this.bodies[i] as HTMLElement;
if(this.X === bd.offsetLeft && this.Y === bd.offsetTop){
throw new Error("蛇撞到自己了!");
}
}
}
}
export default Snake;
14、npm run build 打包生成 dist文件夹(app.js、index.html),然后浏览器直接打开index.html即可看到效果
image.png
网友评论