Vue2的tsx开发入门完全指南

news2024/11/15 19:38:53

本篇文章尽量不遗漏重要环节,本着真正分享的心态,不做标题党

下面进入正题:

由于现在vue的官方脚手架已经非常完善我们就不单独配置webpack了,节省大量的时间成本。

首先使用@vue/cli创建一个vue模版项目(记得是@vue/cli不是vue-cli还不知道的人可以点此传送门进入先导学习站)。

在自己觉得合适的目录下打开命令行输入如下代码,创建一个名为vue-tsx的项目

接下来的步骤vue的cli会给出相应的配置提示,着重配置已截图

第一步选择自定义配置
在这里插入图片描述
第二步选择如图的配置
在这里插入图片描述
剩下的按个人喜好自己选择就可以了

创建完成后的项目结构如图所示
在这里插入图片描述
从图上看出这是一个普通的vue模版项目,使用typescript语言开发

默认使用的仍然是vue的template进行渲染

正常在这种情况下就可以开发直接写代码了,模版项目所提供的示例代码已经很良心了

不过今天要介绍的是使用tsx语法进行开发vue项目

首先介绍一下什么事tsx

其实他就是typescript的jsx语法

那么什么是jsx呢?从这里介绍的话又变成无脑长文了,所以直接掠过,想了解jsx的人可以先去看一下react的开发文档5分钟上手

,但是必须要说的是为什么要使用tsx来写vue项目?vue提供的自带模版不香吗?网友对vue和react的争论喋喋不休到现在,我在这里给的答案其实很简单,vue和react之间没有好坏之分,论性能差距在使用上已经近乎55开,论生态各自都很完善了,这两个框架并存的原因很简单,vue的作者在自己的文章中曾经也提过,创造vue项目只不过是想有一个“自己用起来顺手的框架”。答案就在这句话上,所以我觉得没必要争论哪个好,其实没有可比性,只是喜欢的人各自会觉得对方好而已。

所以今天介绍tsx开发vue项目其实原因很简单,就是让适应了jsx语法的人能无缝从react过渡到vue上。就是给用起来舒服的人准备了一个方案而已。

所以继续我们的项目搭建

接下来先运行一下刚才的模版项目

在vue-tsx目录下打开命令行输入

npm run serve 

出现如下图片证明以上操作全部没问题
在这里插入图片描述
在这里插入图片描述
以上操作全部通过后可以关闭服务器了,我们下一步要做的是修改项目的目录结构

首先

删除views文件夹,

删空components文件夹的内容保留文件夹,

删除App.vue文件

项目结构与图片一样即可,其他地方暂时不要动
在这里插入图片描述
首先将router文件夹中的index.ts文件内容修改为如下代码

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const routes:any = []

const router:VueRouter = new VueRouter({
  routes
})

export default router 

然后修改main.ts中的代码为如下

import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'

Vue.config.productionTip = false

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app') 

并在src下新建名为App.tsx的文件内容为

import { Vue ,Component } from 'vue-property-decorator';
@Component
export default class App extends Vue{
	render(){
		return (
			<div>I am the first module of tsx for the Vue Project! </div>
		)
	}
} 

其他地方暂时不需要改造

然后重新使用npm run serve启动项目访问默认地址
在这里插入图片描述
当界面出现如上图情况的欢迎语,说明我们已经成功的在vue项目中使用tsx模版语法了

与react一样tsx在vue项目中也是使用render方法混合html模版来实现界面渲染,用法与react一样,他在vue项目中会被解析成vue的render:h => h()形式去渲染页面,所以使用tsx模版开发vue带来的负面影响是我们牺牲了vue自带的很多语法糖,如最基本的v-if,v-for,prop.sync等等,不过他带来的好处是我们可以使用tsx语法更自由的去处理这些问题,并且使用tsx可以进行更好的抽象以及工程化的去处理前端项目,各有千秋。

我们在下文会详细的介绍相关内容,首先还是继续进行下去

光使用tsx实现了App.vue相当于没有解决任何问题。

