Vue3+TS quick start

1, TypeScript quick start

New TypeScript

TypeScript is a superset of JavaScript. It mainly provides type system and support for ES6 +. It is developed by Microsoft and the code is open source GitHub upper

Install TypeScript

Run the following command from the command line to install TypeScript globally:

npm install -g typescript

After installation, run the following command on the console to check whether the installation is successful:

tsc -V 

First TypeScript program

  • Write TS program
//helloworld.ts
function greeter(person){
  return 'hello,'+person
}
let user='tao'
console.log(greeter(user))
  • Manually compile code
    We use the. ts extension, but this code is just JS
    On the command line, run the TypeScript compiler:
tsc helloworld.ts

The output result is a helloworld.js file, which contains the same JS code as in the input file
On the command line, run this code through Node.js:

node helloworld.js

Console output:

hello,tao
  • vscode auto compile
1)Generate profile tsconfig.json
tsc --init

2)modify tsconfig.json to configure
"outDir":"./js",
"strict":false,

3)Start monitoring task
 terminal->Run task->monitor tsconfig.json
  • type annotation
    Add the annotation of string type to the function parameters, as follows:
function greeter(person:string){
   return 'hello,'+person
}
let user='tao'
console.log(greeter(user))

Type annotation in TypeScript is a lightweight way to add constraints to functions or variables. In this example, we want the function to accept a string parameter. Then try passing in the array:

function greeter(person:string){
  return 'hello,'+person
}
let user=[0,1,2]
console.log(greeter(user))

Recompilation resulted in an error:

error TS2345: Argument of type 'number[]' is not assignable to parameter of type 'string'.
  • Interface
    Use the interface to describe an object with firstName and lastName fields. In TypeScript, if there are only structures inside two types, the two types are compatible. This allows us to implement the interface as long as we ensure that the structure required by the interface is included, without explicitly using the implementation statement
interface Person{
  firstName:string,
  lastName:string
}
function greeter(person:Person){
  return 'hello,'+person.firstName+person.lastName
}
let user={
 firstName:'tao',
 lastName:'xie'
}
console.log(greeter(user))
  • class
    Create a User class with a constructor and some public fields. Because the fields of the class contain the fields required by the interface, they are well compatible
class User {
 fulName:string,
 firstName:string,
 lastName:string
 
 constructor(firstName:string,lastName:string){
    this.firstName = firstName
    this.lastName = lastName
    this.fullName = firstName + ' ' + lastName
  }
}

interface Person {
  firstName: string
  lastName: string
}

function greeter (person: Person) {
  return 'Hello, ' + person.firstName + ' ' + person.lastName
}

let user = new User('tao', 'xie')

console.log(greeter(user))

TypeScript common syntax

Foundation type
  • Boolean value
    The most basic data type is simple true/false, which is called boolean in JS and TS
let isDone:boolean=false
isDone=true
//isDone=2 //error
  • number
    Like JS, all numbers in TS are floating point numbers. The type of these floating-point numbers is number. In addition to supporting decimal and hexadecimal literals, TS also supports binary and octal literals introduced in ECMAScript2015
let a1:number=10 //decimal system
let a2:number=0b1010 //Binary
let a3:number=0o12 //octal number system
let a4:number=0xa //hexadecimal
  • character string
    Use string to represent text data type. Like JS, you can use double quotation marks "or single quotation marks" to represent strings
let name:string='tom'
name='jack'
//name=12 //error
let age:number=12
const info=`My name is ${name},I am ${age} years old`
  • undefined and null
    By default, null and undefined are subtypes of all types.
let u:undefined=undefined
let u:null=null
  • array
//The first way to define an array is to add [] directly after the element type
let list1:number[]=[1,2,3]

//The second is to define an array
let list2:Array<number>=[1,2,3]
  • Tuple tuple
    Tuple type allows to represent an array with known number and type of elements, and each array element does not have to be the same.
let t1:[string,number]
t1=['hello',1] //ok
t1=[1,'hello'] //error

When you access an element with a known index, you will get the correct type:

console.log(t1[0].substring(1)) //ok 
console.log(t1[1].substring(1)) //error number substring method does not exist
  • enumeration
    enum uses enumeration types to give friendly names to a set of arrays
enum Color {
  Red,
  Green,
  Blue
}
//Enumeration values are incremented from 0 by default
//Get the corresponding enumeration type according to the specific name
let myColor:Color = Color.Green //0
console.log(myColor,Color.Red,Color.Blue)

By default, elements are numbered from 0. You can also specify the number of members:

enum Color {
  Red=1,
  Green,
  Blue
}
let c:Color=Color.Green

Or all manual assignment:

enum Color {
  Red=1,
  Green=2,
  Blue=4
}
let c:Color=Color.Green

Enumeration type provides a convenience that its name can be obtained from the value of enumeration:

enum Color {
  Red=1,
  Green,
  Blue
}
let colorName:string=Color[2]
console.log(colorName) //Green
  • any
let notSure:any=4
notSure='maybe a string'
notSure=false

Any type is very useful when rewriting existing code. It allows you to optionally include or remove checks at compile time. And any type is also useful when you only know the type of some data:

let list:any[]=[1,true,'free']
list[1]=100
  • void
    To some extent, void type is like the opposite of any type. It means that there is no type. When a function has no return value, you will usually see that its return value type is void:
/*Indicates that there is no type. It is generally used to indicate that the return value of a function cannot be a value other than undefined and null*/
function fn():void{
 console.log('fn()')
 //return undefined
 //return null
 //return 1  //error
}

It's no use declaring a variable of void type, because you can only give it undefined and null:

let unusable:void=undefined
  • object
    object represents a non primitive type, that is, a type other than number, string and Boolean
    Using object type can better represent API s such as Object.create:
function fn2(obj:object){
  console.log('fn2()',obj)
  return {}
  // return undefined
  // return null
}
console.log(fn2(new String('abc')))
//console.log(fn2('abc')) //error
console.log(fn2(String))
  • Union type
    Union type indicates that the value can be one of multiple types
    Requirement 1: define a function to get a string value of a number or string value
function toString2(x:number|string):string{
  return x.toString()
}

Requirement 2: define a function to get the length of a number or string value

function getLength(x:number|string){
  //return x.length //error
  if(x.length){ //error
    return x.length
  }else{
    return x.toString().length
  }
}
  • Type Asserts
    Through type assertion, you can tell the compiler, "trust me, I know what I'm doing". Type assertion is like type conversion in other syntax, but it doesn't carry out special data checking and deconstruction. It has no run-time impact, but works at the compilation stage.
    There are two forms of type assertion. One is' angle bracket 'syntax and the other is as syntax
/*
 Type assertion: can be used to manually specify the type of a value
 Syntax:
     Method 1: < type > value
     Method 2: only this method can be used in the value as type tsx
*/

/*Requirement: define a function to get the length of a string or numeric data*/
function getLength(x:number|string){
    if((<string>x).length){
      return (x as string).length
    }else{
      return x.toString().length
    }
}
console.log(getLength('abcd'),getLength(1234))
  • Type inference
    Type inference: TS infers a type when there is no explicit specified type
    There are two situations as follows: 1. When defining a variable, the assignment is inferred as the corresponding type; 2. When defining a variable, there is no assignment, and it is inferred as any type
/*When a variable is defined, it is assigned a value and inferred as the corresponding type*/
let b9=123. //number
//b9='abc' //error

/*The variable is defined without assignment and is inferred as any type*/
let b10 //any
b10=123
b10='abc'
Interface

An interface is an abstraction (description) of an object's state (property) and behavior (method)

  • Preliminary study on interface
    Requirements: to create human objects, you need to restrict human attributes
id yes number Type, must have, read-only
name yes string Type, must have
age yes number Type, must have
sex yes string Type, no

Here is a simple example to see how the interface works:

/*
 In ts, we use interface s to define the types of objects
 Interface: it is the abstraction (description) of the state (property) and behavior (method) of an object
 Object of interface type
   More or less attributes are not allowed
   Optional attribute:?
   Read only attribute: readonly
*/

/*
Requirements: to create human objects, you need to restrict human attributes
id It is of type number and must be read-only
name Is a string type and must have
age Is of type number and must have
sex It is a string type and can not be used
*/

//Define human interface
interface IPerson{
 id:number,
 name:string,
 age:number,
 sex:string
}
const person1:Person={
  id:1,
  name:'tom',
  age:20,
  sex:'male'
}

The type checker will check whether the internal properties of the object are consistent with the description of the Iperson interface. If not, it will prompt the type error

  • optional attribute
    Not all properties in the interface are required. Some exist only under certain conditions or do not exist
interface IPerson{
 id:number,
 name:string,
 age:number,
 sex?:string
}

Interfaces with optional attributes are similar to ordinary interface definitions, except that the optional attribute name definition is followed by a "-"
One of the advantages of optional attributes is that they can predefine possible attributes. The other advantage is that they can catch errors when referring to non-existent attributes

const person2:IPerson={
  id:1,
  name:'tom',
  age:20,
  //sex: 'male' / / no
}
  • Read only attribute
    Some object properties can only change their values when the object is just created. You can specify a read-only attribute with readonly before the attribute name:
interface IPerson{
 readonly id:number,
 name:string,
 age:number,
 sex?:string
}

Once assigned, it can no longer be changed

const person2:IPerson={
 id:2,
 name:'tom',
 age:20,
 //sex: 'male' / / no
 //xxx:12. //error is not defined in the interface and cannot exist
}
person2.id=2 //error

readonly vs const
The simplest way to judge whether to use readonly or const is to use it as a variable or as an attribute. Const is used as a variable and readonly is used as an attribute

  • Function type
    Interface can describe various shapes of objects in JS. In addition to describing ordinary objects with properties, interfaces can also describe function types.
    In order to use an interface to represent a function type, you need to define a call signature for the interface. It's like a function definition with only parameter list and return value type. Each parameter in the parameter list needs a name and type.
/*
 Interfaces can describe function types (parameter types and return types)
*/
interface SearchFunc{
 (source:string,subString:string):boolean
}

After this definition, you can use the interface of this function type like other interfaces. The following example shows how to create a variable of function type and assign a function of the same type to this variable:

const mySearch:SearchFunc=function(source:string,sub:string):boolean{
   return source.search(sub)>-1
}
console.log(mySearch('abcd','bc'))
  • Class type
    Class implementation interface
