阿花记账日程规划

384 阅读3分钟

第一天:导航栏

今天完成了阿花记账的导航栏。制作过程中使用了Vue-Router

  • router/index.ts添加router,配置4个路径对应组件

  • 初始化组件

  • 将router传给new Vue()

  • 在App组件里用<router-view/>给出router渲染区域

  • 切换路径切换页面<router-link to=""></router-link>

  • 找不到页面,进行动态路由匹配(看上去挺高大上,其实就是除了我们设置的页面的其他页面)

听说手机页面布局的时候如果使用fixed进行布局会有很多坑,所以选择用了flex布局

还学到了一个知识。就是SCSS里有一个属性是scope ,这个的作用有两个:

  • 在你的div上加一个属性:data-v-xxx
  • 在CSS上加一个上面的属性选择器。主要是用于匹配
  • 只要能加scope就加scope,这样可以避免class冲突。但是如果是全局设置属性就不要加scope了,例如body{}

Vue插槽

  • 将代码简化,封装,调用。创建<layout></layout>
  • 将重复的部分放在一个组件里,不重复的部分放在插槽里

使用svg-sprite-loader引入icon

  • svg其实就是一个xml
  • 有个难点鸭,怎么把webpack.config.js配置转换成Vu.config.js
  • 在body里创建一个svg标签,svg标签里创建symbol标签,每个symbol有个id。<use xlink:href="#iconname"/>
  • 将一个目录里任意后缀的文件统一全部引入到当前文件。
let importAll = (requireContext: __WebpackModuleApi.RequireContext) => requireContext.keys().forEach(requireContext);</br>
 try {importAll(require.context('../assets/icons', true, /\.svg$/));} catch (error) {console.log(error);}

对icon组件进行封装

  • 代码重复太多惹!怎么办!封装!ps:icon是全局都可以引用的,记得在main.ts把它定义为全局的。
  • 给icon设置name属性。
  • 使用v-bind将icon的name绑定到svg上.注意xlink前面的:
<svg class="icon" @click="$emit('click', $event)">
    <use :xlink:href="'#'+name"/>
</svg>

怎么设置路由激活呢(点击链接,链接高亮)? 答:给router-link添加active-class="selected"属性。点击的时候整个页面先消失,然后出现新的nav页面。路由和to值匹配,进行高亮

第三天:完成Money组件

感触:

  • 模块化:写代码的时候发现Money组件里CSS代码放在一起也太多了!!把Money页面分成了四个部分,每个部分拥有他们自己CSS代码。其实也就是模块化对吧。
  • TypeScript就是JS+Type。重点就是JS的七个基础类型(六个简单类型,一个负责类型) 复习了三个方法:Data() {},props:[''],methods:{}

这里用到了装饰器语法:

import {Component} from 'vue-property-decorator'

@Compontent 告诉TS export函数体里是Vue的一个组件,效果就是:type会自动被处理为 Data,selectType会自动被处理为methods。

@Prop(Number) xxx:number | undefined;
//Props是一个装饰器,他的作用就是告诉Vue,xxx不是Data是Prop.
//Number的作用是告诉Vue,XXX是一个Number
//xxx是一个属性名
//number | undefined是xxx的类型

小问题:使用官方文档给的提示根本就不能使用props,为什么呀? 最后选择了使用第三方提供的props

不过我发现了TS最大的好处(对我而言吧):

  • 文档的自动提示更智能
  • 如果我声明了一个类型,调用的时候如果出错TS会报警的。TS会检查你调用的这个方法是否可以真的调用
  • TS是编译的时候进行报错,而JS是运行的时候进行报错.TS编译报错无法得到JS终端Error.

总结:怎么使用TS组件:
我们必须从vue-property-decorator里引入一个叫做Component这个装饰器。然后将装饰器修饰到Class上。Class可以声明Data和methods。也可以加上生命周期。