我们下一步要改造的是VueRouter

所以

第一步在src下创建一个名为pages的文件夹

第二步在pages下分别创建Index.tsx,以及Login.tsx两个文件

成功后如下图
在这里插入图片描述
分别在两个文件中输入默认代码

Login.tsx

import { Vue , Component } from 'vue-property-decorator'
@Component
export default class Login extends Vue{
	render(){
		return (
			<div>login.tsx</div>
		)
	}
} 

Index.tsx

import { Vue , Component } from 'vue-property-decorator'
@Component
export default class Index extends Vue{
	render(){
		return (
			<div>index.tsx</div>
		)
	}
} 

然后我们把这两个路由的页面加入到router中

在router文件夹下的index.ts中加入如下代码

import Vue from 'vue'
import VueRouter from 'vue-router'
import Index from '@/pages/Index'
Vue.use(VueRouter)

const routes:Array<any> = [
	{
		path:'/',name:'index',component:Index
	},
	{
		path:'/login',name:'login',component:() => import('@/pages/Login')
	}
]

const router:VueRouter = new VueRouter({
  routes
})

export default router 

这里我们子啊router中使用了直接引用和懒加载两种方式去加载路由界面来测试vue对tsx的兼容性

最后一步修改App.tsx,在文件中加入路由的容器,代码如下

import { Vue ,Component } from 'vue-property-decorator';
@Component
export default class App extends Vue{
	render(){
		return (
			<div>
				<router-view></router-view>
			</div>
		)
	}
} 

以上步骤严格按照说明编写后,无需重启服务我们访问默认路径就可以看到变化(如中途遇见问题可重启服务)

在访问http://localhost:8080/#/,以及http://localhost:8080/#/login两个地址分别显示如下图就说明成功了,如有问题请自行检查在这里插入图片描述
在这里插入图片描述
到这里我们已经实现了所有页面使用tsx来替换vue模版

到目前渲染数据都没有问题,但是我们还没有设置页面的样式,下面就介绍一下如何在tsx中使用css样式

由于我在创建项目的时候使用的是node-sass来加载sass-loader所以这里我们使用的scss模版来编写css

App.tsx为例,介绍 一下如何使用scss在tsx中

第一步在src下创建一个名为App.module.scss的文件(中间一定要加.module,这个是vue脚手架的规范,如果想自由命名请熟读@vue/cli的官方文档,本文我们暂时采取默认方式)在其中设置如下样式

.app{
	background: lightblue;
}

第二步改造App.tsx的代码给根标签加一个class=“App”

import { Vue ,Component } from 'vue-property-decorator';
//以模块的形式引入当前的样式文件
import style from './app.module.scss';
@Component
export default class App extends Vue{
	render(){
		return (
		//这里代表将app.module.scss中的.app这个class注入到标签中
			<div class={style.app} >
				<router-view></router-view>
			</div>
		)
	}
} 

我们会发现当前的网页背景颜色会变成我们设置的light-blue如图所示
在这里插入图片描述
但是这里有一个问题,观察当前node命令行窗口会发现Cannot find module ‘./App.module.scss’.错误

这个错误是由于当前的项目默认是不认识scss语法的,我们需要在项目src下的shims-vue.d.ts文件中加入如下代码并重启服务

declare module '*.vue' {
	import Vue from 'vue'
	export default Vue
}
//解决scss文件报错问题
declare module '*.scss'{
	const sass:any
	export default sass
} 

执行此方法后就不会报错了

接下来我们来测试一下如何使用tsx中的scss

首先我们试试可不可以在样式中对html和body标签进行操作,App.module.scss修改为如下

html,body{
	width: 100%;
	height: 100%;
	margin: 0;
	color: red;
}
.app{
	background: lightblue;
	height: 100%;
} 

当我们重新访问页面时出现下图结果
在这里插入图片描述
接下来我们给Index.tsx中的代码修改一下,测试一下可不可以用App.module.scss影响他的子组件,加入index-page的className

