Skip to content

Instantly share code, notes, and snippets.

@ohtsuchi
Last active July 9, 2019 13:44
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 ohtsuchi/551987efd83c98d5ad1dfea589e4f6b2 to your computer and use it in GitHub Desktop.
Save ohtsuchi/551987efd83c98d5ad1dfea589e4f6b2 to your computer and use it in GitHub Desktop.

vue.js サンプル

html, js

  • 2ファイル作成
    • index.html
    • app.js
<!--index.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>The greatest news app ever</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/foundation/6.3.1/css/foundation.min.css">
</head>
<body>
<div id="app">
<li v-for="item in info">
{{ item.name }}
{{ item.address }}
<img :src="item.image_url.shop_image1" alt="test">
</li>
</div>
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="app.js"></script>
</body>
</html>
// app.js
// XXXXX を アクセスキー に変更
new Vue({
el: '#app',
data () {
return {
info: null
}
},
mounted () {
axios
.get('https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid=XXXXX&name=かねさか')
.then(response => (this.info = response.data.rest))
}
})

Component に変更

  • index.html
<div id="app">
    <li v-for="item in info">
        {{ item.name }}
        {{ item.address }}
        <img :src="item.image_url.shop_image1" alt="test">
    </li>
</div>

<div id="app">
    <my-component :info="info"></my-component>
</div>
  • app.js
Vue.component('my-component', {
  props: ['info'],
  template: `<div><li v-for="item in info">
			{{ item.name }} /
			{{ item.address }}
			<img :src="item.image_url.shop_image1" alt="test">
		</li></div>`
});
<!--index.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>The greatest news app ever</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/foundation/6.3.1/css/foundation.min.css">
</head>
<body>
<div id="app">
<my-component :info="info"></my-component>
</div>
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="app.js"></script>
</body>
</html>
// app.js
// XXXXX を アクセスキー に変更
Vue.component('my-component', {
props: ['info'],
template: `<div><li v-for="item in info">
{{ item.name }} /
{{ item.address }}
<img :src="item.image_url.shop_image1" alt="test">
</li></div>`
});
new Vue({
el: '#app',
data () {
return {
info: null
}
},
mounted () {
axios
.get('https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid=XXXXX&name=かねさか')
.then(response => (this.info = response.data.rest))
}
})

The New York Times Developer Network

API Key 作成

Get Started | Dev Portal

Register apps

  • Select My Apps from the user drop-down.
  • New APP クリック
    • Enter a name and description for the app in the New App dialog.
      • name: vue-test で登録
    • Top Stories API をチェック
    • CREATE 押下

API Key 確認

API 仕様確認

Top Stories | Dev Portal

/{section}.json
  • The possible section value are:
    • arts
    • automobiles
    • books
    • business
    • fashion
    • food
    • health
    • home
    • insider
    • magazine
    • movies
    • national
    • nyregion
    • obituaries
    • opinion
    • politics
    • realestate
    • science
    • sports
    • sundayreview
    • technology
    • theater
    • tmagazine
    • travel
    • upshot
    • and world.

Example Call

https://api.nytimes.com/svc/topstories/v2/home.json?api-key=yourkey

参考サイト

Github