/*
 Class type: implementation interface
 1.A class can implement multiple interfaces
 2.An interface can inherit multiple interfaces
*/
interface Alam{
  alert():any
}
interface Light{
  lightOn():void
  lightOff():void
}
class Car implements Alam {
 alert(){
  console.log('Car alert')
 }
}
  • A class can implement multiple interfaces
class Car2 implements Alam,Light{
 alert(){
   console.log('Car alert')
 },
 lightOn(){
   console.log('Car light on')
 },
 lightOff(){
   console.log('Car light off')
 }
}
  • Interface inheritance interface
    Like classes, interfaces can inherit from each other. Members can be copied from one interface to another, and interfaces can be divided into rewritable modules more flexibly
interface LightableAlarm extends Alam,Light{

}
class
  • Basic example:
/*
 Basic definition and use of class
*/
class Greeter{
 //Declare properties
 message:string
 //Construction method
 constructor(message:string){
  this.message=message
 }
 //General method
 greet():string{
   return 'hello'+this.message
 }
}

//Create an instance of a class
const greeter=new Greeter('world')
//Call the method of the instance
console.log(greeter.greete())

this is used when referring to any class member. It indicates that you are accessing a member of a class.

In the next line, an instance of the Greeter class is constructed using new. It calls the previously defined constructor, creates a new object of type Greeter, and executes the constructor to initialize it.

The last line calls its greet method through the greeter object

  • inherit
    One of the most basic patterns in class based programming is to allow inheritance to extend existing classes.
/*
 Class inheritance
*/
class Animal{
  run(distance:number){
    console.log(`Animal run ${distance}m`)
  }
}
class Dog extends Animal{
  cry()
   console.log('wang! wang!')
  }
}
const dog=new Dog()
dog.cry()
dog.run(100) //Methods inherited from the parent can be called

This example shows the most basic inheritance: the class inherits properties and methods from the base class. Here, Dog is a derived class derived from the Animal base class through the extends keyword. Derived classes are often called subclasses, and base classes are often called superclasses.
Because Dog inherits the function of Animal, we can create an instance of Dog, which can cry() and run()

class Animal {
  name:string
  constructor (name;string){
    this.name=name
  }
  run(distance:number=0){
    console.log(`${this.name} run ${distance} m`)
  }
}

class Snake extends Animal {
  constructor(name:string){
    //Call the parent type constructor
    super(name)
  }
  //Override method of parent type
  run(distance:number=5){
    console.log('sliding...')
    super.run(distance)
  }
}

class Horse extends Animal {
  constructor (name:string){
    //Call the parent type constructor
    super(name)
  }
  //Override method of parent type
  run(distance:number=50){
    console.log('dashing...')
    //Call the generic method of the parent type
    super.run(distance)
  }
  xxx(){
    console.log('xxx()')
  }
}

const snake=new Snake('sn')
snake.run()

const horse=new Horse('ho')
horse.run()

//The parent type reference points to the instance of the child type = >
const tom:Animal=new Horse('ho22')
tom.run()

/*If the subtype does not have an extended method, you can make the subtype reference point to the type of the parent type*/
const tom3:Snake=new Animal('tom3')
tom3.run()
/*If a subtype has an extended method, you cannot make a subtype reference point to an instance of the parent type*/
//const tom2:Horse=new Animal('tom2')
//tom3.run()

Using the extends keyword, two subclasses of Animal are created: Horse and Snake. The derived class contains a constructor, which must call super(), which will execute the constructor of the base class. Moreover, before accessing the property of this in the constructor, be sure to call super(). This is an important rule enforced by TS.

This example demonstrates how to override the methods of the parent class in a child class. Both Snake class and Horse class create run methods. They override the run methods inherited from Animal, so that the run methods have different functions according to different classes. Note that even if tom is declared as an Animal type, because its value is Horse, when tom.run(34) is called, it will call the method overridden in Horse.

  • Public, private and protected modifiers
    1. The default is public
    You can freely access the members defined in the program. In TS, all members are public by default. You can also explicitly mark a member as public.

    2. Understand private
    When a member is marked private, it cannot be accessed outside the class that declares it.

    3. Understand protected
    The protected modifier behaves similar to the private modifier, but with one difference, protected members are still accessible in derived classes.

/*
 Access modifier: used to describe the accessibility of properties / methods within a class
 public: By default, exposed external can be accessed
 private: Only the inside of the class can be accessed
 protected: Classes and subclasses can access
*/
class Animal {
  public name:string
  public constructor(name:string){
    this.name=name
  }
  public run(distance:name=0){
    console.log(`${this.name} run ${distance}m`)
  }
}
class Person extends Animal{
  private age:number=18
  protected sex:string='male'
  run (distance:number){
    console.log('Perosn jumping...')
    super.run(distance)
  }
}
class Student extends Person{
  run(distance:number=6){
    console.log('Studnet jumping...')
    
    console.log(this.sex) //The child class can see the protected members in the parent class
    //console.log(this.age) / / the subclass cannot see the private members in the parent class

    super.run(distance)
  }
}

console.log(new Person('abc').name)  //Public visibility
//console.log(new Person('abc').sex) / / protected invisible
//console.log(new Person('abc').age). / / private, invisible
  • readonly modifier
    You can use the readonly keyword to set the property to read-only. Read only properties must be initialized in declarations or constructors.