import { Vue , Component } from 'vue-property-decorator'
@Component
export default class Index extends Vue{
	render(){
		return (
			<div class="index-page">index.tsx</div>
		)
	}
} 

然后在App.module.scss中设置

html,body{
	width: 100%;
	height: 100%;
	margin: 0;
	color: red;
}
.app{
	background: lightblue;
	height: 100%;
	.index-page{
		text-align: center;
		color: blue;
	}
} 

访问页面后,index.tsx的字体并没有居中也没有变色,查看控制台发现样式并没有注入进来,看来当前的模块引入影响的只是当前组件本身,不过在vue的模版中的style标签下可以通过/deep/的方式来实现样式的跨组件穿透,如果我一定要在App.module.scss中设置其他组件的公共样式,把它当成一个基础样式组件来用呢?当然有解决方案,我们只需要做一个简单的修改

html,body{
	width: 100%;
	height: 100%;
	margin: 0;
	color: red;
}
.app{
	background: lightblue;
	height: 100%;
/*穿透效果*/
	:global(.index-page){
		text-align: center;
		color: blue;
	}
} 

使用:global就可以实现/deep/的功能
在这里插入图片描述
到这里样式的基本使用介绍完毕。

接下来是核心环节,就是关于自定义组件以及在vue中如何使用ts开发

修改index.tsx的内容为

import { Vue , Component } from 'vue-property-decorator'
@Component
export default class Index extends Vue{
	//相当于js中的data中的其中一个属性
	private title?:string = '我是标题'

	private author?:string = 'LeoZhang'
	//相当于computed中的函数
	get authorComputed(){
		return `作者是:${this.author}`
	}
	render(){
		return (
			<div class="index-page">
				<h2>{this.title}<small>by {this.author}</small></h2>
				<p>{this.authorComputed}</p>
			</div>
		)
	}
} 

在这里插入图片描述
当前内容输入成功说明你已经习惯了ts与js的区别,这个结构体现出了ts更加清晰的结构化代码

接下来我们测试一下methods与v-model如何实现

Index.tsx修改为如下内容

import { Vue , Component } from 'vue-property-decorator'
import style from './index.module.scss';
@Component
export default class Index extends Vue{
	//相当于js中的data中的其中一个属性
	private title?:string = '我是标题'

	private author?:string = 'LeoZhang'
	//相当于computed中的函数
	get authorComputed(){
		return `作者是:${this.author}`
	}
	//生命周期函数
	created(){
		console.log('我是默认的生命周期')
	}
	//相当于methods
	handleClick(arg:string):void{
		this.title = arg;
	}
	render(){
		return (
			<div class="index-page">
				<h2>{this.title}<small>by {this.author}</small></h2>
				<p>{this.authorComputed}</p>
				<button class={style['p-btn']} onClick={this.handleClick.bind(this,'我是新标题')}>改变标题</button>
				<br/>
				测试v-model改变author
				<input v-model={this.author}/>
			</div>
		)
	}
} 

在这里插入图片描述
测试结果为上图内容

可以看出当前的tsx语法中v-model还是被继续支持的不过v-on和v-bind都有相应的变化这里首先看到的是v-on变成了on事件名的写法,而且给事件传参数使用的是.bind这里与vue自带的template是完全不一样的

接下来我们在login.tsx中引入一个自定义组件来看一下自定义组件的参数和一些内容是否有变化

首先在components中声明一个Test组件
在这里插入图片描述
组件代码如下

import {
	Vue,
	Prop,
	Watch,
	Emit,
	Model,
	Component
} from 'vue-property-decorator'
@Component
export default class Test extends Vue{
	//代表js的props属性可在注解中设置类型是否必填默认值等
	@Prop({required:false,type:String,default:'我是默认值'})
	private msg?:string;

	render(){
		return (
			<div class="test">
				{this.msg}
			</div>
		)
	}
} 

然后在Login.tsx中做如下修改

import { Vue , Component } from 'vue-property-decorator'
import Test from '@/components/Test';
@Component
export default class Login extends Vue{