//1:用JS对象
export default{data,props,methods.created,...}

//2.用TS类,<script lang="ts">
@Component
export default class XXX extends Vue{
    xxx:"string='hi';
    @Prop(Number) xxx:number | undefined;
}
//3.用JS类
@Component
export defalut class XXX extends Vue{
    xxx='hi'
}

NumberPad

注意:

  • 不可以有两个小数点
  • 注意0的位置(比如0可以在开头吗?)

其实事件里是没有点击事件的,点击事件其实是鼠标事件的一类。 使用的时发现TS提示我的target为空,这是我之前没有想到过的。经过提醒,强制给他添加一个类型。主要是因为Vue和TS的结合不够好。

notes

input的event是个什么事件呢?不过问题不大,编译之后就不见了。 重点!!! 如果你的代码里出现了

value="value"
@input="value = $event.target.value"

那么我们就可以把它简写成

:value="x"
@input="x = $event.target.value"
//等同于下面的
v-model="x"

tags

<script lang="ts">
  import Vue from 'vue';
  import {Component, Prop} from 'vue-property-decorator';

  @Component
  export default class Tags extends Vue {
    @Prop() readonly dataSource: string[] | undefined;
    selectedTags: string[] = [];
//判断选中状态
    toggle(tag: string) {
      const index = this.selectedTags.indexOf(tag);
      if (index >= 0) {
        this.selectedTags.splice(index, 1);
      } else {
        this.selectedTags.push(tag);
      }
      this.$emit('update:value', this.selectedTags);
    }
//新增标签
    create() {
      const name = window.prompt('请输入标签名');
      if (name === '') {
        window.alert('标签名不能为空');
      } else if (this.dataSource) {
        this.$emit('update:dataSource',
          [...this.dataSource, name]);
      }

    }
  }

收集四个组件

(tags,notes,numberpad,types的Value值) @watch ('child') onChildChanged(val:string,oldVal;string){} watch是在某个东西发生变化的时候进行监听

使用.sync方法 其实四个组件整合这里我不是很熟悉,怎么说呢。用的并不好

第六天:使用LocalStorage

当用户点击OK的时候,将数据放在LocalStorage里。

  • 监听record.amount的点击状态
  • 重新监听submit事件
saveRecord(){
    const record2 = JSON.parse(JSON.stringify(thisrecord));
    this.recordList.push(record2);
}
@Watch(path:'recordList')
onRecordListChange(){
    window.localStorage.setItem('recordList',JSON.stringify(this.recordList))
}

第七天:动态的获取tags

使用v-for去循环tags

MVC的所有数据操作都是由model自己控制的。
一开始需要fetch(),目的是为了加载数据。
将data放在tags里。
创建的时候注意判断标签名重复。

第九天:如何封装一个通用组件:

改造Notes.vue,让他成为通用组件。
一.数据从父组件传入
为了解耦,子组件本身就不能生成数据。即使生成了,也只能在组件内部运作,不能传递出去,下面是在一些较复杂的场景中,对props传递的参数加一些验证,也是方便如果是数据类型不符合可以直接抛出异常。

二.在父组件处理事件
比如某些子组件的click事件,避免高耦合,逻辑最好放在父组件中,子组件只是一个承载体。

三.slot的应用
现在有一个需求,在同一个子组件中,我在不同 的场景需要用到不同的按钮,那么在封装组件的时候就不用去写按钮,只用在合适的未知留一个slot,把按钮的位置留出来,然后再父组件中写入:

代码重构:使value从data变成了props

第十天:使用Vuex进行全局数据管理

小知识:使用Vue中的deep语法作为深度作用选择器,类似于Sass之类的预处理器无法正确解析 >>> 等语法,在这种情况下可以选择使用/deep/或者是::v-deep等操作符取而代之,两者皆为 >>> 的别名。意思是选择当前组件里层的组件

State:data
mutation:method
action:调用method

使用mixin优化代码