class Person{
  readonly name:string='abc'
  constructor(name:string){
   this.name=name
  }
}
let john=new Person('John')
//john.name='peter'  //error

Parameter properties
In the above example, you must define a read-only member name and a constructor with a parameter of name in the Person class, and immediately assign the value of name to this.name. This is often encountered. Parameter properties make it easy to define and initialize a member in one place.

class Person2{
  constructor (readonly name:string){
    
  }
}
const p=new Person2('jack')
console.log(p.name)

Notice how to discard the parameter name. Only use the readonly name:string parameter in the constructor to create and initialize the name member. Merge declarations and assignments into one place.
Parameter properties are declared by adding an access qualifier in front of constructor parameters. Using private to define a parameter attribute will declare and initialize a private member; The same is true for public and protected.

  • Accessor
    Typescript supports intercepting access to object members through getters/setters. It can help you effectively control access to object members.
class Person {
  firstName:string='A'
  lastName:string='B'
  get fullName(value){
     return this.firstName+'-'+this.lastName
  }
  set fullName(value){
     const names=value.split('-')
     this.firstName=name[0]
     this.lastName=name[1]
  }
}

const p=new Person()
console.log(p.fullName)

p.firstName='C'
p.lastName='D'
console.log(p.fullName)

p.fullName='E-F'
console.log(p.firstName,p.lastName)
  • Static properties
    You can create static members of a class. These properties exist on the class itself rather than on an instance of the class.
/*
Static attribute: it is the attribute of class object
 Non static attribute: it is the attribute of the instance object of the class
*/
class Person{
  name1:string='A'
  static name2:string='B'
}
console.log(Person.name2)
console.log(new Person().name1)
  • abstract class
    Abstract classes are used as base classes for other derived classes. They cannot be instantiated. Unlike interfaces, abstract classes can contain implementation details of members. Abstract keyword is a method used to define an abstract class and define an abstraction inside an abstract class.
/*
abstract class
  You cannot create an instance object. Only an implementation class can create an instance
  Can contain abstract methods that are not implemented
*/
abstract class Animal{
  abstract cry()
  run(){
    console.log('run()')
  }
}
class Dog extends Animal{
  cry(){
    console.log('Dog cry()')
  }
}
const dog=new Dog()
dog.cry()
dog.run()
function
  • Basic example
    Like JS, TS functions can create named and anonymous functions. You can choose the right way for your application, whether it's defining a series of API functions or using functions only once.
    The following examples can quickly recall the two functions of JS:
//Named function
function add(x,y){
  return x+y
}
//Anonymous function
let myAdd=function(x,y){
  return x+y
}
  • Function type
    1. Define type for function
    Add type for the above function
function add(x:number,y:number):number{
  return x+y
}

let myAdd=function(x:number,y:number):number{
  return x+y
}

You can add a type to each parameter before adding a return value type to the function itself. TS can automatically infer the return value type according to the return statement.

  • Write complete function type
let myAdd2:(x:number,y:number)=>number=function(x:number,y:number):number{ return x+ y }
  • Optional and default parameters
    Every function parameter in TS is required. This does not mean that null and undefined cannot be passed as parameters, but that the compiler checks whether the user has passed in a value for each parameter. The compiler also assumes that only these parameters will be passed into the function. In short, the number of parameters passed to a function must be the same as the number of parameters expected by the function.
    In JS, each parameter is optional and can be passed or not. When no parameter is passed, its value is undefined. In TS, it can be used next to the parameter name? Realize the function of optional parameters.
function bulidName(firstName:string='A',lastName?:string):string {
  if(lastName){
    return firstName+'-'+lastName
  } else {
    return firstName
  }
}

console.log(bulidName('C','D'))
console.log(bulidName('C'))
console.log(bulidName())
  • Remaining parameters
    Required parameters, default parameters and optional parameters have one thing in common: they represent a parameter. Sometimes, you want to manipulate multiple parameters at the same time, or you don't know how many parameters will be passed in. In JS, you can use arguments to access all the passed in parameters.
    In TS, all parameters can be collected into one variable: the remaining parameters will be treated as an unlimited number of optional parameters. You can have none, or you can have any. The compiler creates a parameter array. The name is the name given after the ellipsis (...), which can be used in the function body.
function info(x:string,...args:string[]){
  console.log(x,args)
}
info('abc','c','b','a')
  • function overloading
    Function overloading: multiple functions with the same function name but different formal parameters
/*
Function overloading: multiple functions with the same function name but different formal parameters
 Requirements: we have an add function, which can receive two string type parameters for splicing and two number type parameters for adding
*/
//Overloaded function declaration
function add(x:string,y:string):string
function add(x:number,y:number):number

//Define function implementation
function add(x:string | number,y:string | number):string | number {
  //In the implementation, we should strictly judge whether the types of two parameters are equal, rather than simply write an x+y
  if(typeof x==='string'&&typeof y==='string'){
    return x+y
  }else if(typeof x==='number'&&typeof y==='number'){
    return x+y
  }
}

console.log(add(1,2))
console.log(add('a'+'b'))
//console.log(1,'a') //error
generic paradigm

