文章

Vue3使用tsx

Vue3 使用 tsx

Vue3使用tsx

Vue3 使用 tsx

安装插件

:::info npm install @vitejs/plugin-vue-jsx -D

:::

vite.config.ts 配置

1
2
3
4
5
6
7
8
9
10
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx';

export default defineConfig({
  plugins: [
    vue(),
    vueJsx()
  ]
})

使用TSX

tsx 不会自动解包使用 ref .vlaue ! ! !

v-model => 支持

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { ref } from 'vue'
 
let v = ref<string>('')
 
const renderDom = () => {
  return (
    <>
       <input v-model={v.value} type="text" />
       <div>
           {v.value}
       </div>
    </>
  )
}
 
export default renderDom

v-show => 支持

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { ref } from 'vue'
 
let flag = ref(false)
 
const renderDom = () => {
  return (
    <>
       <div v-show={flag.value}>景天</div>
       <div v-show={!flag.value}>雪见</div>
    </>
  )
}
 
export default renderDom

v-if => 不支持

需要换一种形式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { ref } from 'vue'
 
let flag = ref(false)
 
const renderDom = () => {
  return (
    <>
      {
        flag.value ? <div>景天</div> : <div>雪见</div>
      }
    </>
  )
}
 
export default renderDom

v-for => 不支持

需要使用Map

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { ref } from 'vue'
 
let arr = [1,2,3,4,5]
 
const renderDom = () => {
  return (
    <>
      {
        arr.map(v=>{
          return <div>${v}</div>
        })
      }
    </>
  )
}
 
export default renderDom

v-bind使用

直接赋值就可以

1
2
3
4
5
6
7
8
9
10
11
12
13
import { ref } from 'vue'
 
let arr = [1, 2, 3, 4, 5]
 
const renderDom = () => {
  return (
    <>
      <div data-arr={arr}>1</div>
    </>
  )
}
 
export default renderDom

v-on

所有的事件都按照react风格来

  • 所有事件有on开头
  • 所有事件名称首字母大写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 
const renderDom = () => {
  return (
    <>
      <button onClick={clickTap}>点击</button>
    </>
  )
}
 
const clickTap = () => {
    console.log('click');
}
 
export default renderDom

插槽的使用

**父组件: **👇

1
2
3
4
5
6
<Page2 v-slots={{  
       aaa: () => <span>123</span> ,
       bbb: () => <span>456</span> 
 }} />

**子组件: **👇

1
2
3
4
5
6
7
 setup(props, { slots }) {
    return () => 
    <div>
       我是插槽aaa:  {slots.aaa && slots.aaa()}  <br>
       我是插槽bbb:  {slots.bbb && slots.bbb()}
    </div>

  • 通过 v-slots 返回对象,对象的每个属性为一个函数 ,返回对应的文本标签
  • 根据函数的名称,调用对应的方法,来放置具名插槽的位置
  • 先做个插槽的判空操作,会更加严谨

两种写法

写法一

不需要 props 来传参 , 简写

1
2
3
4
5
6
7
import { defineComponent } from 'vue';

const renderDom = defineComponent((props, {emits}) => {
  return () => <div> 写法1 </div>
})

export default renderDom
  • defineComponent 去传入一个 函数 ( 会默认为 setup )
  • 写法方便, 因为 无法去定义 props , 所以 props 一直为空对象
  • 但是可以正常使用 emitsslots

写法二

需要 props 传参

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { defineComponent } from 'vue';

const renderDom = defineComponent({
  props:{
	params:{ 
	  type: String, 
	  defualt: ()=> ''
	}	
  },
  setup(props) {
    return () => <div>  写法2  ,  父组件传过来的值 { props.params }  </div>
  }
})

export default renderDom
  • defineComponent 去传入一个 整个对象
  • 可以定义 props ,可以使用 (父组件 => 子组件) 值
  • 复杂的场景,更加推荐,使用起来更加灵活

父子组件通信

**父组件: (Father.jsx) **👇

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { defineComponent, ref } from 'vue';
import Child from './Child.jsx'

export default defineComponent(() => {
  const params = ref('123')
  function getChild(val){ 
  	console.log(val)
  }
 
  return () => <div>
  	 <h3>子组件↓ </h3>
    <Child params={params.value} onFather={getChild}  />
  </div>;
})

**子组件 : (Child.jsx) **👇

1
2
3
4
5
6
7
8
9
10
11
12
13
import { defineComponent, ref } from 'vue';

export default defineComponent({
  props: ['params'],
  setup(props , { emit }) {
  	const text = ref('传给父组件的值')
    return () => 
    <div>
      父组件传来的值: { props.params }
      <button onClick = {()=>{ emit('father', text.value) } }> 传给 father </button>
    </div>
  }
})
  • 第二种可以定义 props 的写法,才可以接收 父组件传递的参数
  • **emit** 给父组件通信,父组件自定义 方法 要 加 on + 大写开头方法

实战代码 - 注册页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import { ref, reactive, defineComponent } from 'vue'
import { useRouter } from 'vue-router'
import { ElButton, ElForm, ElFormItem, ElInput } from 'element-plus'
import type { FormInstance, FormRules } from 'element-plus'
import styles from './index.module.css'

interface RuleForm {
  phone: string
  code: string
  password: string
}

const Register = defineComponent(() => {
  const router = useRouter()
  const ruleForm = ref<FormInstance>()

  const loginForm = reactive<RuleForm>({
    phone: '',
    code: '',
    password: ''
  })

  const rules = reactive<FormRules<RuleForm>>({
    phone: [
      { required: true, message: '请输入手机号', trigger: 'blur' }
    ],
    code: [
      { required: true, message: '请输入验证码', trigger: 'blur' }
    ],
    password: [
      { required: true, message: '请输入密码', trigger: 'blur' }
    ]
  })

  const register = async (formEl: FormInstance | undefined) => {
    if (!formEl) return
    await formEl.validate((valid, fields) => {
      if (valid) {
        console.log('submit!', loginForm)
      } else {
        console.log('error submit!', fields)
      }
    })
  }

  const goLogin = () => {
    router.push('/login')
  }
  return () => <>
    <div class={styles.wrap}>
      <ElForm model={loginForm} rules={rules} ref={ruleForm} label-width='100px' class={styles.loginForm}>
        <ElFormItem>
          <h1 class={styles.title}>注册账号</h1>
        </ElFormItem>
        <ElFormItem label='手机号' prop='phone'>
          <ElInput size='large' v-model={loginForm.phone} placeholder='请输入手机号' />
        </ElFormItem>
        <ElFormItem label='验证码' prop='code'>
          <div class={styles.codeItem}>
            <ElInput size='large' v-model={loginForm.code} placeholder='请输入验证码' />
            <ElButton size='large' type='primary' class={styles.getBtn}>获取验证码</ElButton>
          </div>
        </ElFormItem>
        <ElFormItem label='密码' prop='password'>
          <ElInput size='large' v-model={loginForm.password} show-password placeholder='请输入6~20位密码(字母+数字组合)' />
        </ElFormItem>
        <ElFormItem>
          <ElButton link onClick={goLogin}>已有账号,去登录</ElButton>
        </ElFormItem>
        <ElFormItem>
          <ElButton size='large' type='primary' class={styles.loginBtn} onClick={() => register(ruleForm.value)}>注册</ElButton>
        </ElFormItem>
      </ElForm>
    </div>
  </>
})

export default Register

此处可以不需要 **defineComponent**** 但是使用 useRouter() 等方法时会有警告** 》》》 inject() can only be used inside setup() or functional components.

本文由作者按照 CC BY 4.0 进行授权