Money.vue组件
1. 小技巧:快速包裹每一行
- 选中,按两下 shift,输入 surround ,选择 surround with emit,输入 li*,意思就是 n 个 li 包住行数
2. input,label 的写法
- 新手
<label for="xxx"></label> <input id = 'xxx' type="text">
- 老手
<label> <span>备注</span> <input type="text"> </label>
3. 文件行数规则
- 一个文件超过 150 行,一般拆成多个文件。
4. 开始写 CSS
- css 重置,抽成另外一个文件 reset.scss,然后在 app.vue 中引入
// reset.scss * { margin: 0; padding: 0; box-sizing: border-box; } a{ text-decoration: none; color:inherit; } // app.vue @import "~@/assets/style/reset.scss";
- 处理字体,需要用到 fonts.css\
- 在 google 搜索 "fonts.css" 中文
- 找到 font-family 的地方,在 helper.scss 中声明 font,然后在 app.vue 中使用
// helper.scss $font-hei: -apple-system, "Noto Sans", "Helvetica Neue", Helvetica, "Nimbus Sans L", Arial, "Liberation Sans", "PingFang SC", "Hiragino Sans GB", "Noto Sans CJK SC", "Source Han Sans SC", "Source Han Sans CN", "Microsoft YaHei", "Wenquanyi Micro Hei", "WenQuanYi Zen Hei", "ST Heiti", SimHei, "WenQuanYi Zen Hei Sharp", sans-serif; // app.vue body{ line-height: 1.5; font-family: $font-hei; }
- 把变量都放到 helper.css 里面。\
- command+shift+f 进行全局搜索
- helper.css 这个文件只能放变量,函数和 mixin,最终会消失的东西
4. 写css推荐顺序
- 一般而言无所谓,如果比较复杂,推荐从里到外,因为里面最简单
5. scss的用法
- 选择器里面
.tags { > .current { } }
- 选择器本身
.tags { &.current { } }
6. 按钮字体样式不会继承
- 在reset.scss中加入
button, input{ font: inherit; }
7. 字体居中解决
- 第一种方式,lineheight和高度一样,这种情况用于只有一行字
- 第二种方式,用flex
8. 字的下划线比字长
border-bottom: 1px solid; padding: 0 4px;
9. selected下划线的做法
- 避免用border-bottom来做,这种做法当class消失会有抖动,要用以下做法
&.selected::after { content: ''; position: absolute; bottom: 0; left: 0; width: 100%; height: 4px; background: #333; }
10. 处理没有的字体,在其后面加上一类字体。
// monospace就是等宽的编程字体类 font-family: Consolas, monospace;
11. 如果用了float
- 父元素一定要用clearfix
.clearfix::after{ content:''; display: block; clear:both; }
- 用scss的%,placeholder功能
// helper.scss // placeholder %x{ &::after{ content: ''; clear: both; display: block; } } // 如何用 // money.vue .buttons { @extend %x; }
12. 两层内阴影的写法
box-shadow: inset 0 -5px 5px -5px fade_out(black, 0.5), inset 0 5px 5px -5px fade_out(black, 0.5);
13. 多个地方统一替换
- 选中之后按command+r
14. 用前缀控制组件内css样式
// 这样写会有bug,要写deep
// Money.vue <Layout class-prefix="layout"> </Layout> <style lang="scss"> .layout-content{ border: 3px solid red; } .layout-wrapper{ border: 3px solid blue; } </style> // Layout.vue <template> <div class="layout-wrapper" :class="classPrefix && `${classPrefix}-wrapper`"> <div class="content" :class="classPrefix && `${classPrefix}-content`"> <slot /> </div> <Nav/> </div> </template> <script lang="ts"> export default { props: ['classPrefix'], name: "Layout" } </script>
15. 如何模块化
- 坚持一个文件查过150行就执行模块化
- 把html scss剪切的单独.vue文件,引入的时候写\
- 最后把相关文件放到一个文件夹
16. 实现TypeScript的Vue组件。
- 以Types组件为例改写
- JS写法
<template> <div> <ul class="types"> <li :class="type === '-' && 'selected'" @click="selectType('-')">支出</li> <li :class="type === '+' && 'selected'" @click="selectType('+')">收入</li> </ul> </div> </template> <script lang="js"> export default { name: "Types", props: ['xxx'], data() { return { type: '-' // '-'表示支出.'+'表示收入 } }, mounted() { console.log(this.xxx) }, methods: { selectType(type) { // type 只能是 '-' 和 '+' 中的一个 if(type !== '-' && type !== '+'){ throw new Error('type is unknown') } this.type = type } } } </script>
- TS写法,用class组件写data methods 和生命周期
- 起手
export default class Types extends Vue { }
- Component修饰符,在最上面加@Compo按下tab键,选择从vue-property-decorator引入
import {Component} from "vue-property-decorator" @Component export default class Types extends Vue { }
- 必需制定参数type的类型
selectType(type: string) { // type 只能是 '-' 和 '+' 中的一个 }
- 代码总结
import Vue from 'vue' import {Component} from "vue-property-decorator" @Component export default class Types extends Vue { type = '-' // '-'表示支出.'+'表示收入 selectType(type: string) { // type 只能是 '-' 和 '+' 中的一个 if(type !== '-' && type !== '+'){ throw new Error('type is unknown') } this.type = type } created(){} mounted(){} }
- props用法
1 查看一个包的最新版本,在终端输入
npm info typescript version
1. TS 组件 @Prop装饰器
- 用法
// 左边Number是运行时的检查,右边number是编译时的检查,编译时的检查会在写代码的时候就给提示 @Prop(Number) xxx: number | undefined; // Prop 告诉 Vue xxx 不是 data 是 prop // Number 告诉 Vue xxx 运行时类型 是个 Number // xxx 属性名 // number | undefined 就是 告诉 TS xxx 的编译时类型 // 为什么前面的Number是大些后面是小写,见3.编译时和运行时的区别
- TS的好处
- html直接空格告诉你有哪些参数
- 如果声明了类型,代码写错了会提前告诉,编译报错,无法编程js
- 检查调用的方法到底能不能调用,你不能写.tostring
2. 编译时和运行时的区别
3. TS的本质
4. Vue但文件组件的三种写法
- 用JS对象
export default { data,props,methods,created,... }
- 用 TS 类
<script lang="ts"> @Component export default class XXX extends Vue{ xxx: string = 'hi'; @Prop(Number) xxx: number|undefined; }
- 用 JS 类
@Component <script lang="js"> export default class XXX extends Vue{ xxx = 'hi' }
5. 开始实现NumberPad组件
- 在按钮上绑定事件,不加参数会默认传入事件
<button @click="inputContent">1</button> inputContent(event: MouseEvent){ if(event.target){ console.log(event.target.textContent); } }
- 强制指定类型,需要这么做的原因是Vue和Typescript不够好
inputContent(event: MouseEvent){ if(event.target){ const button = (event.target as HTMLButtonElement) console.log(button.textContent); } }
- 如果只是要排除空,也可以这么写
const input = button.textContent!;
- 基本完成NumberPad,NumberPad 组件所有代码
import Vue from "vue" import {Component, Prop} from "vue-property-decorator" @Component // 如果如果这样写,就表示Class就有一个propMessage的props,类型为String export default class NumberPad extends Vue { output: string = '0'; inputContent(event: MouseEvent){ const button = (event.target as HTMLButtonElement); const input = button.textContent!; if(this.output.length === 16){return} if(this.output === '0'){ if ('0123456789'.indexOf(input) >= 0) { this.output = input } else { this.output += input; } return } if (this.output.indexOf(".") >= 0 && input === ".") {return;} this.output += input; } remove(){ if (this.output.length === 1){ this.output = '0'; } else { this.output = this.output.slice(0, -1); } } clear(){ this.output = '0'; } ok(){ } }
6. 开始实现备注功能
- 原生html input实现绑定数据
<input type="text" :value="value" @input="onInput" placeholder="在这里输入备注"> onInput(event: KeyboardEvent){ const input = event.target as HTMLInputElement; this.value = input.value }
- 对:value 和 @input绑定数据进行简写
<input type="text" v-model="value" placeholder="在这里输入备注">
7. 开始实现tags模块
- 只能不能改外部数据的写法
@Prop() readonly dataSource: string[] | undefined // 加readonly
- 内部不能直接改外部数据
// 内部 // this.dataSource.push(name!); // 不能改外部数据,这种写法不推荐! this.$emit("update:dataSource", [...this.dataSource, name]) // 外部,用.sync简写 <Tags :data-source.sync="tags"/>