It refers to a feature that specifies a specific type when using a function, interface or class without specifying a specific type in advance.

  • introduce
    Next, create a function to realize the function: create an array containing count values according to the specified quantity count and data value. Without generics, this function may be as follows:
function createArray(value:any,count:number):any[]{
  const arr:any[]=[]
  for(let index=0;index<count;index++){
    arr.push(value)
  }
  return arr
}

const arr1=createArray(11,3)
const arr2=createArray('aa',3)
console.log(arr1[0].toFixed(),arr2[0].split(''))
  • Using function generics
function createArray2<T>(value:T,count:number){
  const arr:Array<T>=[]
  for(let index=0;index<count;index++){
    arr.push(value)
  }
  return arr
}
const arr3=createArray2<number>(11,3)
console.log(arr3[0].toFixed())
// console.log(arr3[0].split('')) //error
const arr4=createArray2<string>('aa',3)
console.log(arr4[0].split(''))
//console.log(arr[4].toFixed()) //error
  • Functions with multiple generic parameters
//A function can define multiple generic parameters
function swap<K,V>(a:K,b:V):[K,V]{
  return [a,b]
}
const result=swap<string,number>('abc',123)
console.log(result[0].length,result[1].toFixed())
  • generic interface
    When defining an interface, define generic types for properties or methods in the interface
    When using interfaces, specify specific generic types
interface ibaseCRUD<T>{
  data:T[]
  add:(t:T)=>void
  getById:(id:number)=>T
}

class User{
  id?:number;//id increases gradually
  name:string;//full name
  age:number;//Age

  constructor(name,age){
    this.name=name
    this.age=age
  }
}

class UserCRUD implements IbaseCRUD <User>{
  data:User[]=[]
  add(user:User):void{
    user={...user,id:Date.now()}
    this.data.push(user)
    console.log('preservation user',user.id)
  }
  getById(id:number):User{
    return this.data.find(item=>item.id===id)
  }
}

const userCRUD=new UserCRUD()
UserCRUD.add(new User('tom',12))
UserCRUD.add(new User('tom2',13))
console.log(userCRUD.data)
  • Generic class
    When defining a class, define generic types for properties or methods in the class, and specify specific generic types when creating instances of the class
class GenericNubmer<T>{
  zeroValue:T
  add:(x:T,y:T)=>T
}
let myGenericNumber=new GenericNubmer<number>()
myGenericNumber.zeroValue=0
myGenericNumber.add=function(x,y){
  return x+y
}

let myGenericString=new GenericNubmer<string>()
myGenericString.zeroValue='abc'
myGenericString.add=function(x,y){
  return x+y
}
console.log(myGenericString.add(myGenericNumber.zeroValue,'test'))
console.log(myGenericNumber.add(myGenericNumber.zeroValue,12))
  • Generic constraints
    Taking the length attribute directly on a generic parameter will report an error, because the generic does not know whether it has this attribute at all
//No generic constraints
function fn<T>(x:T):void{
  //console.log(x.length) //error
}

This can be done using generic constraints

interface Lengthwise{
  length:number
}
//Specify generic constraints
function fn2<T extends Lengthwise>(x:T):void{
  console.log(x.length)
}

The value conforming to the constraint type needs to be passed in, and the length attribute must be included:

fn2('abc')
//fn2(123) //error number has no length attribute
  • other

Declaration file

When using a third-party library, you need to reference its life file to obtain the corresponding code completion, interface prompt and other functions

What is life sentence

If you want to use a third-party library jQuery, a common way is to introduce jQuery through the < script > tag in html, and then you can use the global variable $or jQuery

But in ts, the compiler doesn't know what $or jQuery is

/*
 When using a third-party library, you need to reference its life file to obtain the corresponding functions such as code completion and interface prompt.
 Declaration statement: if necessary ts, check the new syntax. The corresponding type description code needs to be loaded
 declare var jQuery:(selector:string)=>any
 Declaration file: put the declaration statement into a separate file (jQuery.d.ts), and TS will automatically parse all the declaration files in the project
 Download the declaration file: NPM install @ type / jQuery -- save dev
*/
jQuery('#foo')
//ERROR:Cannot find name 'jQuery'

In this case, you need to use declare var to define its type

declare var jQuery:(selector:string)=>any
jQuery('#foo')

The general declaration file will be written as a xxx.d.ts file

Create 01_jQuery.d.ts, where the declaration statement is defined, and the TS compiler will scan and load all TS declaration files in the project

declare var jQuery:(selector:string)=>any

Many third-party libraries define corresponding declaration file libraries. The library file name is generally @ type /xxx, which can be found in https://www.npmjs.com/package/package Search

Some third-party libraries will automatically download the corresponding declaration file library (e.g. webpack) when downloading, and some may need to be downloaded separately (e.g. jQuery/react)

Built in object

There are many built-in objects in JS, which can be directly used as defined types in TS

Built in objects are objects that exist on the global scope according to standards. The standards here refer to ECMAScript and other environment standards (such as DOM)

1. Built in object of ECMAScript

/*1.ECMAScript Built in objects for*/
let b:Boolean=new Boolean(true)
let n:Number=new Number(1)
let s:String=new String('abc')
let d:Date=new Date()
let r:RegExp=/^1/
let e:Error=new Error('error message')
b=true
// let bb:boolean=new Boolean(2) //error

2. Built in objects of BOM and DOM

const div:HTMLELement=document.getElementById('test')
const divs:NodeList=document.querySelectorAll('div')
document.addEventListener('click',(event:MouseEvent)=>{
   console.log(event.target)
})
const fragment:DocumentFragment=document.createDocumentFragment()

2, Know vue3

Know vue3

1. Understand relevant information

  • Vue3 supports most of the properties of vue2
  • Better support for Typescript

2. Performance improvement

  • Using Proxy instead of defineProperty to implement data response
  • Implementation of rewriting virtual DOM and tree shaking

3. New features

  • Composition API

  • setup
    ref and reactive
    computed and watch
    New lifecycle function
    provide and inject
    ...

  • New component
    Fragment - document fragment
    Teleport - location of teleport components
    Suspend - loading interface of asynchronous loading component

  • Other API updates
    Modification of global API
    Transfer the original global API to the application object
    Template syntax changes

Create vue3 project

  • Create with Vue cli
## Install or upgrade
npm install -g @vue/cli

## Ensure that the vue cli version is above 4.5.0
vue --version
## Create project
vue create my-project
  • Create with vite
npm init vite-app <project-name>
cd <project-name>
npm install
npm run sev

Composition API (common part)

  • setup
    New option. All composite API functions are used here and are executed only once during initialization
    If the function returns an object, the properties or methods in the object can be used in the template
  • ref
    1. Function: define a data response formula
    2. Syntax: const xxx=ref(initValue)
    Create a reference object that contains responsive data
    Operation data in js: xxx.value
    Operation data in template:. value is not required
    3. It is generally used to define a basic type of responsive data
<template>
  <h2>{{count}}</h2>
  <hr>
  <button @click="update">to update</button>
</template>
<script>
import {ref} from 'vue'
export default{
  /*data and methods configuration can still be used in vue3, but its new syntax implementation is recommended*/
  //data(){
  // return{
  //     count:0
  //   }
  //},
  //methods:{
  //  update(){
  //   this.count++
  //   }
  //}
  /*Using vue3's composition API*/
  setup(){
    //Define a responsive data ref object
    const count=ref(1)
    console.log(count)

    //Function to update responsive data
    function update(){
      count.value=count.value+1
    }
  }
}
</script>
  • reactive
    1. Function: define the response formula of multiple data
    2.const proxy=reactive(obj): accept a common object and return the responsive proxy object of the common object
    3. Responsive transformation is "deep": it will affect all nested attributes within the object
    4. The internal Proxy implementation based on ES6 operates through the Proxy object, and the internal data of the source object is responsive
<template>
  <h2>name:{{state.name}}</h2>
  <h2>age:{{state.age}}</h2>
  <h2>wife:{{state.wife}}</h2>
  <hr>
  <button @click="update">to update</button>
</template>
<script>
import {reactive} from 'vue'
export default{
 setup(){
  /*Define responsive objects*/
  const state=reactive({
     name:'tom',
     age:25,
     wife:{
      name:"marry",
      age:22
     }
  })
  console.log(state,state.wife)
 
  const update=()=>{
    state.name+='--'
    state.age+=1
    state.wife.name+='++'
    state.wife.age+=2
  }

  return {
    state,
    update
  }
 }
}
</script>
  • Compare the responses of vue2 and vue3 (important)

Response of vue2

1. Core:
Object: hijack (monitor / intercept) the reading and modification of the existing property value of the object through defineProperty
Array: a series of methods to update elements by rewriting the array to update the array

Object.defineProperty(data,'count',{
   get(){},
   set(){}
})

2. Problems
Object directly adds new attributes or deletes existing attributes. The interface will not be updated automatically
Directly replace the element or update the length through the subscript, and the interface will not automatically update arr[1] = {}

Response of vue3
1. Core:
Through proxy: intercept any (13) operations on any attribute of data, including reading and writing attribute values, adding attributes, deleting attributes, etc
Reflect: dynamically perform specific operations on the corresponding attributes of the proxied object

new Proxy(data,{
  //Intercept reading attribute values
  get(target,prop){
    return Reflect.get(target,prop)
  }
  //Intercept setting property values or adding new properties
  set(target,prop,value){
    return Reflect.set(target,prop,value)
  }
  //Block delete attribute
  deleteProperty(target,prop){
    return Reflect.deleteProperty(target,prop)
  }
})
proxy.name="tom"
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Proxy And Reflect</title>
</head>
<body>
  <script>
    
    const user = {
      name: "John",
      age: 12
    };

    /* 
    proxyUser User is the proxy object and user is the proxy object
    All the latter operations operate the internal properties of the proxy object through the proxy object
    */
    const proxyUser = new Proxy(user, {

      get(target, prop) {
        console.log('hijack get()', prop)
        return Reflect.get(target, prop)
      },

      set(target, prop, val) {
        console.log('hijack set()', prop, val)
        return Reflect.set(target, prop, val); // (2)
      },

      deleteProperty (target, prop) {
        console.log('hijack delete attribute', prop)
        return Reflect.deleteProperty(target, prop)
      }
    });
    // Read attribute value
    console.log(proxyUser===user)
    console.log(proxyUser.name, proxyUser.age)
    // Set attribute value
    proxyUser.name = 'bob'
    proxyUser.age = 13
    console.log(user)
    // Add attribute
    proxyUser.sex = 'male'
    console.log(user)
    // Delete attribute
    delete proxyUser.sex
    console.log(user)
  </script>
