STM32的8*8點陣屏開發(小項目)

基礎認識

 實現效果

項目實現STM32點陣屏的操作,自動更改显示內容和串口控制显示內容

STM32上電后:

1)   程序將進行行和列的刷新

2)   自動遞增显示0-9變化

3)   進行矩形由內向外動畫

4)   等等串口輸出控制,輸出範圍為0x00-0x09,點陣屏將显示輸入的数字

代碼為精簡的最小系統,方便後續的擴展和移植

視頻展示

https://www.bilibili.com/video/BV1Pi4y1x7Fo

環境配置

STM32固件版本:V3.5.0

單片機:STM32 F103C8T6

LED點陣管數碼管:共陽1588BS

編程工具:Keil uVision5

 LED點陣管數碼管認識

1.5英寸LED點陣管數碼管8*8紅色16pin

有如下兩種型號:

l  共陽1588BS

l  共陰1588AS

這裏使用的是:共陽1588BS

開始使用

 環境準備

l  STM32固件版本:V3.5.0

l  單片機:STM32 F103C8T6

l  LED點陣管數碼管:共陽1588BS

l  編程工具:Keil uVision5

 點陣屏與STM32接線說明

接線編號:

點陣屏1-8:A0、A1、A2、A3、A4、A5、A6、A7

點陣屏9-16:B0、B1、B10、B11、B12、B13、B14、B15

打開/編譯/燒寫

 

 

 項目測試

打開串口助手

 

連接USB串口模塊

上電后自動進行行列刷新

 

数字自動显示

 

 

小動畫显示

 

串口控制:

 編碼說明

 

 

分析得到編碼序列:

因為列是固定為低電平,也就是只要行輸出高電平,對應的點就點亮,確定行的高低位,設置從上到下為0-7行,所以第0行是十六進制的最低位而7是16進制的最高位。

得到結果分析:

第0列編碼:0000 0000 = 0x00

第1列編碼:0111 1110 = 0x7E

第2列編碼:1010 0001 = 0xA1

第3列編碼:1001 0001 = 0x91

第4列編碼:1000 1001 = 0x89

第5列編碼:1000 0101 = 0x85

第6列編碼:0111 1110 = 0x7E

第7列編碼:0000 0000 = 0x00

所以得到数字0的編碼數組為:

{0x00,0x7E,0xA1,0x91,0x89,0x85,0x7E,0x00}

 

視頻展示

https://www.bilibili.com/video/BV1Pi4y1x7Fo

 

以下內容不完全展示…….

