add vue-router and detail page

This commit is contained in:
YuukanOO 2021-01-21 09:11:41 +01:00
parent 75b818c378
commit c678841406
13 changed files with 189 additions and 12 deletions

View File

@ -10982,6 +10982,11 @@
} }
} }
}, },
"vue-router": {
"version": "3.4.9",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.4.9.tgz",
"integrity": "sha512-CGAKWN44RqXW06oC+u4mPgHLQQi2t6vLD/JbGRDAXm0YpMv0bgpKuU5bBd7AvMgfTz9kXVRIWKHqRwGEb8xFkA=="
},
"vue-style-loader": { "vue-style-loader": {
"version": "4.1.2", "version": "4.1.2",
"resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.2.tgz", "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.2.tgz",

View File

@ -9,7 +9,8 @@
}, },
"dependencies": { "dependencies": {
"core-js": "^3.6.5", "core-js": "^3.6.5",
"vue": "^2.6.11" "vue": "^2.6.11",
"vue-router": "^3.4.9"
}, },
"devDependencies": { "devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0", "@vue/cli-plugin-babel": "~4.5.0",

8
hn-vue/src/Layout.vue Normal file
View File

@ -0,0 +1,8 @@
<template>
<div>
<nav>
<router-link :to="{ name: 'links' }">Derniers liens publiés</router-link>
</nav>
<router-view></router-view>
</div>
</template>

View File

@ -7,12 +7,26 @@ class Api {
return this._get("/api/links"); return this._get("/api/links");
} }
getLinkById(id) {
return this._get(`/api/links/${id}`);
}
getLinkComments(id) {
return this._get(`/api/links/${id}/comments`);
}
_get(path) { _get(path) {
return fetch(this.baseUrl + path, { return fetch(this.baseUrl + path, {
headers: { headers: {
Accept: "application/json", Accept: "application/json",
}, },
}).then((r) => r.json()); }).then((r) => {
if (!r.ok) {
return Promise.reject(new Error("Erreur dans la requête"));
}
return r.json();
});
} }
} }

View File

@ -0,0 +1,20 @@
<template>
<article>
<p>{{ comment.content }}</p>
<p>
Publié le {{ comment.createdAt }} par {{ comment.createdBy.username }}
</p>
<p>👍 {{ comment.upvotesCount }} / 👎 {{ comment.downvotesCount }}</p>
</article>
</template>
<script>
export default {
props: {
comment: {
type: Object,
required: true,
},
},
};
</script>

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="error">{{ err.message }}</div> <div class="error">{{ error.message }}</div>
</template> </template>
<script> <script>

View File

@ -1,6 +1,10 @@
<template> <template>
<article> <article>
<h2>{{ link.url }}</h2> <h2>
<router-link :to="{ name: 'link', params: { id: link.id } }">{{
link.url
}}</router-link>
</h2>
<p>Publié le {{ link.createdAt }} par {{ link.createdBy.username }}</p> <p>Publié le {{ link.createdAt }} par {{ link.createdBy.username }}</p>
<p>👍 {{ link.upvotesCount }} / 👎 {{ link.downvotesCount }}</p> <p>👍 {{ link.upvotesCount }} / 👎 {{ link.downvotesCount }}</p>
</article> </article>

View File

@ -1,8 +1,12 @@
import Vue from "vue"; import Vue from "vue";
import Links from "./Links.vue"; import Layout from "./Layout.vue";
import createRouter from "./router";
Vue.config.productionTip = false; Vue.config.productionTip = false;
const router = createRouter();
new Vue({ new Vue({
render: (h) => h(Links), router,
render: (h) => h(Layout),
}).$mount("#app"); }).$mount("#app");

View File

@ -0,0 +1,69 @@
<template>
<div>
<h1>Détail du lien</h1>
<error v-if="err" :error="err" />
<loading
v-else-if="link === null"
message="Chargement du lien en cours ..."
/>
<div v-else>
<link-item :link="link" />
<loading v-if="comments === null" message="Chargement des commentaires" />
<p v-else-if="comments.length === 0">Aucun commentaire pour ce lien</p>
<ul v-else>
<li v-for="comment in comments" :key="comment.id">
<comment :comment="comment" />
</li>
</ul>
</div>
</div>
</template>
<script>
import LinkItem from "../components/LinkItem.vue";
import Comment from "../components/Comment.vue";
import Error from "../components/Error.vue";
import Loading from "../components/Loading.vue";
import api from "../api";
export default {
props: {
id: {
type: String,
required: true,
},
},
data() {
return {
link: null,
comments: null,
err: null,
};
},
components: { LinkItem, Error, Loading, Comment },
mounted() {
this.fetchLinkDetail();
},
watch: {
// id: 'fetchLinkDetail'
id() {
this.fetchLinkDetail();
},
// '$route': 'fetchLinkDetail'
},
methods: {
async fetchLinkDetail() {
this.link = null;
this.comments = null;
this.err = null;
try {
this.link = await api.getLinkById(this.id);
this.comments = await api.getLinkComments(this.id);
} catch (e) {
this.err = e;
}
},
},
};
</script>

View File

@ -1,11 +1,11 @@
<template> <template>
<div> <div>
<h1>Derniers liens publiés</h1> <h1>Derniers liens publiés</h1>
<error v-if="err" :error="err" />
<loading <loading
v-if="links === null" v-else-if="links === null"
message="Chargement des liens en cours ..." message="Chargement des liens en cours ..."
/> />
<error v-else-if="err" :error="err" />
<ul v-else> <ul v-else>
<li v-for="link in links" :key="link.id"> <li v-for="link in links" :key="link.id">
<link-item :link="link" /> <link-item :link="link" />
@ -15,10 +15,10 @@
</template> </template>
<script> <script>
import Error from "./components/Error.vue"; import Error from "../components/Error.vue";
import Loading from "./components/Loading.vue"; import Loading from "../components/Loading.vue";
import LinkItem from "./components/LinkItem.vue"; import LinkItem from "../components/LinkItem.vue";
import api from "./api"; import api from "../api";
export default { export default {
components: { Loading, Error, LinkItem }, components: { Loading, Error, LinkItem },

23
hn-vue/src/router.js Normal file
View File

@ -0,0 +1,23 @@
import Vue from "vue";
import VueRouter from "vue-router";
import Links from "./pages/Links.vue";
import LinkDetail from "./pages/LinkDetail.vue";
Vue.use(VueRouter);
export default function createRouter() {
const router = new VueRouter({
routes: [
{ path: "/", name: "links", component: Links },
{
path: "/links/:id",
name: "link",
component: LinkDetail,
props: true,
},
{ path: "*", redirect: "/" },
],
});
return router;
}

View File

@ -0,0 +1,20 @@
<template>
<div>
<p v-if="link">{{ link.url }}</p>
</div>
</template>
<script>
export default {
data() {
return { link: null };
},
async beforeRouteEnter(to, from, next) {
const link = await fetch(
`https://hn-dotnet.herokuapp.com/api/links/${to.params.id}`
).then((r) => r.json());
to.meta.title = "Visualisation de " + link.url;
next((vm) => (vm.link = link));
},
};
</script>

View File

@ -18,6 +18,8 @@ const AForm = () =>
import(/* webpackChunkName: "aform" */ "./components/AForm.vue"); import(/* webpackChunkName: "aform" */ "./components/AForm.vue");
const Counter = () => const Counter = () =>
import(/* webpackChunkName: "counter" */ "./components/Counter.vue"); import(/* webpackChunkName: "counter" */ "./components/Counter.vue");
const Link = () =>
import(/* webpackChunkName: "link" */ "./components/Link.vue");
Vue.use(VueRouter); Vue.use(VueRouter);
@ -74,6 +76,12 @@ const router = new VueRouter({
}, },
], ],
}, },
{
path: "/link/:id",
component: Link,
name: "link",
meta: {},
},
{ {
path: "/card/:a/:b", path: "/card/:a/:b",
component: Card, component: Card,
@ -98,6 +106,7 @@ router.beforeEach((to, from, next) => {
}); });
router.afterEach((to) => { router.afterEach((to) => {
console.log(to.matched);
document.title = to.meta.title; document.title = to.meta.title;
}); });