<!-- index.html (ver1) -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>The greatest news app ever</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/foundation/6.3.1/css/foundation.min.css">
</head>
<body>
<div class="container" id="app">
<h3 class="text-center">VueNews</h3>
<div class="columns medium-3" v-for="result in results">
<div class="card">
<div class="card-divider">
{{ result.title }}
</div>
<div class="card-section">
<p>{{ result.abstract }}.</p>
</div>
</div>
</div>
</div>
<script src="https://unpkg.com/vue"></script>
<script src="app.js"></script>
</body>
</html>
// app.js (ver1)
const vm = new Vue({
el: '#app',
data: {
results: [
{title: "the very first post", abstract: "lorem ipsum some test dimpsum"},
{title: "and then there was the second", abstract: "lorem ipsum some test dimsum"},
{title: "third time's a charm", abstract: "lorem ipsum some test dimsum"},
{title: "four the last time", abstract: "lorem ipsum some test dimsum"}
]
}
});
<!-- index.html (ver2) -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>The greatest news app ever</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/foundation/6.3.1/css/foundation.min.css">
</head>
<body>
<div class="container" id="app">
<h3 class="text-center">VueNews</h3>
<div class="columns medium-3" v-for="result in results">
<div class="card">
<div class="card-divider">
{{ result.title }}
</div>
<div class="card-section">
<p>{{ result.abstract }}.</p>
</div>
</div>
</div>
</div>
<script src="https://unpkg.com/vue"></script>
<!-- 追加 -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="app.js"></script>
</body>
</html>
// app.js (ver2)
const vm = new Vue({
el: '#app',
data: {
results: [
// 消去
// {title: "the very first post", abstract: "lorem ipsum some test dimpsum"},
// {title: "and then there was the second", abstract: "lorem ipsum some test dimsum"},
// {title: "third time's a charm", abstract: "lorem ipsum some test dimsum"},
// {title: "four the last time", abstract: "lorem ipsum some test dimsum"}
]
},
// 追加
mounted() {
axios.get("https://api.nytimes.com/svc/topstories/v2/home.json?api-key=your_api_key")
.then(response => {this.results = response.data.results})
}
});
// app.js (ver3)
const NYTBaseUrl = "https://api.nytimes.com/svc/topstories/v2/"
const ApiKey = "your_api_key"
function buildUrl(section) {
return NYTBaseUrl + section + ".json?api-key=" + ApiKey
}
const vm = new Vue({
el: '#app',
data: {
results: []
},
mounted() {
this.getPosts('home');
},
methods: {
getPosts(section) {
let url = buildUrl(section);
axios.get(url).then((response) => {
this.results = response.data.results
}).catch(error => {
console.log(error);
});
}
}
});
// app.js (ver4)
//
// Computed Properties を導入
// APIから得られるオリジナルの結果に少し修正を加え、
// ビューの見栄えに多少の変更を加えます
//
const NYTBaseUrl = "https://api.nytimes.com/svc/topstories/v2/"
const ApiKey = "your_api_key"
function buildUrl(section) {
return NYTBaseUrl + section + ".json?api-key=" + ApiKey
}
const vm = new Vue({
el: '#app',
data: {
results: []
},
mounted() {
this.getPosts('home');
},
methods: {
getPosts(section) {
let url = buildUrl(section);
axios.get(url).then((response) => {
this.results = response.data.results
}).catch(error => {
console.log(error);
});
}
},
// それぞれのニュース記事オブジェクトに image_url 属性を付加
//
// APIの results をループし、
// 個々の result の multimedia 配列をサーチして、
// 必要とするフォーマットのメディアタイプを見つけ、
// そのメディアのURLを image_url 属性にアサイン
computed: {
processedPosts() {
let posts = this.results;
// Add image_url attribute
posts.map(post => {
let imgObj = post.multimedia.find(media => media.format === "superJumbo");
post.image_url = imgObj ? imgObj.url : "http://placehold.it/300x200?text=N/A";
});
// Put Array into Chunks
let i, j, chunkedArray = [], chunk = 4;
for (i = 0, j = 0; i < posts.length; i += chunk, j++) {
chunkedArray[j] = posts.slice(i, i + chunk);
}
return chunkedArray;
}
}
});
<!-- index.html (ver4) -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>The greatest news app ever</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/foundation/6.3.1/css/foundation.min.css">
</head>
<body>
<div class="container" id="app">
<h3 class="text-center">VueNews</h3>
<!--<div class="columns medium-3" v-for="result in results">-->
<!--<div class="card">-->
<!--<div class="card-divider">-->
<!--{{ result.title }}-->
<!--</div>-->
<!--<div class="card-section">-->
<!--<p>{{ result.abstract }}.</p>-->
<!--</div>-->
<!--</div>-->
<!--</div>-->
<!--修正-->
<div class="row" v-for="posts in processedPosts">
<div class="columns large-3 medium-6" v-for="post in posts">
<div class="card">
<div class="card-divider">
{{ post.title }}
</div>
<a :href="post.url" target="_blank"><img :src="post.image_url"></a>
<div class="card-section">
<p>{{ post.abstract }}</p>
</div>
</div>
</div>
</div>
</div>
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="app.js"></script>
</body>
</html>
// app.js (ver5)
const NYTBaseUrl = "https://api.nytimes.com/svc/topstories/v2/"
const ApiKey = "your_api_key"
function buildUrl(section) {
return NYTBaseUrl + section + ".json?api-key=" + ApiKey
}
Vue.component('news-list', {
props:['results'],
// <section> タグでリストを囲む。
// コンポーネントが root element を1つだけしか持てず、複数持てないから
// ( div.row の繰り返しで、複数生成される可能性がある )
template: `
<section>
<div class="row" v-for="posts in processedPosts">
<div class="columns large-3 medium-6" v-for="post in posts">
<div class="card">
<div class="card-divider">
{{ post.title }}
</div>
<a :href="post.url" target="_blank"><img :src="post.image_url"></a>
<div class="card-section">
<p>{{ post.abstract }}</p>
</div>
</div>
</div>
</div>
</section>
`,
computed: {
processedPosts() {
let posts = this.results;
// Add image_url attribute
posts.map(post => {
let imgObj = post.multimedia.find(media => media.format === "superJumbo");
post.image_url = imgObj ? imgObj.url : "http://placehold.it/300x200?text=N/A";
});
// Put Array into Chunks
let i, j, chunkedArray = [], chunk = 4;
for (i = 0, j = 0; i < posts.length; i += chunk, j++) {
chunkedArray[j] = posts.slice(i, i + chunk);
}
return chunkedArray;
}
}
});
const vm = new Vue({
el: '#app',
data: {
results: []
},
mounted() {
this.getPosts('home');
},
methods: {
getPosts(section) {
let url = buildUrl(section);
axios.get(url).then((response) => {
this.results = response.data.results
}).catch(error => {
console.log(error);
});
}
}
});
<!-- index.html (ver5) -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>The greatest news app ever</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/foundation/6.3.1/css/foundation.min.css">
</head>
<body>
<div class="container" id="app">
<h3 class="text-center">VueNews</h3>
<!--<div class="row" v-for="posts in processedPosts">-->
<!--<div class="columns large-3 medium-6" v-for="post in posts">-->
<!--<div class="card">-->
<!--<div class="card-divider">-->
<!--{{ post.title }}-->
<!--</div>-->
<!--<a :href="post.url" target="_blank"><img :src="post.image_url"></a>-->
<!--<div class="card-section">-->
<!--<p>{{ post.abstract }}</p>-->
<!--</div>-->
<!--</div>-->
<!--</div>-->
<!--</div>-->
<!--変更-->
<news-list :results="results"></news-list>
</div>
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="app.js"></script>
</body>
</html>