</body>
</html>
  • setup
    1. Timing of setup execution
    1) Execute (once) before beforeCreate, and the component object has not been created yet;
    2) This is undefined. data/computed/methods/props cannot be accessed through this;
    3) In fact, it is not allowed in all callback functions related to composition API;
    2. Return value of setup
    1) Generally, an object is returned: provide data for the template, that is, all properties / methods in this object can be directly used in the template
    2) The properties in the return object will be merged with the data function return object to form the properties of the component object
    3) The method in the returned object will be merged with the method in methods, and the method of the component object will be merged successfully
    4) If there are duplicate names, setup takes precedence
    5) Note: generally, do not mix them: you can access the properties and methods provided by setup in methods, but you cannot access data and methods in setup method; Setup cannot be an async function: because the return value is no longer the return object, not promise, the template cannot see the attribute data in the return object
    3.setup parameters
    1)setup(props,context)/setup(props,{attrs,slots,emit})
    2) Props: an object that contains the props configuration declaration and passes in all properties
    3) Attrs: object containing attributes not declared in props configuration, equivalent to this.$attrs
    4) Slots: an object containing all the incoming slot contents, equivalent to this.$slots
    5) Emit: a function used to distribute custom events, equivalent to this.$emit
<template>
  <h2>App</h2>
  <p>msg: {{msg}}</p>
  <button @click="fn('--')">to update</button>

  <child :msg="msg" msg2="cba" @fn="fn"/>
</template>
<script lang="ts">
import {
  reactive,
  ref,
} from 'vue'
import child from './child.vue'

export default {

  components: {
    child
  },

  setup () {
    const msg = ref('abc')

    function fn (content: string) {
      msg.value += content
    }
    return {
      msg,
      fn
    }
  }
}
</script>
<template>
  <div>
    <h3>{{n}}</h3>
    <h3>{{m}}</h3>

    <h3>msg: {{msg}}</h3>
    <h3>msg2: {{$attrs.msg2}}</h3>

    <slot name="xxx"></slot>

    <button @click="update">to update</button>
  </div>
</template>
<script lang="ts">

import {
  ref,
  defineComponent
} from 'vue'

export default defineComponent({
  name: 'child',

  props: ['msg'],

  emits: ['fn'], // Optionally, the declaration is easier for programmers to read, and the distributed event data can be verified

  data () {
    console.log('data', this)
    return {
      // n: 1
    }
  },

  beforeCreate () {
    console.log('beforeCreate', this)
  },

  methods: {
    // update () {
    //   this.n++
    //   this.m++
    // }
  },

  // setup (props, context) {
  setup (props, {attrs, emit, slots}) {

    console.log('setup', this)
    console.log(props.msg, attrs.msg2, slots, emit)

    const m = ref(2)
    const n = ref(3)

    function update () {
      // console.log('--', this)
      // this.n += 2 
      // this.m += 2

      m.value += 2
      n.value += 2

      // Distribute custom events
      emit('fn', '++')
    }

    return {
      m,
      n,
      update,
    }
  },
})
</script>
  • reactive and ref details
    1) It is the most important responsive API in vue3's composition API
    2) ref is used to process basic types of data, and reactive is used to process objects (recursive deep response)
    3) If you use ref object / array, the object / array will be automatically converted into a reactive proxy object
    4) ref internal: hijack the data by adding getter/setter to the value attribute
    5) reactive internal: hijack all data inside the object by using Proxy, and operate the internal data of the object through Reflect
    6) ref data operation: you need. value in js, but not in the template (the. value will be added automatically when the template is internally parsed)
<template>
  <h2>App</h2>
  <p>m1: {{m1}}</p>
  <p>m2: {{m2}}</p>
  <p>m3: {{m3}}</p>
  <button @click="update">to update</button>
</template>
<script lang="ts">
import {
  reactive,
  ref
} from 'vue'

export default {

  setup () {
    const m1 = ref('abc')
    const m2 = reactive({x: 1, y: {z: 'abc'}})

    // Using ref to process objects = = > objects will be automatically reactivated as proxy objects
    const m3 = ref({a1: 2, a2: {a3: 'abc'}})
    console.log(m1, m2, m3)
    console.log(m3.value.a2) // It is also a proxy object

    function update() {
      m1.value += '--'
      m2.x += 1
      m2.y.z += '++'

      m3.value = {a1: 3, a2: {a3: 'abc---'}}
      m3.value.a2.a3 += '==' // reactive depth data hijacking of the object
      console.log(m3.value.a2)
    }

    return {
      m1,
      m2,
      m3,
      update
    }
  }
}
</script>
  • Computing properties and monitoring
<template>
  <h2>App</h2>
  fistName: <input v-model="user.firstName"/><br>
  lastName: <input v-model="user.lastName"/><br>
  fullName1: <input v-model="fullName1"/><br>
  fullName2: <input v-model="fullName2"><br>
  fullName3: <input v-model="fullName3"><br>

