问题一:webpack与vue
提交代码,提示vue-cli-service lint found some errors
我的解决方法是在报错文件添加/* eslint-disable */
使用后成功解决了vue.config.js
中的问题
但是Icon.vue
还是存在报错,error: '__WebpackModuleApi' is not defined (no-undef)
在网上搜索到了类似的问题,Vue.js中的__webpack_public_path__
我在.eslintrc.js
>module.exports
添加globals
,成功提交代码。
module.exports = {
"globals":{
"__WebpackModuleApi":"writable"
}
}
问题二:拆分组件
Money.vue
内容太多,对其进行拆分。在components
新建Money
文件夹,对应Money.vue
的几个div块,创建相应的vue文件。
将Money.vue
中的template
与style
移到相应vue文件中,并在Money.vue
中引入。
拆分为几个组件后,效果与原来一致。
问题三:写Vue组件遇到的错误
写Vue组件的方式(单文件组件)
- 用JS对象写
export default {data , props, methods, created, ...}
- 用TS类写
@Componet
export default class XXX extends Vue{
xxx: string = 'hi';
@Prop(Number) xxx: number|undefined;
}
- 用JS类写
@Compnent
export default class XXX extends Vue{
xxx = 'hi'
}
bug1:在使用TS类写vue组件时,prop无法使用
23行代码报错
尝试更新typescript后,依旧报错
@Prop(Number) xxx: number | undefined;
成功
解析一下这句代码
简单来说,number | undefined
是在编译时告诉Vue,xxx的编译类型。而Number
是在运行时告诉Vue,xxx是个number。
扯TS的本质
注:tsc
=>TypeScript compiler
,可检查TS,可将TS编译成JS。
bug2:在使用TS类写vue组件时,selectType出错
声明type: String
即可
问题四:v-model
<template>
<div>
<label class="notes">
<span class="name">备注</span>
<input type="text"
:value="x"
@input="x = $event.target.value"
placeholder="点击输入备注...">
</label>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import {Component} from 'vue-property-decorator';
@Component
export default class Notes extends Vue{
x = '';
}
</script>
可以简写成
<template>
<div>
<label class="notes">
<span class="name">备注</span>
<input type="text"
x-model="x"
placeholder="点击输入备注...">
</label>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import {Component} from 'vue-property-decorator';
@Component
export default class Notes extends Vue{
x = '';
}
</script>
问题五:收集数据
占位,之后整理
问题六:用LocalStorage储存数据
数据收集完之后,想实现以下功能:每次按ok,将数据放到LocalStorage
。
在父组件Money.vue
的NumberPad
新加了一个监听@submit="saveRecord"
<template>
<layout class-prefix="layout">
<NumberPad @update:value="onUpdateAmount" @submit="saveRecord"/>
...
</layout>
</template>
<script lang="ts">
...
export default class Money extends Vue{
tags = ['餐饮','交通','购物','居家'];
recordList: Record[] = [];
record: Record = {tags: [], notes: '', type: '-', amount: 0};
...
// 新增函数
saveRecord(){
this.recordList.push(this.record)
}
@Watch('recordList')
onRecordListChange(){
window.localStorage.setItem('recordList',JSON.stringify((this.recordList)))
}
}
</script>
在子组件NumberPad.vue
文件中的export default
中的ok函数中添加代码
<script lang="ts">
...
export default class NumberPad extends Vue {
...
ok(){
this.$emit('update:value',this.output);
this.$emit('submit',this.output); //新增
}
}
</script>
这样用户每次点击ok
,都会将数据上传至LocalStorae
但是这里出了一个错误,如下:
第一次输入1,点击ok,打印this.recordList
,amount
是数字1,正确。
但第二次输入2,点击ok,再打印this.recordList
,amount
得到两次结果都是2,出现bug。
Local Storage
如下
原因是因为this.recordList.push(this.record)
中this.record
只是引用,所以第一次ok和第二次ok,都只是引用了record
的地址,结果是两个2。
修改代码,record2
是一个深拷贝,相当于保存了this.record
的副本这样就可以实现预想的功能了。
saveRecord(){
const record2 = JSON.parse(JSON.stringify(this.record));
this.recordList.push(record2)
console.log(this.recordList);
}
问题七: js改写ts报错
- 改文件名后缀
js
为ts
- 新建一个
custom.d.ts
,全局声明RecordItem
,赋给data
,解决
- 这里提交代码时,又报了错(晕)
error: 'RecordItem' is not defined (no-undef) at src\views\Money.vue:40:20:
38 |
39 | saveRecord() {
> 40 | const record2: RecordItem = model.clone(this.record);
| ^
41 | record2.createdAt = new Date();
42 | this.recordList.push(record2);
43 | }
cunstom.d.ts中全局声明的RecordItem
,在Money.vue中却提示'RecordItem' is not defined
。
尝试了很多方法没有成功,最后又重新声明了一个RecordItem,引入Money.vue中。
后续如果有更好的解决办法会更新。
问题八:关于子组件直接修改父组件的值
代码如下
<template>
<div>
<label class="formItem">
<span class="name">{{ this.fieldName }}</span>
<input type="text" v-model="value" :placeholder="this.placeholder">
</label>
</div>
</template>
<script lang="ts">
...
export default class FormItem extends Vue{
@Prop({default:''}) value!:string;
...
onValueChanged(value:string){
this.$emit('update:value',value)
}
}
</script>
vue不推荐直接在子组件中修改父组件传来的props的值,改写FormItem.vue
后,报错如下:
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "value"
解决办法:
改写v-model="value"
,不再给value赋值。
通过onValuechanged
对value
进行变更。
// 改后
<template>
<div>
<label class="formItem">
<span class="name">{{ this.fieldName }}</span>
<input type="text"
:value = "value"
@input = "onValueChanged=($event.traget.value)"
:placeholder="placeholder">
</label>
</div>
</template>
<script lang="ts">
...
export default class FormItem extends Vue{
@Prop({default:''}) readonly value!:string;
...
onValueChanged(value:string){
this.$emit('update:value',value)
}
}
</script>
问题九:解决id生成问题
问题描述
举个例子,在组件tagListModel.vue
中create
如下
type TagListModel = {
...
create: (name: string) => 'success' | 'duplicated'
...
}
const tagListModel: TagListModel = {
...
create(name) {
const names = this.data.map(item => item.name)
if(names.indexOf(name) >= 0) { return 'duplicated'; }
this.data.push({ id:name, name: name });
this.save();
return 'success';
},
...
}
创建相同name
的标签,就会提示重复。
后来添加了新功能,在编辑标签页面可以改标签名
,就出现了如下bug——改变标签{id:1, name:1}
的name
,再次新建标签时,不能识别标签重复。
解决思路
- 首先一个id赋给了标签,就不要再修改了,因为路由用了id作为url的地址的一部分。
{
path: '/labels/edit/:id',
component: EditLabel
},
id如果变了,刷新页面就不存在了。
-
其次,id是不能重复的,不然
/label/edit/1
到底对应哪一个标签页? -
我的做法是每新建一个标签,
id
自增。虽然可能会爆栈,但是能满足很大一部分需求。
实现思路大致说一下,代码可以访问我的github。
新建一个ts组件实现id的自增功能,在tagListModel.ts
组件的create
方法引入这个自增id
。
问题十: ISO 8601
用法如下:
日期和时间的组合表示法,要在时间前面加一大写字母T,如要表示东八区时间2004年5月3日下午5点30分8秒,可以写成2004-05-03T17:30:08+08:00或20040503T173008+08。