(给前端开发爱好者加星标,提升前端技能)
转自:海天酱油_沃利贝尔
https://juejin.cn/post/6911883529098002446
前言
原因:闲的。还有一个原因吗?嘿嘿
然后之前就说过了,我拿vue3直接干公司项目了,是内部的孵化项目,客户不多,但是也是正规的生产项目。
技术栈说明:
公司项目:js,element-plus,vue3,jsx,常规template,按需加载(单独领出来是因为这个也会导致你的项目填坑变多)
个人组件库研究项目:TypeScript,vue3,jsx,常规template
主要讲公司项目吧,公司项目上线一个月。还算稳定,不过我需要给没能力填坑的大家看一个截图。
element-plus提交issues
vue3提交issues
这里澄清下,vue3的bug其实目前来说可以说没有,单独我发现的方面,但是在使用过程中elementUI组件配合下发现了一个。这里提交的问题其实有一个核心处理点。其他都算是单纯的提问,不是bug。
小总结
可以上生产,但是要有一定填坑能力。但是时间够你折腾,那么就早点学起来吧。
一、vue3生产注意点
1、不能使用getCurrentInstance的ctx
大家在获取app.config.globalProperties.ELEMENT这里设置的ELEMENT这里设置的ELEMENT是要如下
这里的ctx不是steup里面提供的ctx,而是
const { ctx } = getCurrentInstance()
这里ctx在生产环境下是获取不到的,请各位没玩过生产的别误人子弟,这还是我专门给vue3提交issues问来的。
正确应该使用
const { proxy } = getCurrentInstance()
关于在ts中使用
在ts里面大家估计经常会遇到类型定义错误问题。
使用方式1
interface ProxyEx extends ComponentPublicInstance {
$test: number
}
export default defineComponent({
setup(props, ctx) {
const self = getCurrentInstance() as ComponentInternalInstance
const proxy = self.proxy as ProxyEx
console.log(proxy?.$test)
return {}
},
})
使用方式2
上述方案把类型定义到了页面内部,也可以弄一个全局文件去调用。但是总是不方便的。还有就是我们去扩展@vue/runtime-core文件,
然后我们可以在main.ts文件下面增加这段,也不会产生全局错误了
declare module '@vue/runtime-core' {
interface ComponentCustomProperties {
$test: number
}
}
但是不能放在d.ts文件下面,否则会全局产生错误。我翻了好久的issues也没有找到方案。看官方后续优化解决吧。
二、jsx教学开始
关于jsx的官方教学地址:https://vue3js.cn/docs/zh/guide/render-function.html#jsx
git部分:https://github.com/vuejs/jsx-next/blob/dev/packages/babel-plugin-jsx/README-zh_CN.md
我这里就不放关于h函数的处理了,就直接用和react一样的编码方式来书写。主要是vue3的cli已经内置好了babel插件,也就是说大家不需要单独去引入babel插件。直接可以使用。
也就是大家可以这样写vue文件来书写jsx代码。这里我贴上简单示例
Template对比
简单示例
1、注意事项
1、html代码的js文件或者ts文件后缀名增加‘x’,原本是.js变成.jsx,ts变成.tsx
2、.vue文件的script标签增加 lang="tsx",这个呢是你里面存着jsx写法的就需要加。
比如这种情况
{{ de }}
3、常规jsx语法下是无法配合scpoedCss使用的,解决方法等下就讲
2、在.vue文件下面让你的jsx代码也可以使用scopedCss
也就是大家经常在css部分加的这个
**来源:***github.com/vuejs/jsx-n…
原理:只要取到 __scopeId, 就可以在 setup/render 函数中
其中可以得到__scopeId的方式
方案1:
// main.js
import { createApp } from 'vue';
import App from './App.vue'
createApp(App(App)).mount('#app') // 这里将 App 传回组件
// ./App.vue
export default ({ __scopeId }) => {
// 这里可以取到 __scopeId
})
方案2:
// ./App.vue
export default {
render(ctx) {
// ctx._.type.__scopeId
}
}
方案3: setup 可以返回一个 render 方法, 用于 render jsx
// ./App.vue
export default {
setup() {
return (ctx) {
// ctx._.type.__scopeId
}
}
}
上面的实现对于大家比较抽象,我这里提供一个自己的实现方式
然后附上template对比
简单示例
关于像cssModule,css-in-js等方案大家就自行研究。
3、关于class和style样式
这里提醒一下,大家不太会用的直接拿react代码套进来也可以。也就是你可以直接搜索react使用方式,然后这里一样可以用。就是注意下比如className和class这种区别。语法上两者真的差异不大
class部分使用和template部分没有差别
或者
动态方式就不太一样
style部分如果是没有动态的那么和普通的写法没差异
但是动态的需要是这样的
4、在jsx里面使用ref,reactive等
import { defineComponent, ref, reactive } from 'vue'
const Testref = defineComponent({
setup(props, ctx) {
const dateone = ref('测试')
const datetwo = reactive({
test: '测试',
})
return () => (
{dateone.value}
{datetwo.test}
)
},
})
template对比
{{ dateone }}
{{ test }}
复制代码
5、使用插槽和具名插槽
官方:https://vue3js.cn/docs/zh/guide/component-slots.html#插槽内容
const testslot = defineComponent({
setup(props, ctx) {
return () => (
{/*默认插槽*/}
{ctx.slots.default && ctx.slots.default()}
{/*具名插槽*/}
{ctx.slots.name && ctx.slots.name()}
)
},
})
template对比
6、作用域插槽使用
官方地址:https://vue3js.cn/docs/zh/guide/component-slots.html#作用域插槽
传参
const TestA = defineComponent({
setup(props, ctx) {
return () =>
{ctx.slots.default && ctx.slots.default('作用域传参')}
},
})
使用
const TestD = defineComponent({
setup(props, ctx) {
return () => (
组件:TestD v-slots={{
default: (n: string) => {n},
}}
/>
)
},
})
template对比
**传参
**
使用
{{ slotProps}}
7、v-if 和 v-for
官方:https://vue3js.cn/docs/zh/guide/render-function.html#v-if-和-v-for
const iffor = defineComponent({
setup(props, ctx) {
const ces = true
const ifelse = () => {
if (ces) return
if部分
else return
else部分
}
const forarr = () => {
let i = 0
return new Array(10).fill('').map(() => {
i++
return {i}
})
}
return () => (
{ifelse()}
{forarr()}
)
},
})
template对比
{{ item.name }}
No items found.
8、v-model的使用
template部分我就不放了,太简单了
9、jsx情况下可以不要.vue文件示例
示例1:
export const TestCom = defineComponent({
setup(props, ctx) {
return () =>
},
})
示例2:
import { ref } from 'vue'
interface Props {
text: string
}
// ref不能放在组件内部,否则会重新赋值,导致不会响应式变化
const num = ref(1)
const dataone = ref('测试无defineComponent数据变化')
const addnum = () => {
num.value++
}
const inpt = ref('')
const onInput = () => {
console.log(inpt.value)
}
const NoDcom = (props: Props, ctx: any) => {
//console.log(props, ctx)
return (
{dataone.value}
点击测试数据变化
变化的数字{num.value}
)
}
export default NoDcom
10、关于在vue文件组件注册
注意jsx的文件就不要加jsx后缀了
使用和常规的组件注册一样
import { TestCom } from './Test'
export default defineComponent({
components: { TestCom},
setup(props, ctx) {
return {}
},
})
11、关于click事件之类
原本模板中是@click,全部改为onClick模式,和react比较相似
举例
template
12、使用Teleport
在jsx下使用vue内置的组件需要额外导入组件,并且名称不能变。
import { defineComponent, Teleport } from 'vue'
// 使用Teleport
const teleportCum = defineComponent({
setup(props, ctx) {
return () => (
teleport值
)
},
})
Template使用
并且是不需要单独导入,也没有大小写区分的问题
13、使用Transition
和使用teleport一样,就不单独写代码了。上面的例子一样,把Teleport换成Transition就可以跑了
14、关于指令修饰符
官方自带的指令修饰符方面是说类似自己实现
地址:https://v3.cn.vuejs.org/guide/render-function.html#v-on
然后我个人在项目中因为自定义了一个可以随意拖动的v-move指令,并且定义了boundary修饰符代表是否可以只在父元素范围内移动。这时候就很烦了
最后多方百度下至少自定义的指令修饰符是通过“_”连接,如下
{ctx.slots.default && ctx.slots.default()}
而template里面
三、关于jsx和常规的sfc(vue文件方式)
写到这里,说实在我有点想不到该写什么。jsx给我的感觉就是在用react语法。为什么呢?因为这个babel插件是阿里团队优先搞出来了,然后大家都知道阿里是react技术栈为主的。所以语法上面靠近react。
我说说我的几个见地吧
1、jsx并没有更加方便,只是让你更接近vue模板渲染的底层原理
2、jsx语法灵活很多,光我上面就出现了两种jsx书写方式,个人还是推荐defineComponent方式,更加是一个整体
3、jsx书写会比较强迫的让你把for循环等小逻辑模板单独成为一个函数,优点就是颗粒度更小了,和sfc书写方式相比,没有那么方便。
特别是什么呢,我上面的提供方式优点不方便在return部分写逻辑,如果你写if会报错,官方方面都是用的render方式,其实两者的差异并不大
4、如果你用vue那么jsx可以作为一种优化方式(官方推荐使用template方式意味着,template方式bug会优先解决),而不是大规模使用。特别是中小公司,大公司也好不到哪里去。除了业内头部公司,有几个团队能完全规范化的呢?
这里我说一句话:何不食肉糜?
要是全用jsx,那我还是用react吧。何况react薪资更高呢
5、jsx一定要学,但是ts更要学。虽然未来一定不是ts的天下(浏览器领域),但是ts所带来的影响已经把中高端领域覆盖。
6、学习jsx是让你拓宽视野,react生态毕竟是领头羊。
四、关于vue3书写方式,我想新手很容易写出这种代码吧。
放一个我个人封装的组件地址:https://github.com/ht-sauce/visualization/tree/master/src/componentsLibrary/Popper
文档地址:https://www.yuque.com/cv8igf/oy3c8b/uy5sqv
这恐怕就是大佬所担心的面条式代码,说白了,这就是vue2所带来的习惯。vue3的情况下,那么props,函数,响应式部分都是可以抽离到单独的js文件,但是vue2恐怕只能抽离props部分了。
五、致谢
谢谢大家观看。喜欢的点个赞。
觉得本文对你有帮助?请分享给更多人或点个在看
关注==>>「前端开发爱好者」,一起提升前端技能!
? 「赞」、「在看」、「转发」支持一下