カテゴリーフィルターを実装

app.js

const SECTIONS = "home, arts, automobiles, books, business";
const vm = new Vue({
  el: '#app',
  data: {
    results: [],
    // 追加
    sections: SECTIONS.split(', '), // create an array of the sections
    section: 'home',                // set default section to 'home'
  },
  mounted () {
    this.getPosts(this.section);
  },

index.html

        <!-- セクション選択コンボ -->
        <select v-model="section">
          <option v-for="section in sections" :value="section">{{ section }}</option>
        </select>
        <!-- 検索ボタン -->
        <a @click="getPosts(section)" class="button expanded">Retrieve</a>
// app.js (ver6)
const NYTBaseUrl = "https://api.nytimes.com/svc/topstories/v2/"
const ApiKey = "your_api_key"
function buildUrl(section) {
return NYTBaseUrl + section + ".json?api-key=" + ApiKey
}
Vue.component('news-list', {
props:['results'],
template: `
<section>
<div class="row" v-for="posts in processedPosts">
<div class="columns large-3 medium-6" v-for="post in posts">
<div class="card">
<div class="card-divider">
{{ post.title }}
</div>
<a :href="post.url" target="_blank"><img :src="post.image_url"></a>
<div class="card-section">
<p>{{ post.abstract }}</p>
</div>
</div>
</div>
</div>
</section>
`,
computed: {
processedPosts() {
let posts = this.results;
// Add image_url attribute
posts.map(post => {
let imgObj = post.multimedia.find(media => media.format === "superJumbo");
post.image_url = imgObj ? imgObj.url : "http://placehold.it/300x200?text=N/A";
});
// Put Array into Chunks
let i, j, chunkedArray = [], chunk = 4;
for (i = 0, j = 0; i < posts.length; i += chunk, j++) {
chunkedArray[j] = posts.slice(i, i + chunk);
}
return chunkedArray;
}
}
});
// カテゴリーフィルターを実装
const SECTIONS = "home, arts, automobiles, books, business";
const vm = new Vue({
el: '#app',
data: {
results: [],
// 追加
sections: SECTIONS.split(', '), // create an array of the sections
section: 'home', // set default section to 'home'
},
mounted() {
// this.getPosts('home');
// 変更
this.getPosts(this.section);
},
methods: {
getPosts(section) {
let url = buildUrl(section);
axios.get(url).then((response) => {
this.results = response.data.results
}).catch(error => {
console.log(error);
});
}
}
});
<!-- index.html (ver6) -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>The greatest news app ever</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/foundation/6.3.1/css/foundation.min.css">
</head>
<body>
<div class="container" id="app">
<h3 class="text-center">VueNews</h3>
<!--追加-->
<section class="callout secondary">
<h5 class="text-center">Filter by Category</h5>
<form>
<div class="row">
<div class="large-6 columns">
<!-- セクション選択コンボ -->
<select v-model="section">
<option v-for="section in sections" :value="section">{{ section }}</option>
</select>
</div>
<div class="medium-6 columns">
<!-- 検索ボタン -->
<a @click="getPosts(section)" class="button expanded">Retrieve</a>
</div>
</div>
</form>
</section>
<news-list :results="results"></news-list>
</div>
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="app.js"></script>
</body>
</html>

loading フラグ, title 追加

app.js

const vm = new Vue({
  el: '#app',
  data: {
    // (中略)
    // 追加
    loading: true,
    title: ''
  },
  // (中略)
  methods: {
    getPosts(section) {
      let url = buildUrl(section);
      axios.get(url).then((response) => {
        // 追加
        this.loading = false;
        this.results = response.data.results;
        // 追加
        let title = this.section !== 'home' ? "Top stories in '"+ this.section + "' today" : "Top stories today";
        this.title = title + "(" + response.data.num_results + ")";
      }).catch((error) => { console.log(error); });
    }
  }  
});

index.html

<!-- 追加 -->
<h5 class="text-center uppercase" v-if="!loading">{{ title }}</b></h5>
<div v-if="loading" class="loader"><img src="http://cdnjs.cloudflare.com/ajax/libs/semantic-ui/0.16.1/images/loader-large.gif" alt="loader"></div>
<!-- 変更 -->
<!--<news-list :results="results"></news-list>-->
<news-list v-if="!loading" :results="results"></news-list>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment