Skip to content

Instantly share code, notes, and snippets.

@madogiwa0124
Created April 13, 2019 10:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save madogiwa0124/ec017338aa78ce021b2ad8bed92da6b9 to your computer and use it in GitHub Desktop.
Save madogiwa0124/ec017338aa78ce021b2ad8bed92da6b9 to your computer and use it in GitHub Desktop.
はてなブログの記事をカードで表示するVueコンポーネント
<template>
<div id="app">
<Blogs
endpoint="https://madogiwa0124.hatenablog.com/rss"
displayCount="6"
/>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import Blogs from './components/Blogs.vue';
@Component({
components: {
Blogs,
},
})
export default class App extends Vue {
}
</script>
<style lang="scss">
</style>
<template>
<div class="blog-card" @click="redirect_to(link)">
<h3 class="blog-card--title" :title="title">
{{ title }}
</h3>
<img :src="thumbnail">
</div>
</template>
<script lang="ts">
import { Component, Vue, Prop } from 'vue-property-decorator';
@Component
export default class BlogCard extends Vue {
@Prop() public title?: string;
@Prop() public thumbnail?: string;
@Prop() public link?: string;
public redirect_to(url: string) {
location.href = url;
}
}
</script>
<style lang="scss" scoped>
.blog-card {
width: 45%;
@media screen and (min-width:480px) {
width: 30%;
}
margin: 5px;
border-bottom: 1px #4CAF50 solid;
cursor: pointer;
.blog-card--title {
margin: 5px;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
img {
width: 100%;
max-height: 150px;
@media screen and (min-width:480px) {
max-height: 250px;
}
}
}
</style>
<template>
<div class="blogs" id="blogs">
<h2 class="blogs--title">Blog</h2>
<div class="blogs__items">
<BlogCard
v-for="(blog, index) in blogs" :key="index"
:title="blog.title"
:thumbnail="blog.thumbnail"
:link="blog.link"
/>
</div>
</div>
</template>
<script lang="ts">
import { Component, Vue, Prop } from 'vue-property-decorator';
import BlogCard from './BlogCard.vue';
import axios from 'axios';
@Component ({
components: { BlogCard },
})
export default class Blogs extends Vue {
@Prop() public endpoint!: string;
@Prop() private displayCount!: number;
public blogs: object[] = [];
public parser: DOMParser = new DOMParser();
public created() {
axios.get(this.endpoint).then((res) => {
const rssDom = this.parser.parseFromString(res.data, 'text/xml');
this.buildRssBlogItems(rssDom);
});
}
private buildRssBlogItems(dom: Document): void {
dom.querySelectorAll('item').forEach((item) => {
const itemDom = this.parser.parseFromString(item.innerHTML, 'text/html');
this.blogs.push(this.blogProps(itemDom));
});
this.blogs = this.blogs.slice(0, this.displayCount);
}
private blogProps(dom: Document): object {
const thumbnail = dom.querySelector('enclosure')!.getAttribute('url');
const title = dom.querySelector('title')!.text;
const link = dom.querySelector('body')!.firstChild!.textContent!.trim();
return { title, thumbnail, link };
}
}
</script>
<style lang="scss" scoped>
.blogs {
.blogs--title {
border-left: 2px solid #4CAF50;
padding-left: 15px;
}
.blogs__items {
display: flex;
flex-wrap: wrap;
}
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment