Vue3 + TypeScript 开发实践总结
<p><img src="https://img-hello-world.oss-cn-beijing.aliyuncs.com/imgs/70ef8457e498f95b0733b1fa8238842a.png"></p><h2 id="前言">前言</h2>
<p>迟来的Vue3文章,其实早在今年3月份时就把Vue3过了一遍。<br>在去年年末又把 <code>TypeScript</code> 重新学了一遍,为了上<code> Vue3</code> 的车,更好的开车。<br>在上家公司4月份时,上级领导分配了一个内部的 <code>党务系统开发</code> ,这个系统前端是由我一个人来开发,功能和需求也不怎么复杂的一个<code>B 端</code> 系统,直接上的 <code>Vue3</code> + <code>TypeScript</code> + <code>Element Plus</code> 开发的,开发两周到最后的上线,期间也遇到很多小坑,很多无处可查,慢慢琢磨最后还是克服了。</p>
<h2 id="vue3--typescript-study">Vue3 + TypeScript Study</h2>
<p><img src="https://img-hello-world.oss-cn-beijing.aliyuncs.com/imgs/62b80c2a28d16c435facbbfb801725b8.png"></p>
<h3 id="一-环境配置">一, 环境配置</h3>
<h4 id="11-安装最新-vue-脚手架">1.1 安装最新 Vue 脚手架</h4>
<pre><code class="language-javascript">npm install -g @vue/cli
yarn global add @vue/cli
</code></pre>
<h4 id="12-创建vue3--项目">1.2 创建Vue3项目</h4>
<pre><code class="language-javs">vue create projectName
</code></pre>
<h4 id="_"></h4>
<h4 id="13-现有vue-2-项目-升级到-vue3">1.3 现有Vue 2 项目 升级到 Vue3</h4>
<pre><code class="language-javascript">vue add typescript
</code></pre>
<h3 id="二-进击vue3">二, 进击Vue3</h3>
<h4 id="2-1-vue-2-局限性">2. 1 Vue 2 局限性</h4>
<ol>
<li>
<p>随着组件与组件依赖之间不断变大,组件很难读取和维护</p>
</li>
<li>
<p>没有完美的方法解决跨组件代码重用</p>
</li>
</ol>
<h4 id="22-vue-3-如何解决vue-2-局限">2.2 Vue 3 如何解决Vue 2 局限</h4>
<ol>
<li>组件难以维护管理</li>
</ol>
<p>【在Vue3 中 编写组合函数,使用 Compositon ApisetUp 来解决】</p>
<ol start="2">
<li>没有完美的方法解决跨组件代码重用</li>
</ol>
<h3 id="三vue3-composition-ap-i">三,Vue3 Composition Ap i</h3>
<h4 id="31-关于-composition--api">3.1 关于 CompositionApi</h4>
<p>在Vue3中,也可以不使用 <code> Composition Api</code> 来编写组件,它只是在Vue3 中编写组件中的另一种方法,内部简化了好多操作。</p>
<p>所以你还可以继续使用 Vue2 的方式来 编写 组件。</p>
<h4 id="32-什么时候使用composition-api">3.2 什么时候使用Composition Api</h4>
<ol>
<li>
<p>TypeScript` 的支持</p>
</li>
<li>
<p>编写大型组件时,可以使用 <code> Composition Api</code> 组合函数很好的管理状态</p>
</li>
<li>
<p>跨组件重用代码时</p>
</li>
</ol>
<h3 id="四composition-api-必备基础">四,<code>Composition Api 必备基础</code></h3>
<h4 id="41-什么是-setup">4.1 什么是 <code>setup</code></h4>
<p>setup 是用来配置组件状态的另一种实现。</p>
<p>在setup 中定义的状态,方法要想在模板中使用,必须 <code>return</code></p>
<h4 id="注意">注意:</h4>
<ul>
<li><code> setup</code> 方法是在 <code> components</code> , <code> props</code> <code>data</code><code> Methods</code> <code> Computed</code><code> Lifecyclemethods</code>之前执行</li>
<li>同时在 <code> setup</code>中是不能访问 <code> this</code></li>
</ul>
<h4 id="42---ref-创建响应式变量">4.2<code> ref</code> 创建响应式变量</h4>
<p>在 <code> Vue2</code> 中,我们定义一个响应式变量可以直接在 <code> data</code>中 定义并且在模板中使用该变量。 如果 使用的 <code> composition api</code> 的话,我们得在 <code> setup</code>中 使用 <code> ref</code>来创建 响应式变量,并且得将它返回,才能在页面中使用。</p>
<h4 id="使用">使用</h4>
<ul>
<li>
<ol>
<li>引入 <code>ref</code> <code>import { ref } from 'vue'</code></li>
</ol>
</li>
<li>
<ol start="2">
<li>初始变量 <code>const name = ref('指定默认值')</code></li>
</ol>
</li>
<li>
<ol start="3">
<li>返回变量 <code>return {name }</code>在return中还可以返回方法</li>
</ol>
</li>
<li>
<ol start="4">
<li>在 <code> setup</code> 中 访问 定义的变量值,不能直接通过变量名来获取,<code> 必须通过变量名.value 来获取到该对象 、 值</code></li>
</ol>
</li>
</ul>
<h4 id="这样的好处">这样的好处</h4>
<ul>
<li>状态好管理,可以划分好几个 <code> setup</code> 状态管理,最后在一个 文件导入所有,并且使用。</li>
</ul>
<pre><code class="language-javascript"><template>
<div>
<h1>{{title}}</h1>
</div>
</template>
<script>
import {ref,defineComponent} from 'vue'
export default defineComponent({
setup () {
// 定义响应式变量
const title = ref('前端自学社区')
// 访问该变量
console.log(title.value)
// 返回变量
return {title}
}
})
</script>
</code></pre>
<h4 id="43--生命周期">4.3 <code> 生命周期</code></h4>
<p>Composition Api<code>生命周期钩子 和 </code> Vue 2 选项式 生命周期<code>钩子名称一样,只是在使用</code>组合式API<code>时,前缀为</code> on<code>, </code> onMounted`</p>
<p>sd</p>
<p>下面代码中有两个 mounted 生命钩子,你猜哪个会先执行?</p>
<blockquote>
<p><code> setup</code> 会先执行</p>
</blockquote>
<pre><code class="language-javascript"> setup () {
// 定义响应式变量
const title = ref('前端自学社区')
console.log(title)
// 返回变量
function getTitle(){
console.log(title.value)
}
// 页面在加载
onMounted(getTitle)
return {title}
},
mounted() {
console.log('测试 mounted 执行顺序')
},
</code></pre>
<h4 id="44---watch">4.4<code> watch</code></h4>
<p>在 <code> setup</code> 中使用 watch响应式更改</p>
<ul>
<li>
<p>引入 watch, <code> import { watch } from 'vue'</code></p>
</li>
<li>
<p>直接使用watch,watch 接受 3 个参数</p>
<blockquote>
<ol>
<li>要监听更新的 响应式引用或者 getter 函数</li>
<li>一个回调用来做更新后的操作</li>
<li>可选配置项</li>
</ol>
</blockquote>
</li>
</ul>
<pre><code class="language-javascript">import {wathc} from 'vue'
// 定义响应式变量
const num = ref(0)
// 更新响应式变量
functionchangeNum(){
num.value++
}
// wathc 监听响应式变量
watch(
num,(newValue, oldValue) => {
console.log(`newValue为:${newValue},--------oldValue为:${oldValue}`)
}
)
</code></pre>
<h4 id="45--computed">4.5 <code> computed</code></h4>
<p>它也是 从<code> vue</code> 导入,<code>computed</code> 函数返回一个作为 <code>computed</code> 的第一个参数传递的 getter 类回调的输出的一个<em>只读</em>的<strong>响应式引用</strong>。为了访问新创建的计算变量的 <strong>value</strong>,我们需要像使用 <code>ref</code> 一样使用 <code>.value</code> property。</p>
<p>**当num值变化时,nums 的值会 *3 **</p>
<pre><code class="language-javascript">import {ref,computed} from 'vue';
const num = ref(0)
//更新num
functionchangeNum(){
num.value++
}
//监听num变化
const nums = computed(() =>{
return num.value * 3
})
</code></pre>
<h3 id="五setup">五,<code>setup</code></h3>
<h4 id="51-接受两个参数">5.1 接受两个参数</h4>
<p>props<code>:父组件传递过来的属性,</code> setup` 函数中 props 是响应式的,它会随着数据更新而更新,并且不能使用 ES6 解构,因为它会不能使props 为响应式。</p>
<p><code> context</code> : 它是一个普通的 对象,它暴露3个组件的· <strong>property</strong></p>
<blockquote>
<ol>
<li>Attribute</li>
<li>插槽</li>
<li>触发事件</li>
</ol>
</blockquote>
<h4 id="-context-不是-响应式的所以可以使用es6-解构来简便写法"><code> context</code> 不是 响应式的,所以可以使用ES6 解构来简便写法。</h4>
<pre><code class="language-javascript"> props:{
obj:{
type:Object
}
},
setup (props,{attrs,slots,emit}) {
console.log(attrs)
console.log(slots)
console.log(emit)
console.log(props.obj)
}
</code></pre>
<h4 id="52-组件加载--setup-时注意">5.2 组件加载 <code> setup</code> 时注意</h4>
<p>在组件执行 <code> setup</code> 时, 组件实例没有被创建,因此就无法访问以下属性</p>
<ul>
<li><code>data</code></li>
<li><code> computed</code></li>
<li><code>methods</code></li>
</ul>
<h3 id="六生命周期">六,<code>生命周期</code></h3>
<p>在 <code> setup</code> 中使用 生命周期时,前缀必须加 <code> on</code>.</p>
<table>
<thead>
<tr>
<th>选项式 API</th>
<th>Hook inside <code>setup</code></th>
</tr>
</thead>
<tbody>
<tr>
<td><code>beforeCreate</code></td>
<td></td>
</tr>
<tr>
<td><code>created</code></td>
<td></td>
</tr>
<tr>
<td><code>beforeMount</code></td>
<td><code>onBeforeMount</code></td>
</tr>
<tr>
<td><code>mounted</code></td>
<td><code>onMounted</code></td>
</tr>
<tr>
<td><code>beforeUpdate</code></td>
<td><code>onBeforeUpdate</code></td>
</tr>
<tr>
<td><code>updated</code></td>
<td><code>onUpdated</code></td>
</tr>
<tr>
<td><code>beforeUnmount</code></td>
<td><code>onBeforeUnmount</code></td>
</tr>
<tr>
<td><code>unmounted</code></td>
<td><code>onUnmounted</code></td>
</tr>
<tr>
<td><code>errorCaptured</code></td>
<td><code>onErrorCaptured</code></td>
</tr>
<tr>
<td><code>renderTracked</code></td>
<td><code>onRenderTracked</code></td>
</tr>
<tr>
<td><code>renderTriggered</code></td>
<td><code>onRenderTriggered</code></td>
</tr>
</tbody>
</table>
<h3 id="七-跨组件之间传值">七, 跨组件之间传值</h3>
<p>在 <code>Vue 2</code> 中,我们可以使用 <code> Provide/Inject</code> 跨组件传值,在 Vue 3 中也可以。</p>
<p>在 <code> setup</code> 中 使用,必须从 <code> vue</code> 中导入使用。</p>
<p>使用 <code> Provide</code> 时,一般设置为 响应式更新的,这样的话,父组件变更,子组件,子孙组件也跟着更新。</p>
<h4 id="怎么设置为响应式更新呢">怎么设置为响应式更新呢?</h4>
<blockquote>
<ol>
<li>使用 <code> ref</code>/<code>reactive</code>创建响应式变量</li>
<li>使用 <code>provide('name','要传递的响应式变量')</code></li>
<li>最后添加一个更新 响应式变量的事件,这样响应式变量更新,<code> provide</code> 中的变量也跟着更新。</li>
</ol>
</blockquote>
<h4 id="父组件">父组件</h4>
<pre><code class="language-javascript">父组件
import { provide, defineComponent, ref, reactive } from "vue";
<template>
<Son/>
</template>
<script>
import { provide, defineComponent, ref, reactive } from "vue";
export default defineComponent({
setup() {
const father = ref("我父组件");
const info = reactive({
id: 23,
message: "前端自学社区",
});
function changeProvide(){
info.message = '测试'
}
provide('father',father)
provide('info',info)
return {changeProvide};
}
})
</script>
</code></pre>
<h4 id="子组件">子组件</h4>
<pre><code class="language-javascript"><template>
<div>
<h1>{{info.message}}</h1>
<h1>{{fatherData}}</h1>
</div>
</template>
<script>
import {provide, defineComponent,ref,reactive, inject} from 'vue'
export default defineComponent({
setup () {
const fatherData = inject('father')
const info = inject('info')
return {fatherData,info}
}
})
</script>
</code></pre>
<h3 id="八-在vue-中-使用-typescirpt--技巧">八, 在Vue 中 使用 TypeScirpt技巧</h3>
<h4 id="81-接口约束约束属性">8.1 接口约束约束属性</h4>
<blockquote>
<p>采用 <code> TypeScirpt</code> 的特性, 类型断言 + 接口 完美的对 属性进行了 约束</p>
</blockquote>
<h5 id="-interface"><code> interface</code></h5>
<pre><code class="language-javascript">分页查询 字段属性类型验证
export defaultinterface queryType{
page: Number,
size: Number,
name: String,
age:Number
}
</code></pre>
<h5 id="组件中使用">组件中使用</h5>
<pre><code class="language-typescript">import queryType from '../interface/Home'
data() {
return {
query:{
page:0,
size:10,
name:'测试',
age: 2
} as queryType
}
},
</code></pre>
<h4 id="82-组件使用-来--definecomponent-定义">8.2 组件使用 来 <code> defineComponent</code> 定义</h4>
<blockquote>
<p>这样 <code> TypeScript</code>正确推断 <code>Vue</code>组件选项中的类型</p>
</blockquote>
<pre><code class="language-javascript">import { defineComponent } from 'vue'
export default defineComponent({
setup(){
return{ }
}
})
</code></pre>
<h4 id="83--类型声明-reactive">8.3类型声明 <code>reactive</code></h4>
<pre><code class="language-javascript">export defaultinterface Product {
name:String,
price:Number,
address:String
}
importProduct from '@/interface/Product'
import {reactive} from 'vue'
const product = reactive({name:'xiaomi 11',price:5999,address:'北京'}) as Product
return {fatherData,info,product}
</code></pre>
<h3 id="最后">最后</h3>
<p>文中如有错误,欢迎码友在评论区指正,如果对你有所帮助,欢迎点赞和关注~~~</p><br><br>
来源:https://www.cnblogs.com/HaiJun-Aion/p/15005055.html
頁:
[1]