project from jirengu.com
Money.vue组件
- 需求是完成如下页面:
1. 先搭一个初步的框架,页面所有内容,接下来会模块化:
<template>
<Layout>
<div class="tags">
<ul class="current">
<li>衣</li>
<li>食</li>
<li>住</li>
<li>行</li>
</ul>
<div class="new">
<button>新增标签</button>
</div>
</div>
<div>
<label class="notes">
<span class="name">备注</span>
<input type="text">
</label>
</div>
<!-- 对应支出和收入-->
<div>
<ul class="types">
<li class="selected">支出</li>
<li>收入</li>
</ul>
</div>
<div class="numberPad">
<div class="output">100</div>
<div class="buttons">
<button>1</button>
<button>2</button>
<button>3</button>
<button>删除</button>
<button>4</button>
<button>5</button>
<button>6</button>
<button>清空</button>
<button>7</button>
<button>8</button>
<button>9</button>
<button>OK</button>
<button>0</button>
<button>.</button>
</div>
</div>
</Layout>
</template>
2. 写SCSS样式的总体思路是:
- 2.1 先
reset
,把默认不需要的样式处理掉,都移到assets/style/reset.scss
中,再在App.vue引入这个reset
文件;
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
a{
text-decoration: none; //去掉图标下方文字的下划线
color: inherit;
}
- 2.2 全局样式设置,主要是文字相关的字体和行高之类的,需要用到'font css'跨平台中文字体解决方案,有一行设置代码写到
assets/style/helper.scss
:
$font-hei:-apple-system, "Helvetica Neue", Helvetica, "Nimbus Sans L", Arial, "Liberation Sans", "PingFang SC", "Hiragino Sans GB", "Source Han Sans CN", "Source Han Sans SC", "Microsoft YaHei", "Wenquanyi Micro Hei", "WenQuanYi Zen Hei", "ST Heiti", SimHei, "WenQuanYi Zen Hei Sharp", sans-serif;
- 再去App.vue中引入这个字体设置,并整理样式代码:
<template>
<div id="app">
<router-view/>
</div>
</template>
<style lang="scss">
@import "~@/assets/style/helper.scss";
@import "~@/assets/style/reset.scss";
body {
-webkit-font-smoothing: antialiased; //apple系统用的
-moz-osx-font-smoothing: grayscale; //apple系统用的
color: #333;
font-family: $font-hei;
line-height: 1.5;
}
</style>
- 2.3 定义变量,放在
helper.scss
,其中只放变量、函数:
$font-hei:-apple-system, "Helvetica Neue", Helvetica, "Nimbus Sans L", Arial, "Liberation Sans", "PingFang SC", "Hiragino Sans GB", "Source Han Sans CN", "Source Han Sans SC", "Microsoft YaHei", "Wenquanyi Micro Hei", "WenQuanYi Zen Hei", "ST Heiti", SimHei, "WenQuanYi Zen Hei Sharp", sans-serif;
$font-kai: Baskerville, Georgia, "Liberation Serif", "Kaiti SC", STKaiti, "AR PL UKai CN", "AR PL UKai HK", "AR PL UKai TW", "AR PL UKai TW MBE", "AR PL KaitiM GB", KaiTi, KaiTi_GB2312, DFKai-SB, "TW-Kai", serif;
$font-song:Georgia, "Nimbus Roman No9 L", "Songti SC", STSong, "AR PL New Sung", "AR PL SungtiL GB", NSimSun, SimSun, "TW-Sung", "WenQuanYi Bitmap Song", "AR PL UMing CN", "AR PL UMing HK", "AR PL UMing TW", "AR PL UMing TW MBE", PMingLiU, MingLiU, serif;
$color-highlight:orange;
2.4 局部变量:
3. TypeScript
以上步骤写完以后的Money.vue
代码行数超过150行,就需要模块化的重构,也就是把对应的功能,分4个组件放在components文件夹中
:
- Notes.vue
- NumberPad.vue
- Tags.vue
- Types.vue
然后在精简后的Money.vue
中,分别再去引入刚才分出去的组件:
<template>
<!-- class前缀-->
<Layout class-prefix="layout">
<!-- 由于scss样式写的column-reverse布局,所以组件由下往上堆叠-->
<NumberPad/>
<Types/>
<Notes/>
<Tags/>
</Layout>
</template>
<script lang="ts">
import Notes from '@/components/Money/Notes.vue';
import NumberPad from '@/components/Money/NumberPad.vue';
import Tags from '@/components/Money/Tags.vue';
import Types from '@/components/Money/Types.vue';
export default {
name: 'Money.vue',
components: {Types, Tags, NumberPad, Notes},
// components: {Nav}
};
</script>
<style lang="scss">
.layout-content {
display: flex;
flex-direction: column-reverse; //从下面往上布局
}
</style>
使用 JS 实现 Types.vue组件
- JS是用构造选项options
来写组件,构造选项没有类型,任意添加东西:
<template>
<div>
<ul class="types">
<li :class="type === '-' && 'selected'"
@click="selectType('-')">支出
</li>
<li :class="type === '+' && 'selected'"
@click="selectType('+')">收入
</li>
</ul>
</div>
</template>
<script>
export default {
name: 'Types',
props:['xxx'], //外部接收的属性
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
data(){ //用来保存当前选中的类型,内部属性
return{
type:'-' //'-'表示支出,'+'表示收入
}
},
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
mounted() {
console.log(this.xxx);
},
methods:{ //用于切换 Type 的方法
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
selectType(type){ //type 只能是'-'和'+'中的一个
if(type!=='-' && type !=='+'){
throw new Error('type is unknown')
}
this.type= type
}
}
};
</script>
使用 TS 实现 Types.vue组件
- TS是用class类、装饰器写组件:
<template>
<div>
<ul class="types">
<li :class="type === '-' && 'selected'"
@click="selectType('-')">支出
</li>
<li :class="type === '+' && 'selected'"
@click="selectType('+')">收入
</li>
</ul>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
import {Component} from 'vue-property-decorator'; //自第三方库引入Component装饰器
//声明以下为 TS 写的组件,type='-'会自动处理为data,selectType会自动处理为methods
@Component //将此装饰器修饰到class上;@Component由vue-class-component官方库提供
export default class Types extends Vue { // TS 写组件的引入
type = '-'
selectType(type: string){ // 此行为 TS 语法
if (type !== '-' && type !== '+'){
throw new Error('type is unknown')
}
this.type = type;
}
}
</script>
- 查看TypeScript最新版本:
npm info typescript version
- 重启webStrom
File--Invalidate Caches/Restart --Invalidate and Restart
- TS 声明
Props
,首先要理解什么是编译时和运行时:
@Prop(Number) xxx: number | undefined;
- 上面代码中,
(Number)
就是运行时代码,number | undefined
就是编译时代码。
<script lang="ts">
import Vue from 'vue';
import {Component, Prop} from 'vue-property-decorator'; //自第三方库引入Component装饰器
//声明以下为 TS 写的组件,type='-'会自动处理为data,selectType会自动处理为methods
// @Component //将此装饰器修饰到class上;@Component由vue-class-component官方库提供
@Component
export default class Types extends Vue { // TS 写组件的引入
type = '-'; //相当于js中的data '-'表示支出,'+'表示收入
// helloMsg = 'hello,' + this.propMessage; //官方文档引入props,不能用
@Prop(Number) xxx: number | undefined //第三方库引入props,vue-property-decorator
//@Prop是装饰器,作用是告诉 Vue xxx不是data 而是prop
// (Number)告诉Vue xxx是个 Number ;
//number | undefined 就是 TS 的语法 意为 xxx 的类型是number或undefined
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
selectType(type: string) { //相当于js中的methods; type: string即为 TS 语法
if (type !== '-' && type !== '+') {
throw new Error('type is unknown');
}
this.type = type;
}
mounted() {
if (this.xxx === undefined) {
console.log('没有xxx')
} else {
console.log(this.xxx.toString());
}
}
}
</script>