本案例会一部一步的完成 vue3+typescript 的代码。首先看下需求:
界面图中: 点击排序按钮,下面的List会重新排序。
步骤1、先创建一个新的项目。
npm create vite@latest vue-typescript -- --template vue-ts
cd vue-typescript && npm i && npm run dev,出现下面画面,说明搭建成功了。
修改app.vue
<template>
<div class="app">
<p>{{ name }}</p>
<button @click="changeName('abc')">change name</button>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
setup() {},
name: "App",
data() {
return {
name: "Link",
age: 25,
};
},
methods: {
changeName(name:string) {
this.name = name;
},
},
});
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
点击按钮后可以正常修改name.
添加components/JobsList.vue
<template>
<div class="job-list">
<ul>
<li class="job" v-for="job in jobs" :key="job.id">
<h2>{{ job.title }} in {{ job.location }}</h2>
<div class="salary">
<p>{{ job.salary }} rupees</p>
</div>
<div class="description">
<p>
其另一大卖点是搭载HarmonyOS
2系统,在系统流畅度上比EMUI有了全面的提升,使系统在运行时实现处处顺滑,点击、滑动及其它复杂操作都顺滑跟手不易卡顿。
</p>
</div>
</li>
</ul>
</div>
</template>
<script lang="ts">
import { defineComponent, PropType } from "vue";
import Job from "../types/Job";
export default defineComponent({
props: {
jobs: {
required: true,
type: Array as PropType<Job[]>,
},
},
});
</script>
<style lang="scss" scoped>
.job-list {
max-width: 960px;
margin: 40px auto;
ul{padding: 0;}
li{
list-style-type: none;
background: white;
padding: 16px;
margin: 16px 0;
border-radius: 4px;
}
h2{
margin: 0 0 10px;
text-transform: capitalize;
}
.salary{
display: flex;
img{width:30px}
p{
color: #17bf66;
font-weight: bold;
margin: 10px 4px;
}
}
}
</style>
src/types/job.ts
interface Job {
title: string;
location: string;
salary: number;
id: string;
}
export default Job
修改app.ts
<template>
<div class="app">
<JobList :jobs="jobs" />
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
import JobList from "./components/JobsList.vue";
import Job from "./types/Job";
export default defineComponent({
name: "App",
components: { JobList },
setup() {
// const age = ref<number|string>(32)
const jobs = ref<Job[]>([
{ title: "farm worker", location: "lon lon dr", id: "1", salary: 3000 },
{ title: "quarryman", location: "kon lon dr", id: "2", salary: 6000 },
{ title: "flute player", location: "ton lon dr", id: "3", salary: 3200 },
{ title: "fisherman", location: "don lon dr", id: "4", salary: 4000 },
{ title: "prison guard", location: "son lon dr", id: "5", salary: 8000 },
]);
return { jobs };
},
});
</script>
结果显示
添加types/OrderTerm.ts
type OrderTerm='location'|'title'|'salary'
export default OrderTerm
修改App.vue
<template>
<div class="app">
<header>
<div class="title">
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" data-v-ba633cb8=""><path fill="currentColor" d="M599.872 203.776a189.44 189.44 0 0 1 64.384-4.672l2.624.128c31.168 1.024 51.2 4.096 79.488 16.32 37.632 16.128 74.496 45.056 111.488 89.344 96.384 115.264 82.752 372.8-34.752 521.728-7.68 9.728-32 41.6-30.72 39.936a426.624 426.624 0 0 1-30.08 35.776c-31.232 32.576-65.28 49.216-110.08 50.048-31.36.64-53.568-5.312-84.288-18.752l-6.528-2.88c-20.992-9.216-30.592-11.904-47.296-11.904-18.112 0-28.608 2.88-51.136 12.672l-6.464 2.816c-28.416 12.224-48.32 18.048-76.16 19.2-74.112 2.752-116.928-38.08-180.672-132.16-96.64-142.08-132.608-349.312-55.04-486.4 46.272-81.92 129.92-133.632 220.672-135.04 32.832-.576 60.288 6.848 99.648 22.72 27.136 10.88 34.752 13.76 37.376 14.272 16.256-20.16 27.776-36.992 34.56-50.24 13.568-26.304 27.2-59.968 40.704-100.8a32 32 0 1 1 60.8 20.224c-12.608 37.888-25.408 70.4-38.528 97.664zm-51.52 78.08c-14.528 17.792-31.808 37.376-51.904 58.816a32 32 0 1 1-46.72-43.776l12.288-13.248c-28.032-11.2-61.248-26.688-95.68-26.112-70.4 1.088-135.296 41.6-171.648 105.792C121.6 492.608 176 684.16 247.296 788.992c34.816 51.328 76.352 108.992 130.944 106.944 52.48-2.112 72.32-34.688 135.872-34.688 63.552 0 81.28 34.688 136.96 33.536 56.448-1.088 75.776-39.04 126.848-103.872 107.904-136.768 107.904-362.752 35.776-449.088-72.192-86.272-124.672-84.096-151.68-85.12-41.472-4.288-81.6 12.544-113.664 25.152z"></path></svg>
<h1>列表例子</h1>
</div>
<div class="order">
<button @click="handleClick('title')">order by title</button>
<button @click="handleClick('salary')">order by salary</button>
<button @click="handleClick('location')">order by location</button>
</div>
</header>
<JobList :jobs="jobs" :order="order" />
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
import JobList from "./components/JobsList.vue";
import Job from "./types/Job";
import OrderTerm from "./types/OrderTerm";
export default defineComponent({
name: "App",
components: { JobList },
setup() {
// const age = ref<number|string>(32)
const jobs = ref<Job[]>([
{ title: "farm worker", location: "lon lon dr", id: "1", salary: 3000 },
{ title: "quarryman", location: "kon lon dr", id: "2", salary: 6000 },
{ title: "flute player", location: "ton lon dr", id: "3", salary: 3200 },
{ title: "fisherman", location: "don lon dr", id: "4", salary: 4000 },
{ title: "prison guard", location: "son lon dr", id: "5", salary: 8000 },
]);
const order = ref<OrderTerm>("title");
const handleClick = (term: OrderTerm) => {
order.value = term;
};
return { jobs, order, handleClick };
},
});
</script>
<style lang="scss" scoped>
header {
text-align: center;
.order {
margin-top: 20px;
}
.title{
display: flex;
justify-content: center;
}
svg{
width: 60px;
margin-right: 20px;
}
h1{font-size: 3em;}
}
button {
margin: 0 10px;
color: aqua;
border: 3px solid rgb(43, 177, 201);
background: white;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
font-weight: bold;
}
</style>
修改JobsList.vue
<p>order by {{ order }}</p>
export default defineComponent({
props: {
jobs: {
required: true,
type: Array as PropType<Job[]>,
},
order: {
required: true,
type: String as PropType<OrderTerm>,
},
},
});
修改 JobsList.vue
<template>
<div class="job-list">
<p>order by {{ order }}</p>
<transition-group name="list" tag="ul">
<li class="job" v-for="job in orderedJobs" :key="job.id">
<h2>{{ job.title }} in {{ job.location }}</h2>
<div class="salary">
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" data-v-ba633cb8=""><path fill="currentColor" d="M513.28 448a64 64 0 1 1 76.544 49.728A96 96 0 0 0 768 448h64a160 160 0 0 1-320 0h1.28zm-126.976-29.696a256 256 0 1 0 43.52-180.48A256 256 0 0 1 832 448h-64a192 192 0 0 0-381.696-29.696zm105.664 249.472L285.696 874.048a96 96 0 0 1-135.68-135.744l206.208-206.272a320 320 0 1 1 135.744 135.744zm-54.464-36.032a321.92 321.92 0 0 1-45.248-45.248L195.2 783.552a32 32 0 1 0 45.248 45.248l197.056-197.12z"></path></svg>
<p>{{ job.salary }} rupees</p>
</div>
<div class="description">
<p>
其另一大卖点是搭载HarmonyOS
2系统,在系统流畅度上比EMUI有了全面的提升,使系统在运行时实现处处顺滑,点击、滑动及其它复杂操作都顺滑跟手不易卡顿。
</p>
</div>
</li>
</transition-group>
</div>
</template>
<script lang="ts">
import { computed, defineComponent, PropType } from "vue";
import Job from "../types/Job";
import OrderTerm from "../types/OrderTerm";
export default defineComponent({
props: {
jobs: {
required: true,
type: Array as PropType<Job[]>,
},
order: {
required: true,
type: String as PropType<OrderTerm>,
},
},
setup(props) {
const orderedJobs = computed(() => {
return [...props.jobs].sort((a: Job, b: Job) => {
return a[props.order] > b[props.order] ? 1 : -1;
});
});
return {orderedJobs}
},
});
</script>
<style lang="scss" scoped>
$bg: #2d3a4b;
$dark_gray: #889aa4;
$light_gray: #eee;
.job-list {
max-width: 960px;
margin: 40px auto;
ul {
padding: 0;
}
li {
list-style-type: none;
background: white;
padding: 16px;
margin: 16px 0;
border-radius: 4px;
}
h2 {
margin: 0 0 10px;
text-transform: capitalize;
}
.salary {
display: flex;
svg {
width: 30px;
}
p {
color: #17bf66;
font-weight: bold;
margin: 10px 4px;
}
}
}
.list-move{
transition: all 0.5s;
}
.login-container {
min-height: 100%;
width: 100%;
background-color: $bg;
overflow: hidden;
.login-form {
position: relative;
width: 520px;
max-width: 100%;
padding: 160px 35px 0;
margin: 0 auto;
overflow: hidden;
}
.tips {
font-size: 14px;
color: #fff;
margin-bottom: 10px;
span {
&:first-of-type {
margin-right: 16px;
}
}
}
.svg-container {
padding: 6px 5px 6px 15px;
color: $dark_gray;
vertical-align: middle;
width: 30px;
display: inline-block;
}
.title-container {
position: relative;
.title {
font-size: 26px;
color: $light_gray;
margin: 0px auto 40px auto;
text-align: center;
font-weight: bold;
}
}
.show-pwd {
position: absolute;
right: 10px;
top: 7px;
font-size: 16px;
color: $dark_gray;
cursor: pointer;
user-select: none;
}
}
</style>
来看下效果
在实践本案例过程中的问题请留言。