	private title?:string = '我是Login页面'

	render(){
		return (
			<div>
				{this.title}<br/>
				<Test></Test>
			</div>
		)
	}
}

此时访问http://localhost:8080/#/login

如果显示为如下图就说明已经配置成功一个基础组件了
在这里插入图片描述
我们测试给定义的组件msg传入一个参数

import { Vue , Component } from 'vue-property-decorator'
import Test from '@/components/Test';
@Component
export default class Login extends Vue{

	private title?:string = '我是Login页面'

	private msg:string = '我是login传入的msg'

	render(){
		return (
			<div>
				{this.title}<br/>
				<Test msg={this.msg}></Test>
			</div>
		)
	}
}

之后页面的值如果变为如图,说明成功
在这里插入图片描述
不过此处会在node控制台报错,错误说明是检测不到有msg这个参数类型因为这个参数是我们后创建的vue在默认的组件中是检测不到的所以为了让框架能不管我们自己创建的参数我们需要在shims-tsx.d.ts文件中加入如下代码

declare module "vue/types/options" {

  interface ComponentOptions<V extends Vue> {

	[propName: string]: any;

  }
}

之后重启服务,这样我们自定义组件的参数就不会出现报错了

之后我们再测试一下给组件绑定v-model如何实现双向绑定并监听参数

将Test.tsx的代码修改为如下,代码注释已经添加到代码中了

import {
	Vue,
	Prop,
	Watch,
	Emit,
	Model,
	Component
} from 'vue-property-decorator'
@Component
export default class Test extends Vue{
	//代表js的props属性可在注解中设置类型是否必填默认值等
	@Prop({required:false,type:String,default:'我是默认值'})
	private msg?:string;
	//Model装饰器相当于model属性参数相当于给event赋值,装饰器设置的属性相当于设置prop属性
	@Model('cc')
	@Prop({required:false,type:String,default:'我是双向绑定的默认值'})
	private value?:string;
	//相当于调用this.$emit('cc',val)
	@Emit('cc')
	sendValue(val:string){}
	//相当于watch下监听value属性的变化
	@Watch('value')
	handleWatchValue(newVal:string,oldVal:string){
		console.log(newVal,oldVal);
	}

	handleInput(event:InputEvent){
		//相当于调用this.$emit('cc',val)
		this.sendValue(event.target.value);
	}

	get getValue(){
		return `组件内部的value:${this.value}`
	}
	render(){
		return (
			<div class="test">

				{this.msg}<br/>

				<input value={this.value}
					onInput={this.handleInput}/>
				<br/>
				{this.getValue}
			</div>
		)
	}
}

然后在Login.tsx中修改为如下代码

import { Vue , Component } from 'vue-property-decorator'
import Test from '@/components/Test';
@Component
export default class Login extends Vue{

	private title?:string = '我是Login页面'

	private msg:string = '我是login传入的msg'

	private value:string = '我是外部传入的value'

	get getValue(){
		return `组件外部的value:${this.value}`
	}

	render(){
		return (
			<div>
				{this.title}<br/>
				{this.getValue}
				<Test msg={this.msg} v-model={this.value}></Test>
			</div>
		)
	}
}

成功后会得到如下结果

在这里插入图片描述

可以看到在Test组件中创建的input标签可以触发value属性的变化,并同时通知了外部传入的value属性进行变更,大量使用ts的装饰器(与java中的注解原理类似)这样可以更加直观的进行逻辑归纳,适合结构化开发。

到这里vue+tsx的基本入门关已经过了,掌握本文的技巧之后便开启了vue的tsx之旅。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/376454.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Dockerfile详解

一、能干嘛&#xff1f; 我们总会遇到下面这种情况&#xff1a;使用docker pull 拉取下来的镜像发现其提供的功能并不完善&#xff0c;比如拉下来个centos的镜像&#xff0c;运行该镜像生成容器发现连vim&#xff0c;ifconfig命令都没有&#xff01;想要在该镜像的基础上扩充其…

[SQL]增删查改语法概览

数据定义 基本概念 基本表 本身独立存在的表SQL中一个关系就对应一个基本表一个(或多个)基本表对应一个存储文件一个表可以带若干索引 存储文件 物理结构对用户透明索引存放在存储文件中 视图 从一个或几个基本表导出的表数据库中至存放数据的定义而不存放视图对应的数据视…

Moonlight iPad全屏无边框串流方法

环境&#xff1a;iPad MoonLight 串流PC 问题&#xff1a;iPad无法全屏&#xff0c;有边框 解决办法&#xff1a;将电脑分辨率和MoonLight自定义分辨率调整为iPad原始分辨率 背景&#xff1a;在使用iPad进行MoonLight串流PC游戏时&#xff0c;发现客户端不论如何设定iPad都有边…

SQL函数

SQL函数 DATE_SUB()函数 1.1函数语法定义 1.2函数实际应用&#xff1a; 语法: 获取当前日期&#xff1a;select curdate()获取当前日期前一天&#xff1a;select date_sub(curdate(),interval 1 day)获取当前日期后一天&#xff1a;select date_sub(curdate(),interval -1 …

mysql(一) 使用注意事项及优化

初学mysql的时候、写了一份 "什么是CRUD&#xff1f; CRUD的操作" 的文章&#xff08;18年的&#xff09; 我开心看到有朋友经常在下面讨论一些问题、 但是以现在&#xff08;今天 23年&#xff09;回头看觉得 那些只是入门需要知道和掌握的、也刚好最近不是很忙 所…

S3C2440开发环境搭建

拿出了之前的S3C2440开发板&#xff0c;然后把移植uboot、移植内核、制作根文件系统、设备树编写驱动等几项再做一遍&#xff0c;这篇文章先记录下环境搭建过程&#xff0c;以及先把现成的uboot、内核、根文件系统下载进去&#xff0c;看看开发板还能不能用&#xff0c;先熟悉一…

【C++】踏入C++的大门(万字总结)

文章目录&#x1f3aa; 踏入C的大门&#x1f680;1.什么是C&#x1f680;2.C发展史&#x1f680;3.C关键字&#x1f680;4.命名空间⭐4.1 命名空间定义⭐4.2 命名空间使用⭐4.3 C输入和输出&#x1f680;5.缺省参数⭐5.1 缺省参数概念⭐5.2 缺省参数分类&#x1f680;6.函数重载…

Unreal Engine10:Character的实现

写在前面 这里主要是介绍一下Character的实现&#xff0c;顺带也介绍一下UE4资源的获取&#xff1b; 一、UE4资源获取 1. 地图的获取 1.1 下载资源 在Epic Games Launcher的虚幻商城中搜索内容&#xff0c;带有环境标签的就主要是地图资源&#xff1b;有一些是免费的资源和…

C#--耗时操作实现UI界面实时更新不阻塞(耗时操作解决窗体卡顿)

前言C#实现窗体加载进度条或者百分比实时显示耗时操作的进度&#xff0c;方法有很多。但是经过我的学习、查找与实际应用&#xff0c;发现Task配合MethodInvoker最为高效便捷。下面我就来结合代码讲一下要注意的问题。基础知识C#在winform上进行耗时操作往往会放置progressbar&…

JavaWeb 实战 01 - 计算机是如何工作的

计算机是如何工作的1. 计算机发展史2. 计算机的基本组成2.1 冯诺依曼体系结构2.2 CPU的内部结构2.3 指令2.3.1 指令表2.3.1.1 寄存器2.3.2 CPU的工作流程2.4 小结3. 操作系统3.1 核心功能3.2 操作系统的软硬件结构3.3 什么是进程 / 任务3.4 进程管理3.4.1 管理3.4.2 PCB : 进程…

Carl2——二叉树

一.定义struct TreeNode {int val;TreeNode *left;TreeNode *right;TreeNode(int x) : val(x), left(NULL), right(NULL) {} };二.遍历深度优先1.1 迭代法【1】前序遍历&#xff08;144&#xff09;class Solution { public:vector<int> preorderTraversal(TreeNode* roo…