</template>
<script lang="ts">
/*
Computing properties and monitoring
1. computed Function: 
  Consistent with the function of computed configuration
  Only Getters
  There are getter s and setter s
2. watch function
  Consistent with the watch configuration function
  Monitor one or more specified responsive data. Once the data changes, the monitoring callback will be executed automatically
  By default, the callback is not executed initially, but you can specify that the first callback is executed immediately at the initial time by configuring immediate to true
  Specify deep monitoring by configuring deep to true
3. watchEffect function
  Instead of directly specifying the data to be monitored, the responsive data used in the callback function can be monitored
  By default, the first time is executed initially, so that the data to be monitored can be collected
  Callback when monitoring data changes
*/

import {
  reactive,
  ref,
  computed,
  watch,
  watchEffect
} from 'vue'

export default {

  setup () {
    const user = reactive({
      firstName: 'A',
      lastName: 'B'
    })

    // Only the calculated property of getter
    const fullName1 = computed(() => {
      console.log('fullName1')
      return user.firstName + '-' + user.lastName
    })

    // Calculation properties with getter and setter
    const fullName2 = computed({
      get () {
        console.log('fullName2 get')
        return user.firstName + '-' + user.lastName
      },

      set (value: string) {
        console.log('fullName2 set')
        const names = value.split('-')
        user.firstName = names[0]
        user.lastName = names[1]
      }
    })

    const fullName3 = ref('')

    /* 
    watchEffect: Monitor data used in all callbacks
    */
    /* 
    watchEffect(() => {
      console.log('watchEffect')
      fullName3.value = user.firstName + '-' + user.lastName
    }) 
    */

    /* 
    Two features of watch are used:
      Depth monitoring
      Initialization is executed immediately
    */
    watch(user, () => {
      fullName3.value = user.firstName + '-' + user.lastName
    }, {
      immediate: true,  // Whether to initialize and execute immediately. The default is false
      deep: true, // Whether it is depth monitoring. The default is false
    })

    /* 
    watch One data
      By default, the callback is executed when the data changes
    */
    watch(fullName3, (value) => {
      console.log('watch')
      const names = value.split('-')
      user.firstName = names[0]
      user.lastName = names[1]
    })

    /* 
    watch Multiple data: 
      Use an array to specify
      If it is a ref object, specify it directly
      If it is an attribute in a reactive object, it must be specified through a function
    */
    watch([() => user.firstName, () => user.lastName, fullName3], (values) => {
      console.log('Monitor multiple data', values)
    })

    return {
      user,
      fullName1,
      fullName2,
      fullName3
    }
  }
}
</script>
  • life cycle
    Composite API corresponding to version 2.x lifecycle
    . Beforecreate = > use setup()
    . Create = > use setup()
    . beforeMount=>onBeforeMount
    . mounted=>onMounted
    . beforeUpdate=>onBeforeUpdate
    . updated=>onUpdated
    . beforeDestroy=>onBeforeUnmount
    . destroyed=>onUnmounted
    . errorCaptured=>onErrorCaptured

  • toRefs
    Convert a responsive object into an ordinary object, and each property of the ordinary object is a ref
    Application: toRefs is very useful when returning a responsive object from a composite function, so that the consumer component can decompose and use the returned object without losing the responsiveness
    Problem: all attribute values retrieved by the reactive object are non responsive
    Solution: using toRefs, you can convert all the original attributes of a reactive object into a reactive ref attribute

<template>
  <h2>App</h2>
  <h3>foo: {{foo}}</h3>
  <h3>bar: {{bar}}</h3>
  <h3>foo2: {{foo2}}</h3>
  <h3>bar2: {{bar2}}</h3>
</template>
<script lang="ts">
import { reactive, toRefs } from 'vue'
/*
toRefs:
  Wrap all the attributes in the responsive object as ref objects and return normal objects containing these ref objects
  Application: toRefs is very useful when returning a responsive object from a composite function,
        In this way, the consumer component can decompose the returned object without losing the response
*/
export default {

  setup () {

    const state = reactive({
      foo: 'a',
      bar: 'b',
    })

    const stateAsRefs = toRefs(state)

    setTimeout(() => {
      state.foo += '++'
      state.bar += '++'
    }, 2000);

    const {foo2, bar2} = useReatureX()

    return {
      // ...state,
      ...stateAsRefs,
      foo2, 
      bar2
    }
  },
}

function useReatureX() {
  const state = reactive({
    foo2: 'a',
    bar2: 'b',
  })

  setTimeout(() => {
    state.foo2 += '++'
    state.bar2 += '++'
  }, 2000);

  return toRefs(state)
}

</script>
  • ref get element
    Use the ref function to get the label element in the component
    Functional requirements: let the input box automatically get the focus
<template>
  <h2>App</h2>
  <input type="text">---
  <input type="text" ref="inputRef">
</template>
<script lang="ts">
import { onMounted, ref } from 'vue'
/* 
ref Get element: use the ref function to get the label element in the component
 Functional requirements: let the input box automatically get the focus
*/
export default {
  setup() {
    const inputRef = ref<HTMLElement|null>(null)

    onMounted(() => {
      inputRef.value && inputRef.value.focus()
    })

    return {
      inputRef
    }
  },
}
</script>

Keywords: TypeScript Vue

Added by furotte on Fri, 12 Nov 2021 22:08:30 +0200