獲取工程文件請私聊或評論(*๓´╰╯`๓)

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

※推薦評價好的iphone維修中心

※網頁設計最專業,超強功能平台可客製化

※別再煩惱如何寫文案,掌握八大原則!

小師妹學JavaIO之:Buffer和Buff

目錄

  • 簡介
  • Buffer是什麼
  • Buffer進階
  • 創建Buffer
  • Direct VS non-Direct
  • Buffer的日常操作
    • 向Buffer寫數據
    • 從Buffer讀數據
    • rewind Buffer
    • Compact Buffer
    • duplicate Buffer
  • 總結

簡介

小師妹在學習NIO的路上越走越遠,唯一能夠幫到她的就是在她需要的時候給她以全力的支持。什麼都不說了,今天介紹的是NIO的基礎Buffer。老鐵給我上個Buff。

Buffer是什麼

小師妹:F師兄,這個Buffer是我們縱橫王者峽谷中那句:老鐵給我加個Buff的意思嗎?

當然不是了,此Buffer非彼Buff,Buffer是NIO的基礎,沒有Buffer就沒有NIO,沒有Buffer就沒有今天的java。

因為NIO是按Block來讀取數據的,這個一個Block就可以看做是一個Buffer。我們在Buffer中存儲要讀取的數據和要寫入的數據,通過Buffer來提高讀取和寫入的效率。

更多精彩內容且看:

  • 區塊鏈從入門到放棄系列教程-涵蓋密碼學,超級賬本,以太坊,Libra,比特幣等持續更新
  • Spring Boot 2.X系列教程:七天從無到有掌握Spring Boot-持續更新
  • Spring 5.X系列教程:滿足你對Spring5的一切想象-持續更新
  • java程序員從小工到專家成神之路(2020版)-持續更新中,附詳細文章教程

更多內容請訪問www.flydean.com

還記得java對象的底層存儲單位是什麼嗎?

小師妹:這個我知道,java對象的底層存儲單位是字節Byte。

對,我們看下Buffer的繼承圖:

Buffer是一個接口,它下面有諸多實現,包括最基本的ByteBuffer和其他的基本類型封裝的其他Buffer。

小師妹:F師兄,有ByteBuffer不就夠了嗎?還要其他的類型Buffer做什麼?

小師妹,山珍再好,也有吃膩的時候,偶爾也要換個蘿蔔白菜啥的,你以為乾隆下江南都幹了些啥?

ByteBuffer雖然好用,但是它畢竟是最小的單位,在它之上我們還有Char,int,Double,Short等等基礎類型,為了簡單起見,我們也給他們都搞一套Buffer。

Buffer進階

小師妹:F師兄,既然Buffer是這些基礎類型的集合,為什麼不直接用結合來表示呢?給他們封裝成一個對象,好像有點多餘。

我們既然在面向對象的世界,從表面來看自然是使用Object比較合乎情理,從底層的本質上看,這些封裝的Buffer包含了一些額外的元數據信息,並且還提供了一些意想不到的功能。

上圖列出了Buffer中的幾個關鍵的概念,分別是Capacity,Limit,Position和Mark。Buffer底層的本質是數組,我們以ByteBuffer為例,它的底層是:

final byte[] hb; 
  • Capacity表示的是該Buffer能夠承載元素的最大數目,這個是在Buffer創建初期就設置的,不可以被改變。
  • Limit表示的Buffer中可以被訪問的元素個數,也就是說Buffer中存活的元素個數。
  • Position表示的是下一個可以被訪問元素的index,可以通過put和get方法進行自動更新。
  • Mark表示的是歷史index,當我們調用mark方法的時候,會把設置Mark為當前的position,通過調用reset方法把Mark的值恢復到position中。

創建Buffer

小師妹:F師兄呀,這麼多Buffer創建起來是不是很麻煩?有沒有什麼快捷的使用辦法?

一般來說創建Buffer有兩種方法,一種叫做allocate,一種叫做wrap。

public void createBuffer(){
        IntBuffer intBuffer= IntBuffer.allocate(10);
        log.info("{}",intBuffer);
        log.info("{}",intBuffer.hasArray());
        int[] intArray=new int[10];
        IntBuffer intBuffer2= IntBuffer.wrap(intArray);
        log.info("{}",intBuffer2);
        IntBuffer intBuffer3= IntBuffer.wrap(intArray,2,5);
        log.info("{}",intBuffer3);
        intBuffer3.clear();
        log.info("{}",intBuffer3);
        log.info("{}",intBuffer3.hasArray());
    }

allocate可以為Buffer分配一個空間,wrap同樣為Buffer分配一個空間,不同的是這個空間背後的數組是自定義的,wrap還支持三個參數的方法,後面兩個參數分別是offset和length。

INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=0 lim=10 cap=10]
INFO com.flydean.BufferUsage - true
INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=0 lim=10 cap=10]
INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=2 lim=7 cap=10]
INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=0 lim=10 cap=10]
INFO com.flydean.BufferUsage - true

hasArray用來判斷該Buffer的底層是不是數組實現的,可以看到,不管是wrap還是allocate,其底層都是數組。

需要注意的一點,最後,我們調用了clear方法,clear方法調用之後,我們發現Buffer的position和limit都被重置了。這說明wrap的三個參數方法設定的只是初始值,可以被重置。

Direct VS non-Direct

小師妹:F師兄,你說了兩種創建Buffer的方法,但是兩種Buffer的後台都是數組,難道還有非數組的Buffer嗎?

自然是有的,但是只有ByteBuffer有。ByteBuffer有一個allocateDirect方法,可以分配Direct Buffer。

小師妹:Direct和非Direct有什麼區別呢?

Direct Buffer就是說,不需要在用戶空間再複製拷貝一份數據,直接在虛擬地址映射空間中進行操作。這叫Direct。這樣做的好處就是快。缺點就是在分配和銷毀的時候會佔用更多的資源,並且因為Direct Buffer不在用戶空間之內,所以也不受垃圾回收機制的管轄。

所以通常來說只有在數據量比較大,生命周期比較長的數據來使用Direct Buffer。

看下代碼:

public void createByteBuffer() throws IOException {
        ByteBuffer byteBuffer= ByteBuffer.allocateDirect(10);
        log.info("{}",byteBuffer);
        log.info("{}",byteBuffer.hasArray());
        log.info("{}",byteBuffer.isDirect());

        try (RandomAccessFile aFile = new RandomAccessFile("src/main/resources/www.flydean.com", "r");
             FileChannel inChannel = aFile.getChannel()) {
            MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
            log.info("{}",buffer);
            log.info("{}",buffer.hasArray());
            log.info("{}",buffer.isDirect());
        }
    }

除了allocateDirect,使用FileChannel的map方法也可以得到一個Direct的MappedByteBuffer。

上面的例子輸出結果:

INFO com.flydean.BufferUsage - java.nio.DirectByteBuffer[pos=0 lim=10 cap=10]
INFO com.flydean.BufferUsage - false
INFO com.flydean.BufferUsage - true
INFO com.flydean.BufferUsage - java.nio.DirectByteBufferR[pos=0 lim=0 cap=0]
INFO com.flydean.BufferUsage - false
INFO com.flydean.BufferUsage - true

Buffer的日常操作

小師妹:F師兄,看起來Buffer確實有那麼一點複雜,那麼Buffer都有哪些操作呢?

Buffer的操作有很多,下面我們一一來講解。

向Buffer寫數據

向Buffer寫數據可以調用Buffer的put方法:

public void putBuffer(){
        IntBuffer intBuffer= IntBuffer.allocate(10);
        intBuffer.put(1).put(2).put(3);
        log.info("{}",intBuffer.array());
        intBuffer.put(0,4);
        log.info("{}",intBuffer.array());
    }

因為put方法返回的還是一個IntBuffer類,所以Buffer的put方法可以像Stream那樣連寫。

同時,我們還可以指定put在什麼位置。上面的代碼輸出:

INFO com.flydean.BufferUsage - [1, 2, 3, 0, 0, 0, 0, 0, 0, 0]
INFO com.flydean.BufferUsage - [4, 2, 3, 0, 0, 0, 0, 0, 0, 0]

從Buffer讀數據

讀數據使用get方法,但是在get方法之前我們需要調用flip方法。

flip方法是做什麼用的呢?上面講到Buffer有個position和limit字段,position會隨着get或者put的方法自動指向後面一個元素,而limit表示的是該Buffer中有多少可用元素。

如果我們要讀取Buffer的值則會從positon開始到limit結束:

public void getBuffer(){
        IntBuffer intBuffer= IntBuffer.allocate(10);
        intBuffer.put(1).put(2).put(3);
        intBuffer.flip();
        while (intBuffer.hasRemaining()) {
            log.info("{}",intBuffer.get());
        }
        intBuffer.clear();
    }

可以通過hasRemaining來判斷是否還有下一個元素。通過調用clear來清除Buffer,以供下次使用。

rewind Buffer

rewind和flip很類似,不同之處在於rewind不會改變limit的值,只會將position重置為0。

public void rewindBuffer(){
        IntBuffer intBuffer= IntBuffer.allocate(10);
        intBuffer.put(1).put(2).put(3);
        log.info("{}",intBuffer);
        intBuffer.rewind();
        log.info("{}",intBuffer);
    }

上面的結果輸出:

INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=3 lim=10 cap=10]
INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=0 lim=10 cap=10]

Compact Buffer

Buffer還有一個compact方法,顧名思義compact就是壓縮的意思,就是把Buffer從當前position到limit的值賦值到position為0的位置:

public void useCompact(){
        IntBuffer intBuffer= IntBuffer.allocate(10);
        intBuffer.put(1).put(2).put(3);
        intBuffer.flip();
        log.info("{}",intBuffer);
        intBuffer.get();
        intBuffer.compact();
        log.info("{}",intBuffer);
        log.info("{}",intBuffer.array());
    }

上面代碼輸出:

INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=0 lim=3 cap=10]
INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=2 lim=10 cap=10]
INFO com.flydean.BufferUsage - [2, 3, 3, 0, 0, 0, 0, 0, 0, 0]

duplicate Buffer

最後我們講一下複製Buffer,有三種方法,duplicate,asReadOnlyBuffer,和slice。

duplicate就是拷貝原Buffer的position,limit和mark,它和原Buffer是共享原始數據的。所以修改了duplicate之後的Buffer也會同時修改原Buffer。

如果用asReadOnlyBuffer就不允許拷貝之後的Buffer進行修改。

slice也是readOnly的,不過它拷貝的是從原Buffer的position到limit-position之間的部分。

public void duplicateBuffer(){
        IntBuffer intBuffer= IntBuffer.allocate(10);
        intBuffer.put(1).put(2).put(3);
        log.info("{}",intBuffer);
        IntBuffer duplicateBuffer=intBuffer.duplicate();
        log.info("{}",duplicateBuffer);
        IntBuffer readOnlyBuffer=intBuffer.asReadOnlyBuffer();
        log.info("{}",readOnlyBuffer);
        IntBuffer sliceBuffer=intBuffer.slice();
        log.info("{}",sliceBuffer);
    }

輸出結果:

INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=3 lim=10 cap=10]
INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=3 lim=10 cap=10]
INFO com.flydean.BufferUsage - java.nio.HeapIntBufferR[pos=3 lim=10 cap=10]
INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=0 lim=7 cap=7]

總結

今天給小師妹介紹了Buffer的原理和基本操作。

本文的例子https://github.com/ddean2009/learn-java-io-nio

本文作者:flydean程序那些事

本文鏈接:http://www.flydean.com/java-io-nio-buffer/

本文來源:flydean的博客

歡迎關注我的公眾號:程序那些事,更多精彩等着您!

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

※網頁設計最專業,超強功能平台可客製化

※別再煩惱如何寫文案,掌握八大原則!

掌握SpringBoot-2.3的容器探針:深入篇

歡迎訪問我的GitHub

https://github.com/zq2599/blog_demos

  • 內容:原創分類匯總及配套源碼,涉及Java、Docker、K8S、DevOPS等

關於《SpringBoot-2.3容器化技術》系列

  • 《SpringBoot-2.3容器化技術》系列,旨在和大家一起學習實踐2.3版本帶來的最新容器化技術,讓咱們的Java應用更加適應容器化環境,在雲計算時代依舊緊跟主流,保持競爭力;
  • 全系列文章分為主題和輔助兩部分,主題部分如下:
  1. 《體驗SpringBoot(2.3)應用製作Docker鏡像(官方方案)》;
  2. 《詳解SpringBoot(2.3)應用製作Docker鏡像(官方方案)》;
  3. 《掌握SpringBoot-2.3的容器探針:基礎篇》;
  4. 《掌握SpringBoot-2.3的容器探針:深入篇》;
  5. 《掌握SpringBoot-2.3的容器探針:實戰篇》;
  • 輔助部分是一些參考資料和備忘總結,如下:
  1. 《SpringBoot-2.3鏡像方案為什麼要做多個layer》;
  2. 《設置非root賬號不用sudo直接執行docker命令》;
  3. 《開發階段,將SpringBoot應用快速部署到K8S》;

前文回顧

  1. 本文是《掌握SpringBoot-2.3的容器探針》系列的第二篇,前文 《掌握SpringBoot-2.3的容器探針:基礎篇》知道了kubernetes的存活和就緒探針,以及SpringBoot-2.3的actuator新增的兩個endpoint,當我們把應用部署到kubernetes環境時,這些知識讓我們能配置出官方推薦的探針方案,如下圖:
  1. 儘管上述配置已經可以覆蓋多數場景,依然有三個問題未解決:
  • 首先,SpringBoot為kubernetes提供了兩個actuator項,但是那些並未部署在kubernetes的SringBoot應用呢?用不上這兩項也要對外暴露這兩個服務地址嗎?

  • 其次,就緒探針是什麼時候開始返回200返回碼的?應用啟動階段,業務服務可能需要一段時間才能正常工作,就緒探針要是提前返回了200,那k8s就認為容器可以正常工作了,這時候把外部請求調度過來是無法正常響應的,所以搞清楚就緒探針的狀態變化邏輯很重要;

  • 最後,也是最重要的一點:有的場景下,例如外部依賴服務異常、本地全局異常等情況下,業務不想對外提供服務,等到問題解決后業務又可以對外提供服務了,如果此時我們能自己寫代碼控制就緒探針的返回碼,那就做到了控制kubernetes是否將外部請求調度到此容器上,這可是個很實用的功能!

本篇就是為了解決上述問題而作,這些問題解決后才能用好探針技術,讓它在容器環境帶來更大價值;

關鍵知識點

解決上述問題的關鍵集中在以下幾個知識點:

  1. SpringBoot對容器環境的判斷;
  2. SpringBoot對狀態定義;
  3. 獲取狀態;
  4. 監聽狀態;
  5. 修改狀態;

接下來挨個學習這些知識點;

SpringBoot對容器環境的判斷

  1. 官方文檔如下圖所示,SpringBoot判斷是否是kubernetes環境的邏輯很簡單:是否有_SERVICE_HOST和_SERVICE_PORT這兩個環境變量:

  2. 熟悉kubernetes的讀者看到_SERVICE_HOST” 和_SERVICE_PORT,應該會想起KUBERNETES_SERVICE_HOST和KUBERNETES_SERVICE_PORT,這是k8s給pod中配置的環境變量,看來SpringBoot也是針對k8s的這個規則來判定是否是容器環境的(如果將來k8s的某個版本不給pod設置這個環境變量,那些原本可以正常運行的pod豈不是有危險了?);

  3. 接下來通過實踐來驗證上述規則是否有效;

  4. 創建一個SpringBoot-2.3.0.RELEASE的應用,其pom.xml中的parent信息如下:

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.3.0.RELEASE</version>
  <relativePath/>
</parent>
  1. 增加actuator依賴:
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
  1. 啟動該應用,瀏覽器訪問:http://localhost:8080/actuator/health/liveness,返回404錯誤:
  1. 以上返回是符合預期的,因為此時並非在kubernetes環境,接下來將”_SERVICE_HOST 和_SERVICE_PORT這兩個環境變量加入應用進程,看看是否有變化;
  2. 如下圖,編輯啟動類的配置信息:
  1. 點擊下圖紅框位置,即可進入編輯環境變量的窗口:
  1. 新的窗口中,操作如下圖紅框中所示,新增了兩個環境變量:
  1. 再次運行程序,這次返回的狀態碼是200:
  1. 至此,我們弄明白了SpringBoot是否開啟探針的邏輯,即應用是否運行在容器環境,而是否是容器環境的判定邏輯則是_SERVICE_HOST和_SERVICE_PORT這兩個環境變量是否存在;

非kubernetes環境開啟探針

/actuator/health/liveness和/actuator/health/readiness在kubernetes環境才會開啟,但是一般情況下,在開發階段SpringBoot應用可能運行在自己的電腦上,此時如果想查看這兩個接口的返回值有兩種方式:

第一種,就是前面提到的添加_SERVICE_HOST和_SERVICE_PORT這兩個環境變量,讓SpringBoot以為當前環境是kubernetes環境;

第二種,是按照官方指導添加屬性,如下圖紅框所示:

SpringBoot對探針相關狀態定義

  1. 首先要弄清楚有哪些狀態,源碼是最準確的;
  2. 如下圖,存活探針一共有兩種狀態:CORRECT表示應用運行中並且內部狀態正常,BROKEN表示應用運行中並且內部是BROKEN狀態(請原諒我的英語水平)
  1. 如下圖,就緒探針一共有兩種狀態:ACCEPTING_TRAFFIC表示應用可以對外提供服務,REFUSING_TRAFFIC表示應用無法對外提供服務;
  1. 另外,上圖的since註解显示這兩個枚舉是從2.3.0版本開始生效的;

  2. 小小八卦一下,上述兩個枚舉的作者Brian Clozel,坐標法國里昂,目前在sringboot的提交次數排第8名:

  1. 在SpringBoot啟動過程中,應用、存活探針、就緒探針三者狀態對應關係如下圖:
  1. 在SpringBoot停止過程中,應用、存活探針、就緒探針三者狀態對應關係如下圖:

獲取狀態

如果業務應用想獲取當前的存活和就緒狀態,將ApplicationAvailability接口autowire進來即可,下一篇《實戰篇》會有詳細的使用方式,這裏看下關鍵代碼:

監聽狀態

得益於Spring完整的事件發布和訂閱機制,業務應用通過EventListener註解就能監聽到存活和就緒狀態的變化,在EventListener註解修飾的方法中寫入必要的業務代碼即可實現狀態監聽,下一篇《實戰篇》會有詳細的使用方式,這裏看下關鍵代碼:

修改狀態

  1. 修改狀態,尤其是就緒狀態,這應該是我們最關注的功能了,在某些業務場景下,應用無法對外提供服務,這時候我們希望K8S不要將外部請求調度到這裏,如果K8S通過就緒探針收到返回碼非200,就不再將請求調度到這個pod上;
  2. 下一篇《實戰篇》會有詳細的代碼介紹,這裏給出關鍵代碼作為參考:

請注意

重要的事情一定要強調:咱們修改狀態的最終目的,不是為了取得applicationAvailability.getReadinessState()返回新的枚舉對象,而是要改變/actuator/health/readiness接口的返回碼(就緒是200,未就緒是503),這是kubernetes的探針規則要用到的;

為啥都放在下一篇

  1. 文章看到這裏您可能已經火冒三丈了:關鍵代碼都貼出來了,為啥不在本章給出完整源碼?騙點擊量?湊字數?湊文章數?
  2. 存活和就緒探針是在kubernetes環境下的工具,為了給您提供盡量準確和完整的參考,所有的代碼和操作都必須在kubernetes環境完成調試才能發布,而且這些操作應該作為單獨章節,與當前的理論知識分開;
  3. 歡迎進入《實戰篇》,隨SpringBoot-2.3.0.RELEASE,一起在kubernetes世界暢遊;

歡迎關注我的公眾號:程序員欣宸

https://github.com/zq2599/blog_demos

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

※南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案

※回頭車貨運收費標準

動手造輪子:實現一個簡單的依賴注入(三) — 支持屬性注入

動手造輪子:實現一個簡單的依賴注入(三) — 支持屬性注入

Intro

前面寫了幾篇依賴注入的文章,有興趣的小夥伴可以參考文末 Reference 部分中的鏈接,一直有小夥伴希望增加屬性注入的支持,昨天試着加了一下,思路很簡單,在獲取到服務實例之後檢查實例中有沒有需要注入的屬性,如果有並且不為 null 就從服務容器中獲取一個對應屬性類型的實例

代碼修改

FromServiceAttribute

完整的代碼修改可以參考這個 commit https://github.com/WeihanLi/WeihanLi.Common/commit/91dc0b515d12e7c036771fba9419824cd0219544

首先我們需要增加一個 FromServiceAttribute 用來標識哪些屬性需要注入,代碼如下:

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
public sealed class FromServiceAttribute : Attribute
{
}

這裏 AttributeTargets 除了屬性之外增加了字段和參數,是想可能以後會用到,參數典型的應用場景就是類似於 asp.net core 里的 [FromServices] 用來實現方法注入參數

EnrichObject

增加了一個 EnrichObject 方法,用來在獲取到服務實例之後,對服務實例做一些補充的配置,如我們要加的屬性注入,如果我們要加字段注入等也可以在這個方法內完成,來看實現:

private object EnrichObject(object obj)
{
    if (null != obj)
    {
        // PropertyInjection
        var type = obj.GetType();
        foreach (var property in CacheUtil.TypePropertyCache.GetOrAdd(type, t => t.GetProperties())
            .Where(x => x.IsDefined(typeof(FromServiceAttribute))))
        {
            if (property.GetValueGetter()?.Invoke(obj) == null)
            {
                property.GetValueSetter()?.Invoke(
                    obj,
                    GetService(property.PropertyType)
                    );
            }
        }
    }

    return obj;
}

上面的邏輯就是獲取這個 object 定義的所有需要注入的屬性,如果屬性的值不為 null 則,從服務容器中獲取對應的服務實例,之所以要檢查是不是null

上面的 CacheUtil.TypePropertyCache 是一個 Type 為 key,PropertyInfo 數組為 Value 的併發字典,用來緩存類型的屬性

GetValueGetter/GetValueSetter 是 PropertyInfo 的擴展方法,利用表達式樹和緩存提高屬性 Get/Set 的效率

GetSertviceInstance

修改原來的 GetServiceInstance 方法為 GetServiceInstanceInternal,增加一個一樣的方法,實現邏輯是在 GetServiceInstanceInternal 的基礎上調用上面的 Enrich 方法來實現屬性注入

More

雖然增加了屬性注入的支持,但是還是不太推薦使用,從上面屬性注入的代碼中可以看得到,如果用不好很容易出現循環依賴的問題,而且用構造器注入的話依賴關係很清晰,分析方法的構造方法即可,如果要使用屬性注入請謹慎使用

Reference

  • https://github.com/WeihanLi/WeihanLi.Common/commit/91dc0b515d12e7c036771fba9419824cd0219544
  • https://github.com/WeihanLi/WeihanLi.Common/tree/dev/src/WeihanLi.Common/DependencyInjection
  • https://www.cnblogs.com/weihanli/p/implement-dependency-injection.html
  • https://www.cnblogs.com/weihanli/p/implement-dependency-injection-01.html
  • https://www.cnblogs.com/weihanli/p/implement-dependency-injection-02.html

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

※網頁設計最專業,超強功能平台可客製化

※回頭車貨運收費標準

Spark Streaming,Flink,Storm,Kafka Streams,Samza:如何選擇流處理框架

根據最新的統計显示,僅在過去的兩年中,當今世界上90%的數據都是在新產生的,每天創建2.5萬億字節的數據,並且隨着新設備,傳感器和技術的出現,數據增長速度可能會進一步加快。
從技術上講,這意味着我們的大數據處理將變得更加複雜且更具挑戰性。而且,許多用例(例如,移動應用廣告,欺詐檢測,出租車預訂,病人監護等)都需要在數據到達時進行實時數據處理,以便做出快速可行的決策。這就是為什麼分佈式流處理在大數據世界中變得非常流行的原因。

如今,有許多可用的開源流框架。有趣的是,幾乎所有它們都是相當新的,僅在最近幾年才開發出來。因此,對於新手來說,很容易混淆流框架之間的理解和區分。在本文中,我將首先大致討論流處理的類型和方面,然後比較最受歡迎的開源流框架:Flink,SparkStreaming,Storm,KafkaStream。我將嘗試(簡要地)解釋它們的工作原理,它們的用例,優勢,局限性,異同。

什麼是流/流處理:

流處理的最優雅的定義是:一種數據處理引擎,其設計時考慮了無限的數據集。

與批處理不同,批處理以工作中的開始和結束為界,而工作是在處理有限數據之後完成的,而流處理則是指連續不斷地處理天,月,年和永久到來的無邊界數據。因此,流媒體應用程序始終需要啟動和運行,因此難以實現且難以維護。

流處理的重要方面:

為了理解任何Streaming框架的優點和局限性,我們應該了解與Stream處理相關的一些重要特徵和術語:

  • 交付保證:
    這意味着無論如何,流引擎中的特定傳入記錄都將得到處理的保證。可以是at least once(至少一次)(即使發生故障也至少處理一次),at most once : 至多一次(如果發生故障則可能不處理)或Exactly-once(即使失敗在這種情況下也只能處理一次))。顯然,只處理一次是最好的,但是很難在分佈式系統中實現,並且需要權衡性能。
  • 容錯:
    如果發生諸如節點故障,網絡故障等故障,框架應該能夠恢復,並且應該從其離開的位置開始重新處理。這是通過不時檢查流向某些持久性存儲的狀態來實現的。例如,從Kafka獲取記錄並對其進行處理后,將Kafka檢查點偏移給Zookeeper。
  • 狀態管理:在有狀態處理需求的情況下,我們需要保持某種狀態(例如,記錄中每個不重複單詞的計數),框架應該能夠提供某種機制來保存和更新狀態信息。
  • 性能:
    這包括延遲(可以多久處理一條記錄),吞吐量(每秒處理的記錄數)和可伸縮性。延遲應盡可能小,而吞吐量應盡可能大。很難同時獲得兩者。
  • 高級功能:事件時間處理,水印,窗口化
    如果流處理要求很複雜,這些是必需的功能。例如,根據在源中生成記錄的時間來處理記錄(事件時間處理)。
  • 成熟度:從採用的角度來看很重要,如果框架已經過大公司的驗證和大規模測試,那就太好了。更有可能獲得良好的社區支持並在堆棧溢出方面提供幫助。

流處理的兩種類型:

現在了解了我們剛剛討論的術語,現在很容易理解,有兩種方法可以實現Streaming框架:

原生流處理:
這意味着每條到達的記錄都會在到達后立即處理,而無需等待其他記錄。有一些連續運行的過程(根據框架,我們稱之為操作員/任務/螺栓),這些過程將永遠運行,每條記錄都將通過這些過程進行處理。示例:Storm,Flink,Kafka Streams,Samza。

微批處理:
也稱為快速批處理。這意味着每隔幾秒鐘就會將傳入的記錄分批處理,然後以單個小批處理的方式處理,延遲幾秒鐘。例如:Spark Streaming, Storm-Trident。

兩種方法都有其優點和缺點。
原生流傳輸感覺很自然,因為每條記錄都會在到達記錄后立即進行處理,從而使框架能夠實現最小的延遲。但這也意味着在不影響吞吐量的情況下很難實現容錯,因為對於每條記錄,我們都需要在處理後跟蹤和檢查點。而且,狀態管理很容易,因為有長時間運行的進程可以輕鬆維護所需的狀態。

另一方面,微批處理則完全相反。容錯是免費提供的,因為它本質上是一個批處理,吞吐量也很高,因為處理和檢查點將在一組記錄中一次性完成。但這會花費一定的等待時間,並且感覺不自然。高效的狀態管理也將是維持的挑戰。

流框架對比:

Storm :

Storm是流處理世界的強者。它是最古老的開源流框架,也是最成熟和可靠的框架之一。這是真正的流傳輸,適合基於簡單事件的用例。

優點:

  • 極低的延遲,真正的流,成熟和高吞吐量
  • 非常適合簡單的流媒體用例

缺點

  • 沒有狀態管理
  • 沒有高級功能,例如事件時間處理,聚合,開窗,會話,水印等
  • 一次保證

Spark Streaming :

Spark已成為批處理中hadoop的真正繼任者,並且是第一個完全支持Lambda架構的框架(在該框架中,實現了批處理和流傳輸;實現了正確性的批處理;實現了流傳輸的速度)。它非常受歡迎,成熟並被廣泛採用。Spark Streaming是隨Spark免費提供的,它使用微批處理進行流媒體處理。在2.0版本之前,Spark Streaming有一些嚴重的性能限制,但是在新版本2.0+中,它被稱為結構化流,並具有許多良好的功能,例如自定義內存管理(類似flink),水印,事件時間處理支持等。另外,結構化流媒體更加抽象,在2.3.0版本以後,可以選擇在微批量和連續流媒體模式之間進行切換。連續流模式有望帶來像Storm和Flink這樣的子延遲,但是它仍處於起步階段,操作上有很多限制。

優點:

  • 支持Lambda架構,Spark免費提供
  • 高吞吐量,適用於不需要亞延遲的許多使用情況
  • 由於微批量性質,默認情況下具有容錯能力
  • 簡單易用的高級API
  • 龐大的社區和积極的改進
  • 恰好一次

缺點

  • 不是真正的流,不適合低延遲要求

  • 要調整的參數太多。很難做到正確。

  • 天生無國籍

  • 在許多高級功能方面落後於Flink

Flink :

Flink也來自類似Spark這樣的學術背景。Spark來自加州大學伯克利分校,而Flink來自柏林工業大學。像Spark一樣,它也支持Lambda架構。但是實現與Spark完全相反。雖然Spark本質上是一個批處理,其中Spark流是微批處理,並且是Spark Batch的特例,但Flink本質上是一個真正的流引擎,將批處理視為帶邊界數據流的特例。儘管這兩個框架中的API都是相似的,但是它們在實現上沒有任何相似性。在Flink中,諸如map,filter,reduce等的每個函數都實現為長時間運行的運算符(類似於Storm中的Bolt)

Flink看起來像是Storm的真正繼承者,就像Spark批量繼承了hadoop一樣。

優點:

  • 開源流媒體領域創新的領導者
  • 具有所有高級功能(例如事件時間處理,水印等)的第一個True流框架
  • 低延遲,高吞吐量,可根據要求進行配置
  • 自動調整,無需調整太多參數
  • 恰好一次
  • 被Uber,阿里巴巴等大型公司廣泛接受。

缺點

  • 起步較晚,最初缺乏採用

  • 社區不如Spark大,但現在正在快速發展

Kafka Streams :

與其他流框架不同,Kafka Streams是一個輕量級的庫。對於從Kafka流式傳輸數據,進行轉換然後發送回kafka很有用。我們可以將其理解為類似於Java Executor服務線程池的庫,但具有對Kafka的內置支持。它可以與任何應用程序很好地集成,並且可以立即使用。

由於其重量輕的特性,可用於微服務類型的體繫結構。Flink在性能方面沒有匹配之處,而且不需要運行單獨的集群,非常方便並且易於部署和開始工作。

Kafka Streams的一個主要優點是它的處理是完全精確的端到端。可能是因為來源和目的地均為Kafka以及從2017年6月左右發布的Kafka 0.11版本開始,僅支持一次。要啟用此功能,我們只需要啟用一個標誌即可使用。

優點:

  • 重量很輕的庫,適合微服務,IOT應用
  • 不需要專用集群
  • 繼承卡夫卡的所有優良特性
  • 支持流連接,內部使用rocksDb維護狀態。
  • 恰好一次(從Kafka 0.11開始)。

缺點

  • 與卡夫卡緊密結合,在沒有卡夫卡的情況下無法使用
  • 嬰兒期還很新,尚待大公司測試
  • 不適用於繁重的工作,例如Spark Streaming,Flink。

Samza :

簡短介紹一下Samza。(Samza)看上去就像是(Kafka Streams)。有很多相似之處。這兩個框架都是由同一位開發人員開發的,這些開發人員在LinkedIn上實現了Samza,然後在他們創建Kafka Streams的地方成立了Confluent。這兩種技術都與Kafka緊密結合,從Kafka獲取原始數據,然後將處理后的數據放回Kafka。使用相同的Kafka Log哲學。Samza是Kafka Streams的縮放版本。Kafka Streams是一個用於微服務的庫,而Samza是在Yarn上運行的完整框架集群處理。
優點 :

  • 使用rocksDb和kafka日誌可以很好地維護大量信息狀態(適合於連接流的用例)。
  • 使用Kafka屬性的容錯和高性能
  • 如果已在處理管道中使用Yarn和Kafka,則要考慮的選項之一。
  • 低延遲,高吞吐量,成熟並經過大規模測試

缺點:

  • 與Kafka和Yarn緊密結合。如果這些都不在您的處理管道中,則不容易使用。
  • 至少一次加工保證。我不確定它是否像Kafka 0.11之後的Kafka Streams現在完全支持一次
  • 缺少高級流功能,例如水印,會話,觸發器等

流框架比較:

我們只能將技術與類似產品進行比較。儘管Storm,Kafka Streams和Samza現在對於更簡單的用例很有用,但具有最新功能的重量級產品之間的真正競爭顯而易見:Spark vs Flink

當我們談論比較時,我們通常會問:給我看数字

基準測試是僅當第三方進行比較時比較的好方法。

例如,但這是在Spark Streaming 2.0之前的某個時期,當時它受RDD的限制。
現在,隨着Structured Streaming 2.0版本的發布,Spark Streaming試圖趕上很多潮流,而且似乎還會面臨艱巨的挑戰。

最近,基準測試已成為Spark和Flink之間的一場激烈爭吵。

最好不要相信這些天的基準測試,因為即使很小的調整也可以完全改變数字。沒有什麼比決定之前嘗試和測試自己更好。
到目前為止,很明顯,Flink在流分析領域處於領先地位,它具有大多數所需的方面,例如精確一次,吞吐量,延遲,狀態管理,容錯,高級功能等。

Flink的一個重要問題是成熟度和採用水平,直到一段時間之前,但是現在像Uber,Alibaba,CapitalOne這樣的公司正在大規模使用Flink流傳輸,證明了Flink Streaming的潛力。

最近,Uber開源了其最新的流分析框架AthenaX,該框架基於Flink引擎構建。

如果您已經注意到,需要注意的重要一點是,所有支持狀態管理的原生流框架(例如Flink,Kafka Streams,Samza)在內部都使用RocksDb。RocksDb從某種意義上說是獨一無二的,它在每個節點上本地保持持久狀態,並且性能很高。它已成為新流系統的關鍵部分。

如何選擇最佳的流媒體框架:

這是最重要的部分。誠實的答案是:這取決於 :

必須牢記,對於每個用例,沒有一個單一的處理框架可以成為萬靈丹。每個框架都有其優點和局限性。儘管如此,根據一些經驗,他們仍然會分享一些有助於做出決定的建議:

  1. 取決於用例:
    如果用例很簡單,那麼如果學習和實現起來很複雜,則無需尋求最新,最好的框架。在很大程度上取決於我們願意投資多少來換取我們想要的回報。例如,如果它是基於事件的簡單IOT事件警報系統,那麼Storm或Kafka Streams非常適合使用。
  2. 未來考慮因素:
    同時,我們還需要對未來可能的用例進行自覺考慮。將來可能會出現對諸如事件時間處理,聚合,流加入等高級功能的需求嗎?如果答案是肯定的,則最好繼續使用高級流框架(例如Spark Streaming或Flink)。一旦對一項技術進行了投資和實施,其變更的困難和巨大成本將在以後改變。例如,在之前的公司中,從過去的兩年開始,Storm管道就已經啟動並運行,並且在要求統一輸入事件並僅報告唯一事件之前,它一直運行良好。現在,這需要狀態管理,而Storm本身並不支持這種狀態管理。雖然我使用基於時間的內存哈希表實現,但是在重啟時狀態會消失是有限制的。
  3. 我要提出的觀點是,如果我們嘗試自行實現框架未明確提供的某些內容,則勢必會遇到未知問題。
  4. 現有技術堆棧:
    另一重要點是考慮現有技術堆棧。如果現有堆棧的首尾相連是Kafka,則Kafka Streams或Samza可能更容易安裝。同樣,如果處理管道基於Lambda架構,並且Spark Ba​​tch或Flink Batch已經到位,則考慮使用Spark Streaming或Flink Streaming是有意義的。例如,在我以前的項目中,我已經在管道中添加了Spark Ba​​tch,因此,當流需求到來時,選擇需要幾乎相同的技能和代碼庫的Spark Streaming非常容易。

簡而言之,如果我們很好地了解框架的優點和局限性以及用例,那麼選擇或至少過濾掉可用的選項就更加容易。最後,一旦選擇了幾個選項。畢竟每個人都有不同的選擇。

Streaming的發展速度如此之快,以至於在信息方面,此帖子可能在幾年後已經過時。目前,Spark和Flink在開發方面是領先的重量級人物,但仍有一些新手可以加入比賽。Apache Apex是其中之一。還有一些我沒有介紹的專有流解決方案,例如Google Dataflow。我的這篇文章的目的是幫助剛接觸流技術的人以最少的術語理解流技術的一些核心概念,以及流行的開源流框架的優點,局限性和用例。希望該文章對您有所幫助。

更多實時數據分析相關博文與科技資訊,歡迎關注 “實時流式計算”

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※南投搬家公司費用需注意的眉眉角角,別等搬了再說!

※教你寫出一流的銷售文案?

※回頭車貨運收費標準

※別再煩惱如何寫文案,掌握八大原則!

基於 abp vNext 和 .NET Core 開發博客項目 – Blazor 實戰系列(二)

系列文章

  1. 基於 abp vNext 和 .NET Core 開發博客項目 – 使用 abp cli 搭建項目
  2. 基於 abp vNext 和 .NET Core 開發博客項目 – 給項目瘦身,讓它跑起來
  3. 基於 abp vNext 和 .NET Core 開發博客項目 – 完善與美化,Swagger登場
  4. 基於 abp vNext 和 .NET Core 開發博客項目 – 數據訪問和代碼優先
  5. 基於 abp vNext 和 .NET Core 開發博客項目 – 自定義倉儲之增刪改查
  6. 基於 abp vNext 和 .NET Core 開發博客項目 – 統一規範API,包裝返回模型
  7. 基於 abp vNext 和 .NET Core 開發博客項目 – 再說Swagger,分組、描述、小綠鎖
  8. 基於 abp vNext 和 .NET Core 開發博客項目 – 接入GitHub,用JWT保護你的API
  9. 基於 abp vNext 和 .NET Core 開發博客項目 – 異常處理和日誌記錄
  10. 基於 abp vNext 和 .NET Core 開發博客項目 – 使用Redis緩存數據
  11. 基於 abp vNext 和 .NET Core 開發博客項目 – 集成Hangfire實現定時任務處理
  12. 基於 abp vNext 和 .NET Core 開發博客項目 – 用AutoMapper搞定對象映射
  13. 基於 abp vNext 和 .NET Core 開發博客項目 – 定時任務最佳實戰(一)
  14. 基於 abp vNext 和 .NET Core 開發博客項目 – 定時任務最佳實戰(二)
  15. 基於 abp vNext 和 .NET Core 開發博客項目 – 定時任務最佳實戰(三)
  16. 基於 abp vNext 和 .NET Core 開發博客項目 – 博客接口實戰篇(一)
  17. 基於 abp vNext 和 .NET Core 開發博客項目 – 博客接口實戰篇(二)
  18. 基於 abp vNext 和 .NET Core 開發博客項目 – 博客接口實戰篇(三)
  19. 基於 abp vNext 和 .NET Core 開發博客項目 – 博客接口實戰篇(四)
  20. 基於 abp vNext 和 .NET Core 開發博客項目 – 博客接口實戰篇(五)
  21. 基於 abp vNext 和 .NET Core 開發博客項目 – Blazor 實戰系列(一)
  22. 基於 abp vNext 和 .NET Core 開發博客項目 – Blazor 實戰系列(二)
  23. 基於 abp vNext 和 .NET Core 開發博客項目 – Blazor 實戰系列(三)
  24. 基於 abp vNext 和 .NET Core 開發博客項目 – Blazor 實戰系列(四)
  25. 基於 abp vNext 和 .NET Core 開發博客項目 – Blazor 實戰系列(五)
  26. 基於 abp vNext 和 .NET Core 開發博客項目 – Blazor 實戰系列(六)
  27. 基於 abp vNext 和 .NET Core 開發博客項目 – Blazor 實戰系列(七)
  28. 基於 abp vNext 和 .NET Core 開發博客項目 – Blazor 實戰系列(八)
  29. 基於 abp vNext 和 .NET Core 開發博客項目 – Blazor 實戰系列(九)
  30. 基於 abp vNext 和 .NET Core 開發博客項目 – 終結篇之發布項目

上一篇搭建了 Blazor 項目並將整體框架改造了一下,本篇將完成用 C# 代碼代替 JavaScript 實現幾個小功能,說是代替但並不能完全不用 JavaScript,應該說是盡量不用吧。

二維碼显示與隱藏

可以看到,當我鼠標移入的時候显示二維碼,移出的時候隱藏二維碼。

這個功能如果是用JavaScript來完成的話,肯定首先想到的是HTML的 Mouse 事件屬性,那麼在Blazor中也是一樣的,給我們實現了各種on*事件。

打開index.razor頁面,給微信圖標那個 NavLink 標籤添加兩個事件,@onmouseover和@onmouseout。

...
<NavLink class="link-item weixin" title="掃碼關注微信公眾號:『阿星Plus』查看更多。" @onmouseover="Hover" @onmouseout="Hover">
    <i class="iconfont iconweixin"></i>
</NavLink>
...

當鼠標移入移出的時候都執行我們自定義的一個方法Hover()。

C# 代碼寫在@code{}花括號中,實現显示和隱藏原理是利用css,默認是隱藏的,當显示的時候將具有隱藏屬性的class值去掉就可以了。

所以,可以添加兩個字段,一個用於判斷當前是否處於隱藏狀態,一個用來存儲class的值。

/// <summary>
/// 是否隱藏
/// </summary>
private bool IsHidden = true;

/// <summary>
/// 二維碼CSS
/// </summary>
private string QrCodeCssClass => IsHidden ? "hidden" : null;

當IsHidden = true,QrCodeCssClass = "hidden",當IsHidden = false,QrCodeCssClass = null。

那麼在Hover()方法中,不斷修改IsHidden的值就可以實現效果了。

/// <summary>
/// 鼠標移入移出操作
/// </summary>
private void Hover() => IsHidden = !IsHidden;

最後將QrCodeCssClass變量賦值給二維碼圖片所在的div上。

...
<div class="qrcode @QrCodeCssClass">
    <img src="https://static.meowv.com/images/wx_qrcode.jpg" />
</div>
...

大功告成,index.razor完整代碼如下:

@page "/"

<div class="main">
    <div class="container">
        <div class="intro">
            <div class="avatar">
                <a href="javascript:;"><img src="https://static.meowv.com/images/avatar.jpg"></a>
            </div>
            <div class="nickname">阿星Plus</div>
            <div class="description">
                <p>
                    生命不息,奮鬥不止
                    <br>Cease to struggle and you cease to live
                </p>
            </div>
            <div class="links">
                <NavLink class="link-item" title="Posts" href="posts">
                    <i class="iconfont iconread"></i>
                </NavLink>
                <NavLink target="_blank" class="link-item" title="Notes" href="https://notes.meowv.com/">
                    <i class="iconfont iconnotes"></i>
                </NavLink>
                <NavLink target="_blank" class="link-item" title="API" href="https://api.meowv.com/">
                    <i class="iconfont iconapi"></i>
                </NavLink>
                <NavLink class="link-item" title="Manage" href="/account/auth">
                    <i class="iconfont iconcode"></i>
                </NavLink>
                <NavLink target="_blank" class="link-item" title="Github" href="https://github.com/Meowv/">
                    <i class="iconfont icongithub"></i>
                </NavLink>
                <NavLink class="link-item weixin" title="掃碼關注微信公眾號:『阿星Plus』查看更多。" @onmouseover="Hover" @onmouseout="Hover">
                    <i class="iconfont iconweixin"></i>
                </NavLink>
                <div class="qrcode @QrCodeCssClass">
                    <img src="https://static.meowv.com/images/wx_qrcode.jpg" />
                </div>
            </div>
        </div>
    </div>
</div>

@code {
    /// <summary>
    /// 是否隱藏
    /// </summary>
    private bool IsHidden = true;

    /// <summary>
    /// 二維碼CSS
    /// </summary>
    private string QrCodeCssClass => IsHidden ? "hidden" : null;

    /// <summary>
    /// 鼠標移入移出操作
    /// </summary>
    private void Hover() => IsHidden = !IsHidden;
}

菜單显示與隱藏

菜單是在小屏幕上才會出現的,相信看完了二維碼的显示與隱藏,這個菜單的显示與隱藏就好辦了吧,實現方法是一樣的,菜單按鈕是在頭部組件Header.razor中的,包括主題切換功能,所以下面代碼都在Header.razor裏面。

@code {
    /// <summary>
    /// 下拉菜單是否打開
    /// </summary>
    private bool collapseNavMenu = false;

    /// <summary>
    /// 導航菜單CSS
    /// </summary>
    private string NavMenuCssClass => collapseNavMenu ? "active" : null;

    /// <summary>
    /// 显示/隱藏 菜單
    /// </summary>
    private void ToggleNavMenu() => collapseNavMenu = !collapseNavMenu;
}

默認是不打開的,collapseNavMenu = false。然後根據collapseNavMenu值為NavMenuCssClass給定不同的class。

...
<nav class="navbar-mobile">
    <div class="container">
        <div class="navbar-header">
            <div>
                <NavLink class="menu-item" href="" Match="NavLinkMatch.All">阿星Plus</NavLink>
                <NavLink>&nbsp;·&nbsp;Light</NavLink>
            </div>
            <div class="menu-toggle" @onclick="ToggleNavMenu">&#9776; Menu</div>
        </div>
        <div class="menu @NavMenuCssClass">
            <NavLink class="menu-item" href="posts">Posts</NavLink>
            <NavLink class="menu-item" href="categories">Categories</NavLink>
            <NavLink class="menu-item" href="tags">Tags</NavLink>
            <NavLink class="menu-item apps" href="apps">Apps</NavLink>
        </div>
    </div>
</nav>
...

與二維碼显示與隱藏唯一區別就是這裡是點擊按鈕,不是移入移出,所以菜單显示與隱藏需要用到@onclick方法。

主題切換

哇,這個主題切換真的是一言難盡,當切換主題的時候需要記住當前的主題是什麼,當刷新頁面或者跳轉其他頁面的時候,主題狀態是需要一致的,默認是白色主題,當切換暗黑色主題后其實是在body上加了一個class。

在Blazor實在是不知道用什麼辦法去動態控制body的樣式,所以這裏我想到了一個辦法,寫幾個全局的JavaScript方法,然後再Blazor中調用,要知道,他們是可以互相調用的,於是問題迎刃而解。

添加app.js文件,放在 /wwwroot/js/ 下面。

var func = window.func || {};

func = {
    setStorage: function (name, value) {
        localStorage.setItem(name, value);
    },
    getStorage: function (name) {
        return localStorage.getItem(name);
    },
    switchTheme: function () {
        var currentTheme = this.getStorage('theme') || 'Light';
        var isDark = currentTheme === 'Dark';

        if (isDark) {
            document.querySelector('body').classList.add('dark-theme');
        } else {
            document.querySelector('body').classList.remove('dark-theme');
        }
    }
};

這裏寫了三個方法,設置localStorage:setStorage(name,value),獲取localStorage:getStorage(name),切換主題:switchTheme(),localStorage 是瀏覽器以 name:value 形式的本地存儲對象。

switchTheme主要做的事情就是,判斷當前主題如果是暗黑,就給body加上對應的class,如果不是就去掉。

然後在 index.html 中引用。

...
<body>
    <app>
        <div class="loader"></div>
    </app>
    <script src="js/app.js"></script>
    <script src="_framework/blazor.webassembly.js"></script>
</body>
...

有了這個三個全局的JavaScript方法,切換主題就變得簡單多了,看代碼。

...
/// <summary>
/// 當前主題
/// </summary>
private string currentTheme;

/// <summary>
/// 初始化
/// </summary>
/// <returns></returns>
protected override async Task OnInitializedAsync()
{
    currentTheme = await JSRuntime.InvokeAsync<string>("window.func.getStorage", "theme") ?? "Light";

    await JSRuntime.InvokeVoidAsync("window.func.switchTheme");
}
...

注意在Blazor調用JavaScript方法需要注入IJSRuntime接口,@inject IJSRuntime JSRuntime。

新建一個變量currentTheme,在生命周期函數初始化的時候去調用JavaScript中的getStorage方法,獲取當前主題,考慮到第一次訪問的情況,可以給一個默認值為Light,表示白色主題,然後再去調用switchTheme,執行切換主題的方法。這樣頁面就會根據localStorage的值來確定當前的主題。

...
/// <summary>
/// 切換主題
/// </summary>
private async Task SwitchTheme()
{
    currentTheme = currentTheme == "Light" ? "Dark" : "Light";

    await JSRuntime.InvokeVoidAsync("window.func.setStorage", "theme", currentTheme);

    await JSRuntime.InvokeVoidAsync("window.func.switchTheme");
}
...

SwitchTheme()是切換主題的方法,當我們點擊input按鈕時可以任意切換,並且主題還要實時跟着變化。

當點擊按鈕執行SwitchTheme()時候改變currentTheme的值,然後將currentTheme傳遞給JavaScript方法setStorage,最後再次執行切換主題的JavaScript方法即可。

此時變量currentTheme也發揮了不少作用,在小屏幕下會显示當前主題的名稱,Dark or Light,可以直接將currentTheme在HTML中賦值即可。

並且我們input是checkbox類型,當是黑色主題的時候需要時選中的狀態,白色主題的時候不選中,這裏就可以利用checked屬性這樣寫:checked="@(currentTheme == "Dark")"。

<nav class="navbar">
    <div class="container">
       ...
        <div class="menu navbar-right">
           ...
            <input id="switch_default" type="checkbox" class="switch_default" @onchange="SwitchTheme" checked="@(currentTheme == "Dark")" />
            <label for="switch_default" class="toggleBtn"></label>
        </div>
    </div>
</nav>
<nav class="navbar">
    <div class="container">
       ...
        <div class="menu navbar-right">
           ...
            <input id="switch_default" type="checkbox" class="switch_default" @onchange="SwitchTheme" checked="@(currentTheme == "Dark")" />
            <label for="switch_default" class="toggleBtn"></label>
        </div>
    </div>
</nav>
<nav class="navbar-mobile">
    <div class="container">
        <div class="navbar-header">
            <div>
                <NavLink class="menu-item" href="" Match="NavLinkMatch.All">阿星Plus</NavLink>
                <NavLink @onclick="SwitchTheme">&nbsp;·&nbsp;@currentTheme</NavLink>
            </div>
            <div class="menu-toggle" @onclick="ToggleNavMenu">&#9776; Menu</div>
        </div>
        <div class="menu @NavMenuCssClass">
            ...
        </div>
    </div>
</nav>

OK,搞定,快去試試吧。

優化代碼

現在看起來亂亂的,並且設置獲取localStorage屬於公共的方法,說不定以後也能用到,我們將其封裝一下,便於日後的調用,不然要寫好多重複的代碼。

在Blazor項目根目錄添加文件夾Commons,在文件夾下添加一個Common.cs,目前用到了IJSRuntime,用構造函數注入,然後寫幾個公共的方法。

//Common.cs
using Microsoft.JSInterop;
using System.Threading.Tasks;

namespace Meowv.Blog.BlazorApp.Commons
{
    public class Common
    {
        private readonly IJSRuntime _jsRuntime;

        public Common(IJSRuntime jsRuntime)
        {
            _jsRuntime = jsRuntime;
        }

        /// <summary>
        /// 執行無返回值方法
        /// </summary>
        /// <param name="identifier"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public async ValueTask InvokeAsync(string identifier, params object[] args)
        {
            await _jsRuntime.InvokeVoidAsync(identifier, args);
        }

        /// <summary>
        /// 執行帶返回值的方法
        /// </summary>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="identifier"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public async ValueTask<TValue> InvokeAsync<TValue>(string identifier, params object[] args)
        {
            return await _jsRuntime.InvokeAsync<TValue>(identifier, args);
        }

        /// <summary>
        /// 設置localStorage
        /// </summary>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public async Task SetStorageAsync(string name, string value)
        {
            await InvokeAsync("window.func.setStorage", name, value);
        }

        /// <summary>
        /// 獲取localStorage
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public async Task<string> GetStorageAsync(string name)
        {
            return await InvokeAsync<string>("window.func.getStorage", name);
        }
    }
}

然後需要在Program.cs中注入。

using Meowv.Blog.BlazorApp.Commons;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Net.Http;
using System.Threading.Tasks;

namespace Meowv.Blog.BlazorApp
{
    public class Program
    {
        public static async Task Main(string[] args)
        {
            var builder = WebAssemblyHostBuilder.CreateDefault(args);
            builder.RootComponents.Add<App>("app");

            builder.Services.AddTransient(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });

            builder.Services.AddSingleton(typeof(Common));

            await builder.Build().RunAsync();
        }
    }
}

緊接着在_Imports.razor中注入使用Common,@inject Commons.Common Common。

改造一下Header.razor,全部代碼如下:

<header>
    <nav class="navbar">
        <div class="container">
            <div class="navbar-header header-logo">
                <NavLink class="menu-item" href="/" Match="NavLinkMatch.All">
                    阿星Plus
                </NavLink>
            </div>
            <div class="menu navbar-right">
                <NavLink class="menu-item" href="posts">Posts</NavLink>
                <NavLink class="menu-item" href="categories">Categories</NavLink>
                <NavLink class="menu-item" href="tags">Tags</NavLink>
                <NavLink class="menu-item apps" href="apps">Apps</NavLink>
                <input id="switch_default" type="checkbox" class="switch_default" @onchange="SwitchTheme" checked="@(currentTheme == "Dark")" />
                <label for="switch_default" class="toggleBtn"></label>
            </div>
        </div>
    </nav>
    <nav class="navbar-mobile">
        <div class="container">
            <div class="navbar-header">
                <div>
                    <NavLink class="menu-item" href="" Match="NavLinkMatch.All">阿星Plus</NavLink>
                    <NavLink @onclick="SwitchTheme">&nbsp;·&nbsp;@currentTheme</NavLink>
                </div>
                <div class="menu-toggle" @onclick="ToggleNavMenu">&#9776; Menu</div>
            </div>
            <div class="menu @NavMenuCssClass">
                <NavLink class="menu-item" href="posts">Posts</NavLink>
                <NavLink class="menu-item" href="categories">Categories</NavLink>
                <NavLink class="menu-item" href="tags">Tags</NavLink>
                <NavLink class="menu-item apps" href="apps">Apps</NavLink>
            </div>
        </div>
    </nav>
</header>

@code {
    /// <summary>
    /// 下拉菜單是否打開
    /// </summary>
    private bool collapseNavMenu = false;

    /// <summary>
    /// 導航菜單CSS
    /// </summary>
    private string NavMenuCssClass => collapseNavMenu ? "active" : null;

    /// <summary>
    /// 显示/隱藏 菜單
    /// </summary>
    private void ToggleNavMenu() => collapseNavMenu = !collapseNavMenu;

    /// <summary>
    /// 當前主題
    /// </summary>
    private string currentTheme;

    /// <summary>
    /// 初始化
    /// </summary>
    /// <returns></returns>
    protected override async Task OnInitializedAsync()
    {
        currentTheme = await Common.GetStorageAsync("theme") ?? "Light";

        await Common.InvokeAsync("window.func.switchTheme");
    }

    /// <summary>
    /// 切換主題
    /// </summary>
    private async Task SwitchTheme()
    {
        currentTheme = currentTheme == "Light" ? "Dark" : "Light";

        await Common.SetStorageAsync("theme", currentTheme);

        await Common.InvokeAsync("window.func.switchTheme");
    }
}

實現過程比較簡單,相信你絕對學會了。本篇就到這裏了,未完待續…

開源地址:https://github.com/Meowv/Blog/tree/blog_tutorial

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※想知道最厲害的網頁設計公司"嚨底家"!

※別再煩惱如何寫文案,掌握八大原則!

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※回頭車貨運收費標準

10幾萬就想買個好看又踏實的家用車,怪不得大家都買他們…

58萬元,在推出第二年才推出了自動擋車型,可能因為自動變速箱實在不行,在往後的幾年推出新款就再也沒推出過自動擋車型了,直到15年的時候擁有一定的調校技術和資源才推出了自動擋車型,也開始陸續地“開枝散恭弘=叶 恭弘”,紅標、藍標、運動版逐漸現世,但依然不太推薦自動擋車型,兩百塊能跑四百公里和只能跑300公里相比,你會怎麼選。

“,我要買哈弗H6!”

“哦?那你想買哪個版本?”

“啊?怎麼說?”

“哈弗H6有紅標運動版、藍標運動版、升級版、柴油版、Coupe車型….”

“……”

11月份哈弗H6賣出了7.03萬輛

排在國內熱銷SUV排行榜榜首

銷量超過了第二名的傳祺GS4兩倍有餘

為什麼哈弗H6這麼多人買?

因為它賣得火啊!

全文終。

自2011年哈弗H6在長城天津工廠下線以來,一步步地成為國內SUV市場的爆款,在2015年哈弗H6累計銷量破百萬,這是自主品牌的銷量神話…

哈弗H6犹如是淘寶中慢慢蛻變爆款的商品,在SUV市場還沒全面興起的時候,恰好在這個時間上架,也憑藉一些實力做出了一些口碑,可以理解為“刷”好評。消費者要買想SUV,首先看的是SUV銷量排行榜,其次是看口碑,十個口碑中有六個好評其實已經引起消費者的好感和購買慾望,這是大部分中國消費者的消費習慣。

▲哈弗H6符合國人口味的外觀

▲哈弗H6不俗的內飾

口碑是可以“刷”出來的,但也需要用實力去支撐,哈弗H6也有它的“過人之處”,多重的因素令它成為了最成功的SUV車型之一。每一個商家不會放過任何一個有爆款潛力的商品,更何況是已經成為爆款的商品,更是加大投入推廣和改進,爭取獲得更好的銷量成績。

▲哈弗H6 COUpE車型

11年上市的哈弗H6隻有兩個版本,分別是2.0L和2.0T的發動機,只有手動擋配置,當時國內的自動變速箱技術還真不夠成熟,所以那時候大部分自主車型都是手動擋,畢竟机械離合器構造簡單成本低。價錢也不低,當時候最低配也要9.58萬元,在推出第二年才推出了自動擋車型,可能因為自動變速箱實在不行,在往後的幾年推出新款就再也沒推出過自動擋車型了,直到15年的時候擁有一定的調校技術和資源才推出了自動擋車型,也開始陸續地“開枝散恭弘=叶 恭弘”,紅標、藍標、運動版逐漸現世,但依然不太推薦自動擋車型,兩百塊能跑四百公里和只能跑300公里相比,你會怎麼選?手動擋剛開始接觸可能稍難上手一些,但用得久了,其實真沒什麼,這是很多開手動擋車的老司機原話。

現在很多更新換代的車型無非就是稍微改改外觀內飾,增加或減少配置控制整車成本,都是這樣的一個套路,哈弗H6這麼多款版本車型也不例外,無論是外觀和內飾配置怎麼變怎麼改,都是用那套原來舊的動力總成、懸架甚至是車身結構,並沒有“改頭”只是“換臉”而已。眾所周知大部分自主品牌使用的動力總成大多都是合資品牌的老舊技術,質量過關耐用,但就是跟不上時代的步伐,就拿國內的2.0T發動機和本田的2.0T發動機相比,真的是天地之別。

奈何,國人的用車習慣就是車能跑得快、空間夠大人坐得舒服也載得多人,其次還有外觀要好看霸氣有面子,重點還要價錢不能高,所以十來萬的SUV最符合國人的口味,哈弗H6就是這樣符合國情,但真要說人生第二台車會不會選哈弗,相信很多消費者都是否定的。

再來說說轎車吧,轎車一直都不是自主品牌的強悍,SUV市場一片繁華,但轎車方面還是十分中庸,11月份轎車銷量排行榜十中有九都是合資品牌,都是我們熟悉的軒逸、朗逸、速騰、英朗等等一直很火的十來萬緊湊型車。

▲日產軒逸-11月份轎車排行榜銷量冠軍

轎車銷量排行榜前十名的銷量並沒有SUV排行榜那麼懸殊,都是賣出三、四萬台這樣,日產軒逸賣出4.52萬輛排在第一,對於部分抵制日貨的消費者來說很氣,但日系車特別符合家庭用車習慣這是最大的事實,賣出一台日系車日本賺到的利潤遠遠比不上我們自己國家收的稅多,這裏就不往下說了,日系車還是賣得很好,證明大部分消費者都是理性消費的。

▲國人的用車還是以家庭為主

中國家庭就是需要一台看着大氣開起來舒服又省油的轎車,車價在10-15萬元是國人最能接受的區間,首付供車壓力不算大,全款支付也並不需要N+1年才能實現“有車一族”,所以轎車銷量排行榜中車型都涉及到這個車價區間,這也是國內汽車市場最受歡迎的價格區間。

你想問轎車銷量排行榜裏面哪款車比較好?不吹不黑告訴你們,這些車都差不多,很適合家庭用車,如果你想從中選一台,可以按以下步驟:

第一、從外觀入手,除了自己的審美之外,問問父母的意見(僅僅外觀一項)有女朋友的問女朋友有老婆的問老婆,從中挑幾款順眼好看的車型;

第二、到4S店靜態體驗,空間大小和座椅的舒適性比較,當然最好也能帶上父母或者老婆,畢竟以後他們都會坐上你的車;

第三、看手頭的預算,挑配置,配置不用多夠用就好,省點總比亂花好;

第四、道路試駕,其中十來萬的合資車開起來差不到哪裡去,省油才是最關鍵,其次感受一下車輛的濾震,挑開起來順手最舒服的那台絕對沒錯;

第五、看中哪個配置車型就可以跟銷售砍價了。

有個性的車,例如外觀極端,不管是好看還是難看,基本都賣不好,自然成為了小眾車型。國人的審美逐漸被常見的車型平淡化,你覺得這輛車個性又獨特,但當你真正需要買車的時候不會想到這些小眾的車型,除非是價錢吸引到你,大多人都會回歸到銷量排行榜中,這是一種依賴的心理效應,總覺得賣得好的車就是最靠譜的車,至少不會因為自己的選擇而後悔,就算是後悔也有一大把人陪自己呢,車子出問題了大不了跟“同病相憐”的一起抱怨罷了。

總結:SUV或轎車也好,其實不必要太糾結每個月的銷量排行榜,我們可以將它作為我們買車的參考,而不是將它作為我們買車的標準,選擇自己真心喜歡的車型,沒必要迎合他人的口味。榜上有名的車型自然有它們存在的道理,這裏不談它們的優點或缺點,畢竟人無完人,車也一樣嘛!本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

※教你寫出一流的銷售文案?

※超省錢租車方案

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※回頭車貨運收費標準

當精工製造遇上了一雙慧眼,會造出一輛什麼車?

在整個越野路段對比體驗中,印象最深刻的就是傲虎的動力輸出特性,由於傲虎使用的是自然吸氣水平對置發動機與CVT變速箱,低轉速時的扭力輸出比渦輪增壓發動機要好很多,動力的輸出非常線性,簡單點來說就是很容易駕馭,同時對安全也有幫助,駕駛員能把更多的精力放在觀察路況與路線當中。

想要打造出一輛能夠大賣的爆款車型,或許並不難,只要它有足夠的賣點即可,例如帥氣靚麗的外形,又或者極致的駕駛樂趣,再或者是豐富的配置,相較於那些各有特色的車型,覺得“均衡”才是一輛好車的必備條件。

近日,就試駕到了兩款非常“均衡”的車,同時它們對於斯巴魯而言也具有里程碑意義,因為它們首次將斯巴魯的EyeSight技術帶進中國,這兩款車就是斯巴魯的力獅與傲虎。

每次提及到斯巴魯,首先就會想到它們引以為傲的“水平對置發動機”與“左右對稱全時四驅”,為什麼斯巴魯一直在堅持,覺得一方面是對駕駛員的尊重,另一方面是對自然界的致敬。

在這次的斯巴魯力獅性能體驗中,在廣東國際賽車場輪流試駕了斯巴魯力獅、奧迪A4L和奔馳C級,三款車型的驅動方式分別為:全時四驅、前驅和后驅。

三種驅動形式各有特色,在賽道上進行極限駕駛時,力獅的左右對稱全時四驅盡顯其優勢,最明顯的就是出彎極限非常高,同樣的一個高速彎,開着力獅能夠從容的全油門出彎,然而A4L和C級都無法這樣做,否則就會伴隨着轉向不足與轉向過度。

除了左右對稱全時四驅,水平對置發動機的低重心也對車輛操控有积極意義,除了出色的操控,在三車對比當中,力獅 2017款 2.5i 全驅榮耀版 EyeSight在賽道上的動力表現值得稱讚,對比車型的奧迪A4L 40 TFSI與奔馳C200L同樣是使用2.0T的直列四缸渦輪增壓發動機,力獅則是2.5L自然吸氣水平對置發動機。

還沒開始試駕之前,一度認為用2.0T渦輪增壓與2.5L自然吸氣對比,好像有點不太公平,可是輪流試駕完三輛車之後,徹底改觀。賽道是一個分秒必爭的地方,力獅的CVT變速箱在此時此刻發揮出了它的優點。

通過方向盤右側多功能按鍵設定運動駕駛模式后,油門踏板變得非常靈敏,出彎時深踩油門,發動機轉速迅速上升,隨後一直維持在最佳動力輸出的轉速,整個過程不僅免除了換檔時間,動力的傳遞還非常及時,這樣的表現與市面上的大多數CVT都不太一樣。

如果你現在還是認為城市SUV的四驅性能都是噱頭,那麼就大錯特錯了,其實在此之前,也是對城市SUV的四驅系統不太看好,但是親自體驗完斯巴魯傲虎、奧迪Q5和豐田漢蘭達之後,徹底感受到傲虎的優勢。

“穩定可靠,簡單易用”,這是對於傲虎越野性能的總結,越野場地的賽道長度很短,但是涵蓋了眾多項目,其中最具有參考意義的就是炮彈坑、岩石路段和陡坡環節。

在整個越野路段對比體驗中,印象最深刻的就是傲虎的動力輸出特性,由於傲虎使用的是自然吸氣水平對置發動機與CVT變速箱,低轉速時的扭力輸出比渦輪增壓發動機要好很多,動力的輸出非常線性,簡單點來說就是很容易駕馭,同時對安全也有幫助,駕駛員能把更多的精力放在觀察路況與路線當中。

除了線性的動力輸出,還有一個關鍵點不得不提,那就是非常高效率的电子限滑系統,當車輛開啟了X-MODE模式之後,电子限滑系統的控制邏輯就會改變,變得更加积極、靈敏,在此模式下通過大炮彈坑,雖然兩個對象車輪懸空,但是整個過程一氣呵成,电子限滑系統反應迅速,車輪幾乎沒有出現空轉。

斯巴魯傲虎的陡坡緩降功能同樣是非常好用,當我們開啟X-MODE模式后,陡坡緩降系統就會在我們下坡時自動控制車速,我們先需要通過剎車制動把車輛控制在我們想要的車速,然後鬆開剎車踏板,系統就是自動保持在當前時速,我們要做的就是專註於轉向的控制。

無論是力獅的賽道性能還是傲虎的越野性能體驗,回歸到我們實際用車當中,覺得最重要的還是——安全,這是親自體驗過後最直觀的感受,即使你是第一次駕駛它們,你也會發現並不需要什麼適應過程,車輛會幫你處理那些瑣碎的事情,我們只需專註於駕駛,專註於觀察路面的狀況即可,這就是智能化的深度表現。

從第一輛汽車的誕生開始,車輛安全永遠都是世人關注的焦點,斯巴魯為什麼堅持全時四輪驅動,為什麼堅持水平對置發動機,覺得這些都是基於安全這個大前提去考慮的。

2017款斯巴魯力獅和傲虎是國內首次搭載預防性安全技術——EyeSight駕駛輔助系統的車型,繼日本、澳大利亞、北美、歐洲上市后,中國是第五個投放的市場,EyeSight的實際表現如何呢,感觸最深的是——細膩。

體驗內容包含了EyeSight駕駛輔助系統的幾大功能,防碰撞制動系統(pCB)、起步油門誤操作預防功能、全車速自適應巡航控制系統(ACC)和警報與提示功能。只要是配備了EyeSight駕駛輔助系統的車型,每當車輛啟動,防碰撞制動系統就會處於開啟狀態,若車速小於50km/h,能夠避免車輛與前方靜止的障礙物發生碰撞。

車內視角

車外視角

在實際測試中,分別以10km/h、30km/h和50km/h的時速進行體驗,車速越高,防碰撞制動系統的介入就越早,當系統識別到前方有障礙物,並且駕駛員沒有進行減速時,就會在儀錶盤進行相關提示,並帶有蜂鳴聲音,如果駕駛員仍然沒有進行任何操作,隨後車輛就會自動剎車至靜止狀態,整個自動剎車過程中,車內人員不會感覺到非常突兀,因為系統會進行提前預先剎車。

全車速自適應巡航控制系統能夠在0~180km/h的車速範圍內工作,能夠實現跟車功能,當車輛靜止后,可以通過兩個途徑恢復之前設定的時速繼續巡航,輕踩油門踏板或者是向上撥動車速設定撥桿即可。

這套全車速自適應巡航控制系統有幾個細節點做得很好,首先是跟車距離的設定,即便是從最近車距調節至最遠車距,系統也不會猛然減速,整個調節過程比人為控製做得還要好。

其次是對於前方有車輛併入車道,識別度很高,減速過程也不會感覺到很突兀,剎車力度有一個漸進的過程。除了這些,儀錶盤的動畫显示也做得非常好,無論是車輛併入,還是跟車的過程中,只要是我們的車輛處於減速狀態,儀錶盤中的显示剎車燈亮起的狀態,從這些這些細節的設計能夠看出斯巴魯還是很走心的。

EyeSight駕駛輔助系統還有一個功能非常適合剛拿到駕照的新手,那就是“起步油門誤操作預防功能”,當車輛處於靜止狀態下,如果系統識別到前方有靜止的障礙物,同時駕駛員將檔位掛到前進檔,即便是深踩油門,車輛也不會快速往前行駛,造成事故。

為什麼會這呢,其實是因為系統對發動機輸出進行抑制,發動機處於低速運轉,車輛只會有輕微的蠕動,這時候儀錶盤會有相關的提示和警示音,這樣就能夠很好的避免駕駛員掛錯檔而造成不必要的損失。

回過頭來看到整個EyeSight駕駛輔助系統,認為斯巴魯之所以選擇雙攝像頭,主要還是想讓更多的消費者體驗到這種預防性安全系統,為什麼這樣說呢,目前為止,其實各種駕駛輔助系統的方案都存在弱項,EyeSight的立體攝像頭方案很重要的一點在於其性價比很高。

在其它廠商的車型中,配備駕駛輔助系統的車型絕大多數都是頂配車型,但是這次斯巴魯將EyeSight引入中國,並沒有投放在頂配車型上,而是中配車型,他們的目的就是讓我們不需要花大價錢就能夠使用上EyeSight,始終將汽車安全性放在首位,這就是斯巴魯的獨特魅力。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※別再煩惱如何寫文案,掌握八大原則!

※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※超省錢租車方案

※教你寫出一流的銷售文案?

※網頁設計最專業,超強功能平台可客製化

※產品缺大量曝光嗎?你需要的是一流包裝設計!

買了小排量就鐵定省油?天真!

5排量啊,還帶T,聽起來像思域的那台哦。你跟我談油耗。看下F1的發動機怎麼噴油的。F1的百公里油耗差不多在50—70升。你跟我說小排量省油。所以發動機的油耗與排量沒有最直接的關係,而是發動機做功的多少,我們都知道能量守恆定律。

這两天由於各個地方的霧霾,大排量的汽車又被推上風口浪尖,甚至引起不少所謂的微博大V撕逼。還有所謂的大學生上街遊行抵制大排量。

以往說到大排量就會想到油老虎,確實,我們所見到的大排量的車要麼是跑車。

要麼是旗艦級的豪車。

還有“美國車”。

首先發動機的排量是個什麼東西呢?今天就不列公式裝逼了。打個簡單的比方,如果說小排量是瘦子。

那麼大排量就像胖子。

同樣吃一個大蛋糕,大排量每一口吃得更多,小排量每口吃得更少,所以胖子吃得更快。不過即使這樣,只要時間充足,瘦子最後也能把蛋糕吃完。

這也是我們大多數人的印象,大排量發動機動力更好,車跑得更快,但是油耗更高。

為什麼會有大排量就鐵定高耗油的定論呢?因為胖子嘴大,餓起來連自己都吃,所以每一口吃得多,你要讓豬八戒把人蔘果分兩口吃肯定不可能。

而瘦子則可以每次吃半口,如果感覺有點飽了接下來的半口可以留着不吃。理論上聽着確實很省。

但是為什麼現在很多朋友買了1.2T三缸和1.5T四缸,發現並沒有想象中省油呢?先不說那所謂的“工信部油耗”。

我們上面也說了,從A到B就像吃吃一塊蛋糕,如果每一口吃得多,那麼肯定吃得快,要是小排量也想和大排量一起吃完,那就必須吃得更快,所以像之前說的1050馬力的本田1.5T F1發動機工作轉速就高達14000轉。1.5排量啊,還帶T,聽起來像思域的那台哦。

你跟我談油耗?看下F1的發動機怎麼噴油的!

F1的百公里油耗差不多在50—70升。你跟我說小排量省油?所以發動機的油耗與排量沒有最直接的關係,而是發動機做功的多少,我們都知道能量守恆定律。要想馬兒跑得快肯定要讓馬多吃草。那麼市面上的小排量發動機的優勢在哪裡呢?我們會發現大排量的車發動機也是多缸數,3.0以上排量就肯定是6缸了,4.0以上至少8缸,再往上就12缸,還是那句老話,馬力大十匹不如體重減十斤。12缸畢竟缸數在這裏,所以像3缸4缸發動機在自重上佔有不少優勢。如果兩台發動機功率一樣,那麼重量更輕的在油耗上肯定佔有優勢。

所以發動機的油耗是看做功的多少,(做功的多少又關係發動機的熱效率)那麼做的功多少能用到輪上又考慮到變速箱和輪胎等多方面因素了,一台車是否省油還是看你怎麼開,只是小排量更容易開出低油耗。

如果你經常切二擋。

2.0也可以開出6.0的油耗。

如果你只是當做一個從A到B的工具,能動就可以,不追求什麼加速能力,推背感,6.0也可以開出2.0的油耗。

就像以前手機還是2G網絡的時候一個月30M都用不完,現在用上4G一個月10G也不夠。

而那些把空氣污染和霧霾全部歸咎於汽車排放的人,看了下面的成績單,是不是說明邯鄲的汽車排放是北京的3倍呢?

那如果霧霾的罪魁禍首不是汽車又是誰呢?

本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※教你寫出一流的銷售文案?

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※回頭車貨運收費標準

※別再煩惱如何寫文案,掌握八大原則!

※超省錢租車方案

※產品缺大量曝光嗎?你需要的是一流包裝設計!

“小7系”降臨,E級顫抖了嗎?!全新寶馬5系Li揭開面紗!

而在動力總成方面,預計未來國產長軸距版車型將搭載不同功率調校的全新2。0T發動機以及3。0T發動機。與發動機匹配的有望是8速自動變速箱,部分車型還將搭載四驅系統。新5系標準軸距版海外的5系標準軸距版將於2017年2月在歐洲率先開售,起售價為36025英鎊,摺合人民幣29。

日前,華晨寶馬公布了一張國產全新5系Li長軸距版車型的官方圖片。新車針對中國消費者喜好,在全新一代寶馬5系標準軸距版的基礎上進行軸距加長打造而成。有消息稱全新5系Li有望在2017年4月的上海車展首發亮相,並且預計在2017年6月正式上市。

全新5系Li

在外觀方面,全新5系Li與標準軸距版幾乎保持一致,標誌性的雙腎型進氣格柵,開眼角式大燈,貫穿全車的側面腰線,前輪後方的氣流出口,儼然在向大哥7系看齊。

新5系標準軸距版

7系

內飾方面,預計也會和標準軸距版保持一致,延續新7系的設計語言,豪華之餘充滿科技感。略偏向駕駛者的中控布局,懸浮式中控大屏,全新設計的多功能方向盤,以及整體的飾料風格和色彩搭配,讓人一眼看上去很容易以為就是7系的內飾。

新5系標準軸距版

7系

配置方面,新車預計將配備多種新7繫上的高科技配置,如手勢控制、遙控泊車、遠程3D視角、HUD抬頭显示、夜視系統等。

而在動力總成方面,預計未來國產長軸距版車型將搭載不同功率調校的全新2.0T發動機以及3.0T發動機。與發動機匹配的有望是8速自動變速箱,部分車型還將搭載四驅系統。

新5系標準軸距版

海外的5系標準軸距版將於2017年2月在歐洲率先開售,起售價為36025英鎊,摺合人民幣29.67萬元,而國內售價則尚未公布。用5系的價格買到一輛“小7系”,這種越級的體驗不再是奔馳E級一家獨大,相信隨着全新寶馬5系Li的推出,國內C級豪華轎車市場的競爭會越發激烈。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※超省錢租車方案

※別再煩惱如何寫文案,掌握八大原則!

※回頭車貨運收費標準

※教你寫出一流的銷售文案?

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※網頁設計最專業,超強功能平台可客製化