はじめに
埋め込みツイートの表示をするにあたり、公式の埋め込みツイートを使おうと思ったのですが、なぜかVueで<script>
が動きませんでした。原因を調べてもいまいちわからなかったので、自作したほうが早いのではないかと思いました。
一応、Vuetifyにも「Twitter card」というものはあったのですが……なんか違う。
というわけで、v-cardを基本にそれっぽいレイアウトにしてみました。
つくるもの
See the Pen Oembed Tweet by END (@aiandrox) on CodePen.
環境
- Vue.js 2.6.11
- Vuetify 2.2.21
- Material Design Icon 5.1.45
アイコンは別のものでも代用可能だと思います。Twitterアイコン、リプライ、リツイート、いいねで使用しています。
使用データ
サンプルコードでは以下のようにデータをネストしています。
- tweet
- tweetId(ツイートのID)
- html(本文部分のHTML)
- tweetedAt(ツイート日時)
- user
- name(表示名)
- screenName(
@screen_name
のユーザー名) - avatarUrl(アイコンの画像URL)
htmlはGET statuses/oembedで取得した埋め込みツイート用のHTMLから<p>
タグの内側を抜き出して利用しました。
日時はDay.jsなどを使ってフォーマットを整えることをおすすめします。
ツイート表示の規定
Twitterの埋め込みツイートには表示の規定があるので、それに従ってカードを作成します。
こちらのDisplay requirements – Twitter DevelopersをざっくりGoogle意訳しました。間違っていたらご指摘をお願いします。
- 実際のアカウントによる変更を加えられていないツイートを表示すること。
- 公式ツイッターロゴを表示すること。
- 個々のツイートの右上隅に表示するか、タイムラインに直接添付すること。
- ロゴは、画像と同じ高さにすること。
- 作成者のプロフィール画像、@ユーザーネーム、表示名を常に表示し、Twitterプロフィールページにリンクさせること。
- @ユーザーネームは
@
を用いて表示すること。 - プロフィール画像は、表示名と@ユーザーネームの左側に配置すること(ただし右から左に読む言語のツイートは例外)
- ツイートのテキストは作成者の表示名と@ユーザーネームの下の行に表示すること。
- ツイートのテキストと作成者の周りのスペースはツイートのパーマリンクにリンクさせること。
- テキスト内のツイートエンティティは、Twitter上の適切なホームに適切にリンクすること。
-
@ユーザーネーム
によるメンションは言及されたユーザーのプロフィールページにリンクすること。 - ハッシュタグは、ハッシュタグをクエリとしてTwitter検索にリンクすること。
- テキスト内のリンクは、URL entities APIにおけるdisplay_urlを表示し、元のt.co urlにリンクすること(詳細はt.co best practices articleを参照)
-
- ツイートのタイムスタンプを表示し、ツイートのパーマリンクにリンクすること。
- プラットフォームに存在しないツイートのモックアップを使用しないこと。
コード
CodePenの方はそれだけで完結するようにしています。
こちらのコードはコンポーネント用のコードです。
<template>
<div>
<v-card flat outlined max-width="500" class="mt-3" :href="tweetUrl">
<v-card-title>
<v-list-item class="pl-0">
<v-list-item :href="userUrl">
<v-list-item-avatar color="grey" size="40">
<v-img :src="tweet.user.avatarUrl" />
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title>{{ tweet.user.name }}</v-list-item-title>
<v-list-item-subtitle class="font-weight-light">@{{ tweet.user.screenName }}</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
<v-spacer />
<v-list-item-action>
<v-icon color="blue">mdi-twitter</v-icon>
</v-list-item-action>
</v-list-item>
</v-card-title>
<v-card-text class="text--primary" v-html="tweet.html" />
<v-card-actions>
<v-btn
v-for="button in buttons"
:key="button.icon"
:href="button.url"
:color="button.color"
icon
>
<v-icon>{{ button.icon }}</v-icon>
</v-btn>
<v-spacer />
<span class="body-2 font-weight-light">{{ tweet.tweetedAt }}</span>
</v-card-actions>
</v-card>
</v-card>
</div>
</template>
<script>
export default {
data() {
return {
tweet: {
tweetId: "0000000000",
html: "テキスト<br>改行するとこんな感じ",
tweetedAt: "2020-12-31 10:51",
user: {
name: "ユーザー",
screenName: "screen_name",
avatarUrl: "https://avataaars.io/?avatarStyle=Transparent&topType=ShortHairShortCurly&accessoriesType=Prescription02&hairColor=Black&facialHairType=Blank&clotheType=Hoodie&clotheColor=White&eyeType=Default&eyebrowType=DefaultNatural&mouthType=Default&skinColor=Light"
},
}
}
},
computed: {
userUrl() {
return `https://twitter.com/${this.tweet.user.screenName}`
},
tweetUrl() {
return `https://twitter.com/${this.tweet.user.screenName}/status/${this.tweet.tweetId}`
},
replyUrl() {
return `https://twitter.com/intent/tweet?in_reply_to=${this.tweet.tweetId}`
},
retweetUrl() {
return `https://twitter.com/intent/retweet?tweet_id=${this.tweet.tweetId}`
},
likeUrl() {
return `https://twitter.com/intent/like?tweet_id=${this.tweet.tweetId}`
},
buttons() {
return [
{ url: this.replyUrl, color: "gray", icon: "mdi-chat-outline" },
{ url: this.retweetUrl, color: "green", icon: "mdi-twitter-retweet" },
{ url: this.likeUrl, color: "pink", icon: "mdi-heart-outline" }
]
},
},
}
</script>
おわりに
プロフィールのリンクの範囲が気になりますが、これで妥協点とします。
もっといい感じにできそうなら踏み台にしていただきたいです。リンクをしていただければ見に行きますので……。
ご意見、ご指摘などございましたらコメントを頂けると幸いです。