はじめに
埋め込みツイートの表示をするにあたり、公式の埋め込みツイートを使おうと思ったのですが、なぜかVueで<script>
が動きませんでした。原因を調べてもいまいちわからなかったので、自作したほうが早いのではないかと思いました。
一応、Vuetifyにも「Twitter card」というものはあったのですが……なんか違う。

というわけで、v-cardを基本にそれっぽいレイアウトにしてみました。
つくるもの
こんな感じのツイート風コンポーネントです。

環境
- 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上の適切なホームに適切にリンクすること。
- ツイートのタイムスタンプを表示し、ツイートのパーマリンクにリンクすること。
- プラットフォームに存在しないツイートのモックアップを使用しないこと。
コード
CodePenの方はそれだけで完結するようにしています。
こちらのコードはコンポーネント用のコードです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
<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>
|
おわりに
プロフィールのリンクの範囲が気になりますが、これで妥協点とします。
もっといい感じにできそうなら踏み台にしていただきたいです。