卡片链接
-
卡片链接
卡片链接往往比单纯的放一个链接,视觉效果更加的友好。更能够吸引读者去点击阅读,增加点击量和阅读量。
-
简单实现一个卡片链接
- 使用nodejs作为后台解析。
- 使用模块: cheerio,爬取网页链接基本信息。
-
爬虫函数的实现
3.1 爬虫函数
const request = async url => {
const request = axios.create();
request.interceptors.request.use(config => {
config.headers['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36'
// config.headers['Referer'] = url
// config.headers['Origin'] = rootUrl(url)
return config
})
return request.get(url).then(result => {
let body = result.data;
// 加载数据
const $ = cheerio.load(body);
const title = findTitle($); // 获取链接标题
const description = findDescription($); // 获取链接简要描述内容
const icon = findLinkIcon($, url); // 获取链接icon
const image = findImage($) // 获取图片
return {
title,
url,
description,
icon,
image
};
})
};
3.2 获取链接标题
const findTitle = $ => {
const title = $('title').text().trim();
const metaList = $('meta[property]');
if (title === '') {
for (const meta of metaList) {
if (get(meta, 'attribs.property', '').indexOf('title') !== -1) {
return get(meta, 'attribs.content', '');
}
}
}
return title;
};
3.3获取链接描述内容
const findDescription = $ => {
const match_description = $('meta[name=description]')['0'];
if (match_description) {
return get(match_description, 'attribs.content', '');
}
const metaList = $('meta');
for (const meta of metaList) {
if (get(meta, 'attribs.name', '').indexOf('description') !== -1) {
return get(meta, 'attribs.content', '');
}
}
return '';
};
3.4 获取链接描述内容
const findLinkIcon = ( $ , url) => {
const handle_link = link => {
if (link.startsWith('//')) {
return 'http://' + link.slice(2);
}
if (link.startsWith('/')) {
return rootUrl(url) + link;
}
return link;
};
const icon = $('link[rel=icon]')['0'];
if (icon) {
return handle_link(get(icon, 'attribs.href', ''));
}
const linkList = $('link[rel]');
for (const link of linkList) {
if (get(link, 'attribs.rel', '').indexOf('icon') !== -1) {
return handle_link(get(link, 'attribs.href', ''));
}
}
return '';
};
3.5 获取链接描述内容
const findImage = $ => {
const metaList = $('meta[property]');
for (const meta of metaList) {
if (get(meta, 'attribs.property', '').indexOf('og:image') !== -1) {
return get(meta, 'attribs.content', '');
}
}
return ''
}
-
前端实现
前端就比较好实现了,根据服务器返回来的title,icon,description,image,进行布局就好。
4.1 LinkCard.tsx
export default function LinkCard(props: any): React.ReactElement {
let {
link
} = props
// let link = {
// title: 'lodash的get方法 - SegmentFault 思否',
// url: 'https://segmentfault.com/a/1190000015605531',
// description:
// 'get这个方法,在lodash中是出场率很高的方法,初识起来有些疑惑,看了demo,又很直观。 get方法源码链接 下边是它的使用说明 {代码...} 根据object对象的path路径获取值。如果解析值是undefined,就返回一个默认的值(defaultValue) {代码...} 暂时不考虑第第三个参数,只考虑第二个参数,该参数的含义就是路径。 指向obj...',
// icon: 'https://cdn.segmentfault.com/r-fd1f02aa/favicon.ico',
// };
const [innerLink,setInnerLink] = useState(link);
useEffect(() => {
// console.log(innerLink)
if (!innerLink.isSpider) {
updateLinkInfo({
link_id: innerLink.id,
url: innerLink.url
}).then(res => {
// console.log(res.data.data)
setInnerLink(res.data.data)
})
}
}, [])
return (
<Link href={link.url} target="_blank" >
<div className={styles.container}>
<div className={cls(styles.left,{
[styles.hideLeft]: innerLink.image
})}>
<div>
{innerLink.title && (
<div className={styles.title}>
<span>{innerLink.title}</span>
</div>
)}
{innerLink.description && (
<div className={styles.content}>
<span> {innerLink.description}</span>
</div>
)}
</div>
<div className={styles.link}>
{innerLink.icon && <img src={innerLink.icon} alt="" />}
<span>{innerLink.url}</span>
</div>
</div>
{
innerLink.image && <div className={styles.right}>
<img className={styles.coverimage} src={innerLink.image} alt="" />
</div>
}
</div>
</Link>
);
}
4.2 index.less
css这里就添一个比较重要的内容。卡片需要显示几行描述文字。
.content {
font-size: 12px;
font-family: 'mono';
color: #333;
margin-bottom: 5px;
max-height: 120px;
width: 100%;
display: -webkit-box;/** 对象作为伸缩盒子模型显示 **/
word-break: break-all;
text-overflow: ellipsis;
-webkit-box-orient: vertical;/** 设置或检索伸缩盒对象的子元素的排列方式 **/
-webkit-line-clamp: 2;/** 显示的行数 **/
overflow: hidden;
}