【心无旁骛】vue-ts-daily

这是一个非常有意思的项目,我们先来看看效果

这个项目所用的技术也比较有意思,它的技术栈为vue2.5 + Typescript + vuex + vue-router
放下博主的项目地址吧,https://github.com/xiaomuzhu/vue-ts-daily
接下来我们一起看项目代码吧,也一起研究ts怎么在vue中进行使用
首先是入口文件main.ts

//main.ts
// 本质上和写js一样
import Vue from 'vue';
// 解决300ms点击延迟问题
import FastClick from 'fastclick';
// 引用图标字体组件
import VueIconFont from 'vue-icon-font-pro';
// 日历组件
import vueEventCalendar from 'vue-event-calendar-pro';
// Vue.js 2.0 组件级懒加载方案:Vue Lazy Component
import VueLazyComponent from '@xunlei/vue-lazy-component';
//骨架loading
import VueSkeletonLoading from 'vue-skeleton-loading';
// Normalize.css是一种CSS reset的替代方案
import 'normalize.css';
// 动画
import 'vue2-animate/dist/vue2-animate.min.css';
import 'vue-event-calendar-pro/dist/style.css';

import App from './App.vue';
import router from './router';
import store from './store';
import './registerServiceWorker';
import '@/assets/iconfont.js';

// 兼容毒瘤ios的300ms延迟问题
if ('addEventListener' in document) {
  document.addEventListener(
    'DOMContentLoaded',
    () => {
      (FastClick as any).attach(document.body);
    },
    false,
  );
}

Vue.use(VueLazyComponent);
Vue.use(VueSkeletonLoading);
Vue.use(vueEventCalendar, { locale: 'zh', weekStartOn: 1 });
Vue.use(VueIconFont);

Vue.config.productionTip = false;

new Vue({
  router,
  store,
  render: (h) => h(App),
}).$mount('#app');

App.vue引入两个组件

<template>
  <main id="app">
    <div v-if="$route.meta.main">
      <Header></Header>
        <router-view />  
      <Footer></Footer>
    </div>
    <div v-if="!$route.meta.main">
    <router-view />
    </div>
  </main>
</template>

<script lang="ts">
// 引入组件
import { Component, Prop, Vue } from 'vue-property-decorator';
// 引入头部和底部
import Header from './components/Header.vue';
import Footer from './components/Footer.vue';
@Component({
  components: {
    Header,
    Footer,
  },
})
export default class App extends Vue {}
</script>

<style lang="scss" scoped>
@import './style/mixin';
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: $font;
  display: flex;
  text-align: center;
  flex-direction: column;
  justify-content: space-between;
  max-width: 100vw;
  height: 100vh;
}
#nav {
  padding: 30px;
  a {
    font-weight: bold;
    color: $font;
    &.router-link-exact-active {
      color: #42b983;
    }
  }
}
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.5s;
}
.fade-enter,
  .fade-leave-to
  /* .fade-leave-active below version 2.1.8 */
 {
  opacity: 0;
}
</style>

接下来我们看里面引入的HeaderIcon.ts

//src\components\common\Icon\HeaderIcon.ts
import { Component, Prop, Vue } from 'vue-property-decorator';
import template from './Icon.vue';

@Component({
  name: 'HeaderIcon',
  mixins: [template],
})
// 使用ts封装的src\components\common\Icon\HeaderIcon.ts组
export default class FooterIcon extends Vue {
  @Prop() private name!: string;
  @Prop() private path!: string;

  private data() {
    return {
      isTouched: false,
    };
  }
}

我们来看一下FooterIcon.ts

//src\components\common\Icon\FooterIcon.ts
import { Component, Prop, Vue, Emit } from 'vue-property-decorator';
import { Mutation } from 'vuex-class';

import { PageInfo } from '@/store/state';
import template from './Icon.vue';

@Component({
  name: 'FooterIcon',
  mixins: [template],
})
// 使用ts封装的src\components\common\Icon\FooterIcon.ts组件
export default class FooterIcon extends Vue {
  @Prop() private name!: object;
  @Prop() private path!: string;
  @Prop() private id!: number;
  @Prop() private isActived!: boolean;
  @Prop() private tagName!: string;
  @Mutation private getActivePage!: (pageName: number) => void;
  @Mutation private changeHeaderState!: (pageName: number) => void;

  private changeActivePage() {
    const id = this.id;

    if (!this.isActived) {
      this.getActivePage(id);
      this.changeHeaderState(id);
    }
  }
}

对icon也做的封装

//src\components\common\Icon\Icon.vue
<template>
    <section>
        <router-link v-if="!!path" :to="path">
            <span @click="changeActivePage">
                        <icon :name="!isActived ? name.defaultName : name.activedName" style="width: 2rem; height:2rem"></icon>
                        <p :class="{active: isActived}">{{tagName}}</p>
                    </span>
        </router-link>
        <div v-else class="headerIcon">
            <icon :name="name" style="width: 1.6rem; height:1.8rem">
            </icon>
        </div>
    </section>
</template>

<style src="./style.scss" lang="scss" scoped>
</style>

footer.vue中也是对footer进行了封装,感觉和封装普通的组件差别不大,不过在使用vuex,state之类的属性的时候就难起来

//src\components\Footer.vue
<template>
    <footer>
        <Icon v-for="item in activePage" :key="item.id" :tagName="item.tagName" :isActived="item.isActived" :id="item.id" :name="item.name" :path="item.path" >
        </Icon>
    </footer>
</template>

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

import { PageInfo } from '@/store/state';
import Icon from './common/Icon/FooterIcon';

@Component({
  components: {
    Icon,
  },
})
export default class Footer extends Vue {
  @State private activePage!: PageInfo[];
}
</script>

<style lang="scss" scoped>
@import '../style/mixin';

footer {
  width: 100%;
  height: 3.5rem;
  min-height: 8%;
  background-color: $grey;
  display: flex;
  align-items: center;
  justify-content: space-around;
  div {
    display: flex;
    flex-direction: column;
    justify-content: space-around;
    align-items: center;
    font-size: 60%;
    svg {
      margin-bottom: 0.4rem;
    }
  }
}
</style>

封装的骨架

//src\components\common\Skeleton\SkeletonList.vue
<template>
        <skeleton-loading>
            <row
                    v-for="i in num"
                    :key="i"
                    :gutter="{top: '10px', bottom: '10px'}"
            >
                <column :span="23" :gutter="10">
                        <square-skeleton 
                            :count="2"
                            :boxProperties="{
                                bottom: '15px',
                                width: '250px',
                                height: '15px'
                            }"
                        >
                        </square-skeleton>
                </column>
            </row>
        </skeleton-loading>
</template>

<script lang="ts">
import { Component, Vue, Prop } from 'vue-property-decorator';
@Component({})
export default class Skeleton extends Vue {
  @Prop() private num!: number;
}
</script>

<style lang="scss" scoped>
@import '../../../style/mixin';

</style>

猜你喜欢

转载自www.cnblogs.com/smart-girl/p/11243712.html