小文智能结合ChatGPT的产业未来

最近几个月&#xff0c;由人工智能实验室OpenAI发布的对话式大型语言模型ChatGPT在国内外各大平台掀起了一阵AI狂潮。短短几天时间&#xff0c;其用户量就突破了百万大关&#xff0c;注册用户之多一度导致服务器爆满。 继AI画图之后&#xff0c;ChatGPT成为了新的顶流&#xf…

支付宝二面:使用 try-catch 捕获异常会影响性能吗?

一. JVM异常处理逻辑 Java 程序中显式抛出异常由athrow指令支持&#xff0c;除了通过 throw 主动抛出异常外&#xff0c;JVM规范中还规定了许多运行时异常会在检测到异常状况时自动抛出(效果等同athrow), 例如除数为0时就会自动抛出异常&#xff0c;以及大名鼎鼎的 NullPointe…

论文阅读:NeRF++: ANALYZING AND IMPROVING NEURAL RADIANCE FIELDS

中文标题&#xff1a;分析并提升神经辐射场 提出问题 把NeRF生成的视角图像投影到一个球模型上&#xff08;体密度在球面上为1&#xff0c;其余为零&#xff09;&#xff0c;这个模型可以很好解释训练集&#xff08;左2&#xff09;&#xff0c;但是一旦推广到其他视角&#x…

阶段八:服务框架高级(第五章:服务异步通信-高级篇(RabbitMQ高级))

阶段八&#xff1a;服务框架高级&#xff08;第五章&#xff1a;服务异步通信-高级篇&#xff08;RabbitMQ高级&#xff09;&#xff09;Day-第五章&#xff1a;服务异步通信-高级篇&#xff08;RabbitMQ高级&#xff09;0.学习目标1.消息可靠性1.1.生产者消息确认1.1.1.修改配…

Docker离线部署

Docker离线部署 目录 1、需求说明 2、下载docker安装包 3、上传docker安装包 4、解压docker安装包 5、解压的docker文件夹全部移动至/usr/bin目录 6、将docker注册为系统服务 7、重启生效 8、设置开机自启 9、查看docker版本信息 1、需求说明 大部份公司为了服务安全…

【PostgreSQL的idle in transaction连接状态】

在平时查询pg_stat_activity这个视图的时候&#xff0c;每一行包含了一个进程的相关信息&#xff0c;包含当前正在执行的SQL&#xff0c;或者会话的状态等等&#xff0c;state字段表示当前进程的状态。在PostgreSQL数据库里&#xff0c;其实代码里总共定义了7种BackendState&am…

手推式洗地机什么牌子好?洗地机品牌排行榜

当今潮流下&#xff0c;大家都开始纷纷追求高品质的居家生活&#xff0c;洗地机也成为越来越多人的追求&#xff0c;因为和传统的吸尘器相比&#xff0c;洗地机除了有扫地的功能之外&#xff0c;还可以轻松搞定家里的拖地任务&#xff0c;下面我们一起来看看洗地机排行榜都有哪…

怎么把音乐传到苹果手机上?如何将铃声导入iphone

很多人肯定都有这样的经验—比起电脑&#xff0c;使用iPhone和iPad播放音乐能获得更好的声音体验。 因此&#xff0c;现在有越来越多的用户将音乐传输到iPhone/iPad上播放。怎么把音乐传到苹果手机上&#xff1f;把音乐导入苹果手机&#xff0c;主要有2种方法&#xff1a;一种是…

【python】运算符,有关它的一切,都在这里了

Python运算符嗨害大家好鸭&#xff01;我是小熊猫~什么是运算符&#xff1f;Python算术运算符Python比较运算符Python赋值运算符Python位运算符Python逻辑运算符Python成员运算符Python身份运算符Python运算符优先级嗨害大家好鸭&#xff01;我是小熊猫~ 源码资料电子书:点击此…