摄影小白怎样选购微单

4. 相机有美肤模式,但不失真,不模糊过度,是自拍界清流,人像功能拍得皮肤很好

5. 富士是aps-c格式,使它在进行大幅展示,打印的时候精细程度会更好

缺点:

1. 对焦慢,拍运动状态困难,很多使用者说容易拍糊

2. 配的套头有点重

3. 传照片很慢,同样300张照片,索尼a6000只要5分钟,富士xa5要40分钟

4. 无取景器

5. 拍不出阳光的效果

测评结果

重,容易拍糊,不考虑

索尼a5100

和索尼a6000比,可翻转自拍,但没有4d对焦,没有取景器,很多单反应有的操作没有

测评结果

很多单反应有的操作没有,不考虑

索尼a6000

优点:

1. 对焦速度快

2. 追焦成功率高,通过连拍可将运动物体完美捕捉

3. 有wifi传输功能

4. 有取景器

5. 轻便

缺点:

1. 没有屏幕旋转自拍功能,但可以用playmemoryapp,用手机远程遥控相机拍摄

2. 和富士对比后,拍人会发黄

3. 没有美颜模式(但感觉有自动美颜)

测评结果

追焦成功率高,可通过连拍将运动物体完美捕捉,轻便,考虑

奥林巴斯em10-II

优点:

1. 触摸对焦功能,简单方便

2. 黑科技五轴防抖功能,可以在比较暗的环境也能拍摄到清晰的照片

3. 机内拼图功能,滤镜模式,美颜功能,滤镜出彩

4. 有wifi传输功能

5. 机身轻便体积小,官配的饼干镜头很轻

6. 外形很复古,很好看

7. 型号III比型号II增加了4k视频功能,拍视频有提升,但型号II拍视频效果也还可以

8. 有取景器

缺点:

1. 不能自拍,但可用app遥控拍照

测评结果

防抖功能,可以在暗的环境拍到清晰的照片,还有复古外形,而且很轻,考虑

松下gf9

优点:

1. 可自拍,贴近主流的自拍效果,有十度美肤十度瘦身功能,自拍是日系暖风感觉

2. 轻薄,口袋机

3. 支持wifi传输

缺点:

1. 夜拍效果一般

测评结果

主打自拍功能,但其他没有自拍功能的机型可以通过手机app控制拍照来弥补,所以无感,夜拍效果一般,不考虑

佳能M6

配套镜头选择很少,未来想配镜头时选择会比较少,并没有特别突出的优点

测评结果

配套镜头选择很少,不考虑

根据我的诉求,结合优缺点的对比分析,选出了以下两个候选者:

索尼a6000 3528元

奥林巴斯em10-II 3899元

综合考量:

1. 都很轻便

2. 都不能自拍但可用手机app控制来完成自拍

3. 长得都挺好看,但更喜欢奥林巴斯的复古外形

4. 奥林巴斯em10-II是防抖特性,索尼a6000是高速连拍特性,但平时没有连拍习惯,觉得防抖特性更吸引我

所以,最后的最后,我选择了奥林巴斯em10-II。在京东下的单,第二天就寄到了。希望自己可以好好利用这个相机,记录美好的日常。

周末去上海当代艺术博物馆溜了一圈,展品很棒

今天就说到这儿,回头见!

普元好物记

好物 | 糟物 | 生活小记

好用才会好好用。

几个你不知道却非常实用的JavaScript APIs

前言

在本文中,将介绍一些鲜为人知但却非常有用的API,如:

我们将一起看看它们是什么,我们应该在哪里使用它们,以及如何使用它们。

Page Visibility API

这是一个鲜为人知的 web API,在JS现状调查[1]中,它的认知度排名倒数第四。它可以让你知道用户何时离开了页面。准确地说,只要页面的可见性状态发生变化,无论是用户最小化、最大化窗口还是切换标签页,该API都会触发一个事件。

在过去,你不得不使用一些噱头来了解用户是否切换了标签页或最小化了窗口。最流行的方式是使用blur和focus浏览器事件。使用这些事件会导致类似下面情况的发生:

window.addEventListener("focus"function ({
    // User is back on the page
    // Do Something
});

window.addEventListener("blur"function ({
    // User left the page
    // Do Something
});

前面的代码可以工作,但是不符合预期。因为blur事件是在页面失去焦点时触发的,所以当用户点击搜索栏、alert对话框、控制台或窗口边框时,它就会被触发。所以,blur和focus只告诉我们页面是否被激活,但不告诉我们页面的内容是否被隐藏或显示。

什么时候使用

一般来说,我们想要使用Page Visibility API,是希望用来停止不必要的程序。比如说当用户没有看到页面时,或者执行后台操作时。具体的场景可以是:

如何使用

Page Visibility API带来了两个属性和一个事件,用于访问页面可见性状态:

visibilitychange:这是一个由document对象提供的事件,当页面的visibilityState发生变化时被触发。

document.addEventListener("visibilitychange", () => {
    if (document.visibilityState === "visible") {
        // page is visible
    } else {
        // page is hidden
    }
});

为了了解如何使用Page Visibility API,让我们用该特性来实现当用户离开页面时,暂停视频以及停止从API获取资源。首先,我将使用vite.js,它是一个快速启动新项目的神奇工具:

npm create vite@latest unknown-web-apis

当被要求选择一个框架时,选择vanilla来创建一个vanillajavascript项目。完成之后,前往新文件夹,安装必要的npm包并启动开发服务器:

cd unknown-web-apis
npm install
npm run dev

打开localhost:3000/[2],你将看到你的Vite项目启动和运行!

vite-new-project.png

首先,我们直接跳转到/main.js文件并删除所有样板代码。其次,打开/index.html,在id为#app的div标签内部添加一个video元素,上面可以添加你想添加的任意视频文件。这里我使用了一只正在跳舞的耀西。

<div id="app">
    <video controls id="video">
        <source src="./yoshi.mp4" />
    video>
div>

dancing-Yoshi.png

回到/main.js,我们将向document对象添加一个事件监听器,用来监听visibilitychange事件。然后当页面显示或隐藏时,我们可以访问document.visibilityState属性的值。

document.addEventListener("visibilitychange", () => {
    console.log(document.visibilityState);
});

你可以前往页面的控制台,当最小化窗口或者切换到另一个标签页时,查看页面可见性状态。现在,在事件监听器内部,我们可以检查document.visibilityState属性,当属性值为hidden时暂停视频,当属性值为visible时 视频。当然,我们首先要使用document.querySelector()选择video元素。

const video = document.querySelector("#video");

document.addEventListener("visibilitychange", () => {
    if (document.visibilityState === "visible") {
        video.play();
    } else {
        video.pause();
    }
});

现在,只要用户离开页面,视频就会停止。另一个使用Page Visibility API的场景是,当用户没有查看页面时,停止获取不必要的资源。为了看效果,我们将编写一个函数不间断地从quotable.io[3] API获取随机引用,并当页面隐藏时暂停该行为。首先,我们将在/index.html创建一个新的div标签来存储引用。

<div id="app">
    <video controls id="video">
        <source src="./yoshi.mp4" />
    video>
    <div id="quote">div>
div>

回到/main.js,我们使用Fetch API[4]发起对quotable.io端点[5] 的调用,然后将结果插入到quotediv中。

const quote = document.querySelector('#quote');

const getQuote = async () => {
  try {
    const response = await fetch('');
    const { content, author, dateAdded } = await response.json();
    const parsedQuote = ${content} 
 

${author}


 

Added on ${dateAdded}

`
;
    quote.innerHTML = parsedQuote;
  } catch (error) {
    console.error(error);
  }
};

让我们简单地解释一下此处发生了什么。首先我们从DOM中选中了quote元素。然后声明getQuote函数,该函数是一个异步函数,允许我们使用await关键字进行等待,直到从API中获取到数据。获取的数据是JSON格式的,因此我们再次使用await关键字来等待,直到数据被解析为JavaScript对象。

quotable.io的API为我们提供了content、author和dateAdded等属性,我们把这些属性注入并显示在quotediv中。这样做是没问题的,但是引用只会获取一次,因此我们可以使用setInterval()每10秒来调用一次函数。

const quote = document.querySelector('#quote');

const getQuote = async () => {
  try {
    const response = await fetch('');
    const { content, author, dateAdded } = await response.json();
    const parsedQuote = ${content} 
 

${author}


 

Added on ${dateAdded}

`
;
    quote.innerHTML = parsedQuote;
  } catch (error) {
    console.error(error);
  }
};

getQuote();

setInterval(getQuote, 10000);

如果用户最小化窗口或者切换标签页,该页面仍然会获取引用,创建没有必要的网络加载。为了解决这个问题,在获取引用之前我们可以检查当前页面是否可见。

const getQuote = async () => {
  if (document.visibilityState === 'visible') {
    try {
      const response = await fetch('');
      const { content, author, dateAdded } = await response.json();
      const parsedQuote = `
          ${content} 
 
          

${author}


 
          

Added on ${dateAdded}

`
;
      quote.innerHTML = parsedQuote;
    } catch (error) {
      console.error(error);
    }
  }
};

getQuote();

setInterval(getQuote, 10000);

现在,我们只会在页面对用户可见的情况下获取引用。

兼容性

广泛支持[6]

Web Share API这是什么

Web Share API也是最不为人所知的API之一,但却非常有用。它可以让你访问操作系统的原生分享机制,这对移动端用户特别有用。有了这个API,你可以分享文本、链接和文件,而不需要创建你自己的分享机制或使用第三方的分享机制。

什么时候使用

用途已经不言自明。你可以用它将你的页面内容分享到社交媒体上,或将其复制到用户的剪贴板上。

如何使用

Web Share API赋予我们两个接口来访问用户的分享系统:

navigator.canShare():接受你想分享的数据作为参数,并根据其是否可分享,来返回一个布尔参数。

navigator.share():返回一个promise,如果分享成功的话,该promise将会resolve。该接口会调用原生分享机制,并接收你想分享的数据作为参数。注意,它只能在用户按下链接或按钮时调用。也就是说,它需要transient activation[7](瞬时激活)。分享数据是一个可以具有以下属性的对象:

为了了解如何使用该API,我们将回收先前的用例,做一个选项使用Web Sharing API来分享我们的引用。首先,我们必须在/index.html新增一个分享按钮:

<div id="app">
    <video controls id="video">
        <source src="./yoshi.mp4" />
    video>
    <div id="quote">div>
    <button type="button" id="share-button">Share Quotebutton>
div>

前往/main.js从DOM中选择分享按钮。然后,创建async函数来分享想要分享的数据。

const shareButton = document.querySelector("#share-button");

const shareQuote = async (shareData) => {
    try {
        await navigator.share(shareData);
    } catch (error) {
        console.error(error);
    }
};

现在,我们可以为shareButton元素添加click事件监听器,以此来调用shareQuote函数。shareData.text的值会是quote.textContent属性,shareData.url的值会是页面的URL,也就是location.href属性。

const shareButton = document.querySelector("#share-button");

const shareQuote = async (shareData) => {
    try {
        await navigator.share(shareData);
    } catch (error) {
        console.error(error);
    }
};

shareButton.addEventListener("click", () => {
    let shareData = {
        title"A Beautiful Quote",
        text: quote.textContent,
        url: location.href,
    };

    shareQuote(shareData);
});

现在你可以通过你的原生操作系统与任何人分享你的引用。然而,需要注意的是,Web Share API只有在上下文安全的情况下才会起作用,也就是说,页面是通过或wss:// URLs提供的。

兼容性

基本不支持[8]

Broadcast Channel API这是什么

我想谈论的另一个API是Broadcast Channel API 。它允许浏览器上下文互相发送和接收基本数据。浏览器上下文是指标签页、窗口、iframe等元素,或任何可以显示页面的地方。出于安全考量,浏览器上下文之间的通信是不被允许的,除非它们是同源的并使用Broadcast Channel API。对于两个同源的浏览器上下文,它们的URL必须有相同的协议(如http/https)、域(如example.com)和端口(如:8080)。

什么时候使用

Broadcast Channel API通常用于在不同的标签页和窗口之间保持页面状态同步,以提高用户体验或出于安全原因考虑。它也可以用来知道一个服务在另一个标签页或窗口中何时完成。使用场景有:

如何使用

Broadcast Channel API涉及一个BroadcastChannel对象,该对象可用于向其他上下文发送信息。构造函数只有一个参数:作为标识符的字符串,该标识符从其他上下文连接到频道。

const broadcast = new BroadcastChannel("new_channel");

一旦我们在两个上下文中创建了具有相同标识符的BroadcastChannel对象,这个新的BroadcastChannel对象将有两个可用的方法来开始进行通信:

为了接受信息,BroadcastChannel有一个message事件,我们可以使用addEventListener或其onmessage属性来监听。message事件有一个data属性,包含发送的数据和其他属性,以识别发送消息的上下文,如origin、lastEventId、source和ports。

broadcast.onmessage = ({data, origin}) => {
    console.log(`${origin} says ${data}`);
};

让我们看看如何通过使用先前的例子来使用Broadcast Channel API。我们的目标是制作另一个具有同源的浏览器上下文,并在两个上下文中展示相同的引用。为了做到这一点,我们将创建一个名为new-origin的新文件夹,里面有一个新的/index.html和/main.js文件。

/new-origin/index.html将是一个新的HTML模板,里面有一个#quotediv:

html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <link rel="icon" type="image/svg+xml" href="../favicon.svg" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Vite Apptitle>
    head>
    <body>
        <div id="quote">div>
        <script type="module" src="./main.js">script>
    body>
html>

在/new-origin/main.js文件中,我们将创建一个新的broadcast channel,并从DOM中选择#quote元素:

const broadcast = new BroadcastChannel("quote_channel");
const quote = document.querySelector("#quote");

在先前的/main.js文件中,我们将创建新的BroadcastChannel对象,并连接到"quote_channel"。我们还将修改getQuote函数,将引用作为消息发送到其他上下文。

const broadcast = new BroadcastChannel("quote_channel");

//...

const getQuote = async () => {
 try {
  const response = await fetch("");
  const {content, author, dateAdded} = await response.json();
  const parsedQuote = ${content} 
 

${author}


 

Added on ${dateAdded}

`
;
  quote.innerHTML = parsedQuote;
  broadcast.postMessage(parsedQuote);
 } catch (error) {
  console.error(error);
 }
};

回到/new-origin/main.js文件,我们将监听message事件并在每次发送新的引用时改变quote.innerHTML。

const broadcast = new BroadcastChannel("quote_channel");
const quote = document.querySelector("#quote");

broadcast.onmessage = ({data}) => {
    quote.innerHTML = data;
};

现在你可以看到:3000/new-origin/中的引用是如何变化为:3000中的引用的。你也可以注意到,当:3000标签被隐藏时,引用并没有改变,因为它只在其页面可见性状态为可见时才会去获取引用。

兼容性

广泛支持[9]

Internationalization API这是什么

在开发一个网页或应用程序时,需要将其内容翻译成其他语言以覆盖更广泛的受众是非常常见的。然而,仅仅将你的网页文本翻译成你所需要的任何语言,并不足以使你的内容对讲该语言的人可用,因为像日期、数字、单位等东西在不同国家是不同的,可能会给你的用户带来困惑。

我们假设你想在你的网页上展示日期"2022年11月8日",就像"11/8/22"。根据读者所在的国家,这些数据可以用三种不同的方式来阅读:

这就是Internationalization API(或I18n API)来解决不同语言和地区的格式问题的地方。I18n API是一个了不起的工具,有多种用途,但我们不会深入研究,以免使本文过于复杂。

如何使用

I18n API使用locale标识符来起作用。locale标识符是一个字符串,用来表示用户的语言、城市、地区、方言以及其他偏好。准确的说,locale标识符是一个字符串,由连字符分隔的子标签组成。子标签代表了用户偏好,比如语言、国家、地区或文字,并以以下方式格式化:

"zh":中文(语言);

"zh-Hant":用繁体字(文字)书写的中文(语言);

"zh-Hant-TW":在台湾(地区)使用的繁体字(文字)书写的中文(语言)。

还有更多的子标签来解决更多用户的偏好(如果你想了解更多,你可以查看RFC[10]对语言标签的定义),但简而言之,I18n API使用这些locale标识符来知道如何格式化所有语言敏感的数据。

更确切地说,I18n API提供了一个Intl对象,它带来了一堆专门的构造函数来处理对语言敏感的数据。在我看来,一些对国际化最有用的Intl构造函数是:

在我们的例子中,我们将重点关注Intl.DateTimeFormat()构造函数,以根据用户的区域设置来格式化引用的dateAdded属性。Intl.DateTimeFormat()构造函数接收两个参数:定义日期格式约定的locale字符串和用于自定义日期格式的options对象。

创建的Intl.DateTimeFormat()对象有一个format()方法,它接收两个参数:我们要格式化的Date对象和用于自定义如何显示格式化日期的options对象。

const logDate = (locale) => {
    const newDate = new Date("2022-10-24"); // YY/MM/DD
    const dateTime = new Intl.DateTimeFormat(locale, {timeZone"UTC"});
    const formatedDate = dateTime.format(newDate);
    console.log(formatedDate);
};

logDate("en-US"); // 10/24/2022
logDate("de-DE"); // 24.10.2022
logDate("zh-TW"); // 2022/10/24

注意:在Intl.DateTimeFormat构造函数的options参数中,我们将timeZone属性设置为"UTC",这样日期就不会被格式化为用户的当地时间。在我的例子中,没有timeZone的选项,日期被解析为 "10/23/2022"。

正如你所看到的,dateTime.format()根据locale的日期格式约定改变日期。我们可以使用navigator.language全局属性在引用的日期上实现这一行为,该全局属性具有用户的首选locale设置。为此,我们将创建一个新的函数,接收一个日期字符串(YYYY-MM-DD格式),并根据用户的locale返回格式化的日期。

const formatDate = (dateString) => {
    const date = new Date(dateString);
    const locale = navigator.language;
    const dateTimeFormat = new Intl.DateTimeFormat(locale, {timeZone"UTC"});

    return dateTimeFormat.format(date);

};

我们可以在getQuote()函数中添加这个函数来解析dateAdded日期。

const getQuote = async () => {
    if (document.visibilityState === "visible") {
        try {
            const response = await fetch("");
            const {content, author, dateAdded} = await response.json();
            const parsedQuote = `
            ${content} 
 
            

${author}


 
            

Added on ${formatDate(dateAdded)}

`
;
            quote.innerHTML = parsedQuote;
            broadcast.postMessage(parsedQuote);
        } catch (error) {
            console.error(error);
        }
    }
};

有了这个,我们的引用就被本地化为用户的首选语言了!在我的例子中,我的navigator.language值是"en",所以我的日期被格式化为MM/DD/YY。

兼容性

广泛支持[11]

总结

读完这篇文章后,你现在可以灵活地了解这些API的存在以及如何使用它们。尽管它们在JS现状调查中的认知度排名最后,但它们非常有用,知道如何使用它们肯定会提高你的开发经验。这些强大的API并不为人所知,这意味着还有一些你我都不知道的有用的API,所以现在是探索并找到那个可以简化你的代码,并为你节省大量开发时间的API的最佳时机。

本站内容来自用户投稿,如果侵犯了您的权利,请与我们联系删除。联系邮箱:835971066@qq.com

本文链接:http://news.xiuzhanwang.com/post/1512.html

发表评论

评论列表

还没有评论,快来说点什么吧~

友情链接: