倫敦一些地區要在路燈內安裝充電站,讓電動車充電更方便

 

 

隨著電動車逐漸興起,充電的問題變得越來越受到關注,當使用者在城市中開著電動車時,究竟該去哪裡尋找充電設施?Electrek 報導指出,倫敦一些地區似乎正試著透過在路燈柱內安裝充電站的計畫,來解決這個問題。

在充電的問題上,北歐國家似乎具有「先天」優勢,為了面臨嚴峻的冬季氣溫,他們原先在街道上就廣泛設有協助汽車引擎啟動的加熱器(block heater),因此也能夠運用同樣系統讓電動車能在街道上進行充電。

其他沒有這麼寒冷的地方就不同了,在沒有類似基礎設施的情況下,一些公司正在思考相關方案來解決這個問題;像是特斯拉就推出了城市專用的充電站,雖然因為功率低使得充電速度較慢,但也不失為市區內的一個選擇。

另一方面,位在倫敦的肯辛頓與切爾西區(RBKC)的行政當局則選擇了不同的做法,他們已經和能源供應商OVO Energy 和近期獲得西門子投資的德國充電公司ubitricity 簽約,要在都市中現有的燈柱內安裝充電站。

之所以做出這項決定,當地的交通委員會主席Cllr Gerard Hargreaves 表示,是因為居民的充電需求正隨著電動車持續增長,但多數人都無法在附近街道的停車處找到充電設施,讓電動車的充電變得難以進行。

Hargreaves 認為,透過在復古路燈內設置充電設施,駕駛人在住家附近就可以直接充電,倫敦的空氣汙染問題也得以緩解。「除此之外,在路燈內設置意味著不需要額外的基礎建設,更具成本效益的同時也不會影響市容。」

肯辛頓與切爾西區目前計畫安裝的是ubitricity 提供的「SimpleSockets」充電系統,最大輸出功率為4.6 kW。

OVO 表示,SimpleSockets 將會設立在付費和非付費停車格附近的路燈內,24 小時提供使用,每度電只需15 便士(約台幣6 元),這讓電動車不僅更為方便,花費也將更貼近一般人生活。

雖然SimpleSockets 每度電收取的費用與該區的電費規定相當,但Electrek 報導也指出,用戶必須每月繳納7.99 英鎊(約台幣320 元)的訂閱費,同時向ubitricity 購買199 英鎊(約台幣7,960 元)的電纜,才能使用這項收費標準。

當然用戶也可以選擇不繳納訂閱費,但使用上還是必須花100 多英鎊(約台幣4,000 元)購買使用的電纜,同時每度電的收費也將提高到19 便士(約台幣7.6 元),只是即使如此,也遠比英國國內的其他充電選擇好上許多。

ubitricity 目前已經開始在肯辛頓與切爾西區內進行安裝,目標在1 月底前要安裝完成50 個在路燈座內的充電裝置。

(合作媒體:。首圖來源: 臉書)  

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

【其他文章推薦】

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

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

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

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

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

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

聚甘新

【asp.net core 系列】10 實戰之ActionFilter

0.前言

在上一篇中,我們提到了如何創建一個UnitOfWork並通過ActionFilter設置啟用。這一篇我們將簡單介紹一下ActionFilter以及如何利用ActionFilter,順便補齊一下上一篇的工具類。

1. ActionFilter 介紹

ActionFilter全稱是ActionFilterAttribute,我們根據微軟的命名規範可以看出這是一個特性類,看一下它的聲明:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public abstract class ActionFilterAttribute : Attribute, IActionFilter, IFilterMetadata, IAsyncActionFilter, IAsyncResultFilter, IOrderedFilter, IResultFilter

這是一個允許標註在類和方法上的特性類,允許多個標記,標註之後子類會繼承父類的特性。然後,這個類是一個抽象類,所以我們可以通過繼承ActionFilterAttribute來編寫自己的ActionFilter。

1.1 ActionFilter的四個方法

對於一個ActionFilter而言,最重要的是它的四個方法:

public virtual void OnActionExecuted(ActionExecutedContext context);
public virtual void OnActionExecuting(ActionExecutingContext context);

public virtual void OnResultExecuted(ResultExecutedContext context);
public virtual void OnResultExecuting(ResultExecutingContext context);

上圖是這四個方法在一次請求中執行的順序。在一次請求真正執行之前,想要攔截這個請求,應該使用OnActionExecuting

為什麼單獨說這個呢?因為這個方法的出鏡率很高,大多數時候都會使用這個方法進行請求過濾。

1.2 在ActionFilter中我們能做什麼

我們來簡單介紹一下,四個方法中的四種上下文類型,看一看裏面有哪些我們可以利用的方法:

1.2.1 ActionExecutingContext

這是一個Action執行前的上下文,表示Action並未開始執行,但是已經獲取到了控制器實例:

public class ActionExecutingContext : FilterContext
{
    public virtual IDictionary<string, object> ActionArguments { get; }
    public virtual object Controller { get; }
    public virtual IActionResult Result { get; set; }
}

ActionExecutingContext繼承自FilterContext,我們暫且不關注它的父類,只看一下它自己的屬性。

  • ActionArguments 表示Action的參數列表,這裏面放着各種從用戶接到請求參數以及其他中間處理程序添加的參數
  • Controller 表示執行該請求的控制器,在之前我們提過,asp.net core 對於控制器的限制很小,所以控制器什麼類型都可能,故而這裏使用object作為控制器類型
  • Result 執行結果,正常情況下,在此處獲取這個屬性的值沒有意義。但是我們可以通過修改這個屬性的值,來讓我們攔截請求

1.2.2 ActionExecutedContext

ActionExecutedContext 表示Action執行完成后的上下文,這時候Action已經執行完成,我們可以通過這個獲取Action執行結果:

public class ActionExecutedContext : FilterContext
{
    public virtual bool Canceled { get; set; }
    public virtual object Controller { get; }
    public virtual Exception Exception { get; set; }
    public virtual ExceptionDispatchInfo ExceptionDispatchInfo { get; set; }
    public virtual bool ExceptionHandled { get; set; }
    public virtual IActionResult Result { get; set; }
}

同樣,繼承自FilterContext,暫且忽略。

  • Canceled 表示是否被設置短路
  • Controller 處理請求的控制器
  • Exception 執行過程中是否發生異常,如果有異常則 有值,否則為Null
  • ExceptionHandled 異常是否被處理
  • Result 此處對Result進行修改不會屏蔽執行的ActionResult,但是可以向用戶隱藏對應的實現

1.2.3 ResultExecutingContext

這是在Result渲染之前執行的上下文,這時候Action已經執行完畢,正準備渲染Result:

public class ResultExecutingContext : FilterContext
{
    public virtual bool Cancel { get; set; }
    public virtual object Controller { get; }
    public virtual IActionResult Result { get; set; }
}
  • Cancel 取消當前結果執行以及後續篩選器的執行
  • Controller 控制器
  • Result 處理結果

1.2.4 ResultExecutedContext

Result已經執行完成了,獲取執行結果上下文:

public class ResultExecutedContext : FilterContext
{
    public virtual bool Canceled { get; set; }
    public virtual object Controller { get; }
    public virtual Exception Exception { get; set; }
    public virtual ExceptionDispatchInfo ExceptionDispatchInfo { get; set; }
    public virtual bool ExceptionHandled { get; set; }
    public virtual IActionResult Result { get; }
}

這個類與 ActionExecutedContext類似,就不做介紹了。

1.2.5 FilterContext

在上面的四個上下文都繼承自 FilterContext,那麼我們來看一下FilterContext中有哪些屬性或者方法:

public abstract class FilterContext : ActionContext
{
    public virtual IList<IFilterMetadata> Filters { get; }
    public TMetadata FindEffectivePolicy<TMetadata>() where TMetadata : IFilterMetadata;
}

可以看到FilterContext繼承了另一個ActionContext的類。小夥伴們應該對這個類要有一定的概念,這個類是Action的上下文類。它完整存在於一個Action的生命周期,所以有時候可以通過ActionContext進行Action級的數據傳遞(不推薦)。

那麼,繼續讓我們回過頭來看看ActionContext里有什麼:

public class ActionContext
{
    public ActionDescriptor ActionDescriptor { get; set; }
    public HttpContext HttpContext { get; set; }
    public ModelStateDictionary ModelState { get; }
    public RouteData RouteData { get; set; }
}
  • ActionDescriptor 執行的Action描述信息,包括Action的显示名稱、一些參數等,具體用到的時候,再為大夥詳細說
  • HttpContext 可以通過這個屬性獲取此次請求的Request和Response對象
  • ModelState 模型校驗信息, 這部分在後續再為小夥伴們細說
  • RouteData 路由信息,asp.net core 在處理請求時解析出來的路由信息,包括在程序中修改的路由信息

2. 使用ActionFilter

在《【asp.net core 系列】9 實戰之 UnitOfWork以及自定義代碼生成》也就是上一篇中,介紹到了ActionFilter與普通特性類一致,可以通過標註控制器然後啟用該ActionFilter。

因為大多數情況下,一個ActionFilter並不會僅僅局限於一個控制器,而是應用於多個控制器。所以這時候,我們通常會設置一個基礎控制器,在這個控制器上進行標註,然後讓子類繼承這個控制器。通過這種方式來實現一次聲明多次使用。

當然,在asp.net core 中添加了另外的一種使用ActionFilter的方式,Setup.cs中

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
}

默認是這樣的,我們可以通過設置參數來添加一個全局應用的Filter,例如說我們上一篇中創建的 UnitOfWorkFilterAttribute:

services.AddControllersWithViews(options=>
{
    options.Filters.Add<UnitOfWorkFilterAttribute>();
});

通過這種方式可以啟用一個全局ActionFilter。如果需要使用asp.net core的默認依賴注入可以使用 AddService進行配置。(依賴注入的內容在後續會講解)。

3. 工具類生成

繼續上一篇遺留的內容:

public static void CreateEntityTypeConfig(Type type)
{
    var targetNamespace = type.Namespace.Replace("Data.Models", "");
    if (targetNamespace.StartsWith("."))
    {
        targetNamespace = targetNamespace.Remove(0);
    }
    var targetDir = Path.Combine(new[] { CurrentDirect, "Domain.Implements", "EntityConfigures" }.Concat(
        targetNamespace.Split('.')).ToArray());

    if (!Directory.Exists(targetDir))
    {
        Directory.CreateDirectory(targetDir);
    }
    var baseName = type.Name.Replace("Entity", "");
    if (!string.IsNullOrEmpty(targetNamespace))
    {
        targetNamespace = $".{targetNamespace}";
    }

    var file = $"using {type.Namespace};" +
        $"\r\nusing Microsoft.EntityFrameworkCore;" +
        $"\r\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;" +
        $"\r\nnamespace Domain.Implements.EntityConfigures{targetNamespace}" +
        "\r\n{" +
        $"\r\n\tpublic class {baseName}Config : IEntityTypeConfiguration<{type.Name}>" +
        "\r\n\t{" +
        "\r\n\t\tpublic void Configure(EntityTypeBuilder<SysUser> builder)" +
        "\r\n\t\t{" +
        $"\r\n\t\t\tbuilder.ToTable(\"{baseName}\");" +
        $"\r\n\t\t\tbuilder.HasKey(p => p.Id);" +
        "\r\n\t\t}\r\n\t}\r\n}";
    File.WriteAllText(Path.Combine(targetDir, $"{baseName}Config.cs"), file);
}

工具類其實本質上就是一次文件寫入的方法,本身沒什麼難度。

不過,這裏還有有個小問題,每次調用都會覆蓋原有的文件,還有就是這裏面有很多可以優化的地方,小夥伴們可以自己試試去優化一下,讓代碼更好看一點。

4 總結

到目前為止,實戰系列也有了幾篇,很多小夥伴問我能提供一下源碼嗎?當然,能呀。不過不是現在,容我留個謎底。當主要框架功能完成之後,我就會給小夥伴們發代碼的。

其實也是因為現在還沒個完整的,開放給小夥伴們也沒啥意義。當然了,跟着一塊敲,也是能實現的哈。關鍵地方的代碼都有。

更多內容煩請關注我的博客《高先生小屋》

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

【其他文章推薦】

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

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

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

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

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

聚甘新

基於 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 開發博客項目 – 終結篇之發布項目

終於要接近尾聲了,上一篇基本上將文章模塊的所有功能都完成了,整個博客頁面也都完成了,本篇主要來美化幾個地方,修修補補。

編輯器主題切換

當我們新增和編輯文章的時候,默認編輯器是白色的,如果點擊了頭部切換主題按鈕,我想要把編輯器主題顏色也做相應的改變該如何去實現呢?

剛好,editor.md是支持主題切換的,這就比較舒服了,直接按照要求調用對應的方法即可。

app.jsrenderEditor函數中我們已經自定義了三個參數themeeditorThemepreviewTheme,這三個參數就是來改變編輯器主題顏色的。

還是將值存在localStorage中,和我們博客的主題切換一樣,這裏叫editorTheme

theme: localStorage.editorTheme || 'default',
editorTheme: localStorage.editorTheme === 'dark' ? 'pastel-on-dark' : 'default',
previewTheme: localStorage.editorTheme || 'default',

默認從localStorage中取數據,如果沒取到的話,給對應的默認值。第二個參數有點特殊,用了一個三元表達式給不同的值。

然後在主題切換的時候也對編輯器做相應的調整即可。

打開Header.razor頭部組件,找到SwitchTheme()切換主題的方法,添加一句await Common.SwitchEditorTheme(currentTheme);

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

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

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

    var uri = await Common.CurrentUri();
    if (uri.AbsolutePath.StartsWith("/admin/post"))
    {
        await Common.SwitchEditorTheme(currentTheme);
    }
}

將具體切換邏輯放到SwitchEditorTheme中,他接收一個參數currentTheme,用來判斷是切換黑的還是白的。

/// <summary>
/// 切換編輯器主題
/// </summary>
/// <param name="currentTheme"></param>
/// <returns></returns>
public async Task SwitchEditorTheme(string currentTheme)
{
    var editorTheme = currentTheme == "Light" ? "default" : "dark";

    await SetStorageAsync("editorTheme", editorTheme);

    await InvokeAsync("window.func.switchEditorTheme");
}

切換主題之前拿到當前URI對象,判斷當前請求的鏈接是否是新增和更新文章的那個頁面,即”/admin/post”,才去執行切換編輯器主題的方法,當不是這個頁面的時候,編輯器是沒有渲染出來的,如果也執行這段代碼就會報錯。

去看看效果。

文章詳情頁美化

現在的文章詳情頁是沒有將markdown格式渲染出來的,這裏還是使用editor.md提供的方法,因為需要加載幾個js文件,然後才能渲染樣式。

所以還是在app.js添加一段代碼。

renderMarkdown: async function () {
    await this._loadScript('./editor.md/lib/zepto.min.js').then(function () {
        func._loadScript('./editor.md/lib/marked.min.js').then(function () {
            func._loadScript('./editor.md/lib/prettify.min.js').then(function () {
                func._loadScript('./editor.md/editormd.js').then(function () {
                    editormd.markdownToHTML("content");
                });
            });
        });
    });
},

然後在文章詳情頁的組件Post.razor中修改代碼,當數據加載完成后調用renderMarkdown即可,然後還需要引用一個css文件editormd.preview.css

提供一下Post.razor最終的代碼。

@page "/post/{year:int}/{month:int}/{day:int}/{name}"

<link href="./editor.md/css/editormd.preview.css" rel="stylesheet" />

@if (post == null)
{
    <Loading />
}
else
{
    @if (post.Success)
    {
        var _post = post.Result;

        <article class="post-wrap">
            <header class="post-header">
                <h1 class="post-title">@_post.Title</h1>
                <div class="post-meta">
                    Author: <a itemprop="author" rel="author" href="javascript:;">@_post.Author</a>
                    <span class="post-time">
                        Date: <a href="javascript:;">@_post.CreationTime</a>
                    </span>
                    <span class="post-category">
                        Category:<a href="/category/@_post.Category.DisplayName/">@_post.Category.CategoryName</a>
                    </span>
                </div>
            </header>
            <div class="post-content" id="content">
                @((MarkupString)_post.Html)
            </div>
            <section class="post-copyright">
                <p class="copyright-item">
                    <span>Author:</span>
                    <span>@_post.Author</span>
                </p>
                <p class="copyright-item">
                    <span>Permalink:</span>
                    <span><a href="/post@_post.Url">https://meowv.com/post@_post.Url</a></span>
                </p>
                <p class="copyright-item">
                    <span>License:</span>
                    <span>本文採用<a target="_blank" href="http://creativecommons.org/licenses/by-nc-nd/4.0/"> 知識共享 署名-非商業性使用-禁止演繹(CC BY-NC-ND)國際許可協議 </a>進行許可</span>
                </p>
            </section>
            <section class="post-tags">
                <div>
                    <span>Tag(s):</span>
                    <span class="tag">
                        @if (_post.Tags.Any())
                        {
                            @foreach (var tag in _post.Tags)
                            {
                                <a href="/tag/@tag.DisplayName/"># @tag.TagName</a>
                            }
                        }
                    </span>
                </div>
                <div>
                    <a @onclick="@(async () => await Common.NavigateTo("/posts"))">back</a>
                    <span>· </span>
                    <a href="/">home</a>
                </div>
            </section>
            <section class="post-nav">
                @if (_post.Previous != null)
                {
                    <a class="prev"
                       rel="prev"
                       @onclick="@(async () => await FetchData(_post.Previous.Url))"
                       href="/post@_post.Previous.Url">@_post.Previous.Title</a>
                }
                @if (_post.Next != null)
                {
                    <a class="next"
                       rel="next"
                       @onclick="@(async () => await FetchData(_post.Next.Url))"
                       href="/post@_post.Next.Url">
                        @_post.Next.Title
                    </a>
                }
            </section>
        </article>
    }
    else
    {
        <ErrorTip />
    }
}

@code {
    [Parameter]
    public int year { get; set; }

    [Parameter]
    public int month { get; set; }

    [Parameter]
    public int day { get; set; }

    [Parameter]
    public string name { get; set; }

    /// <summary>
    /// URL
    /// </summary>
    private string url => $"/{year}/{(month >= 10 ? month.ToString() : $"0{month}")}/{(day >= 10 ? day.ToString() : $"0{day}")}/{name}/";

    /// <summary>
    /// 文章詳情數據
    /// </summary>
    private ServiceResult<PostDetailDto> post;

    /// <summary>
    /// 初始化
    /// </summary>
    protected override async Task OnInitializedAsync()
    {
        await FetchData(url);
    }

    /// <summary>
    /// 請求數據,渲染頁面
    /// </summary>
    /// <param name="url"></param>
    /// <returns></returns>
    private async Task FetchData(string url, bool isPostNav = false)
    {
        post = await Http.GetFromJsonAsync<ServiceResult<PostDetailDto>>($"/blog/post?url={url}");
        await Common.InvokeAsync("window.func.renderMarkdown");
    }
}

到這裏整個開發工作便結束了,這裏只是一個小小的實戰系列記錄,沒有深層次的剖析研究Blazor的所有使用方式。

如果本系列對你有些許幫助,便是我最大的收穫,歡迎大家關注我的公眾號:阿星Plus。

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

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

聚甘新

詳說tcp粘包和半包

tcp服務端和客戶端建立連接後會長時間維持這個連接,用於互相傳遞數據,tcp是以流的方式傳輸數據的,就像一個水管里的水一樣,從一頭不斷的流向另一頭。
理想情況下,發送的數據包都是獨立的,

現實要複雜一些,發送方和接收方都有各自的緩衝區。
發送緩衝區:應用不斷的把數據發送到緩衝區,系統不斷的從緩衝區取數據發送到接收端。
接收緩衝區:系統把接收到的數據放入緩衝區,應用不斷的從緩衝區獲取數據。
當發送方快速的發送多個數據包時,每個數據包都小於緩衝區,tcp會將多次寫入的數據放入緩衝區,一次發送出去,服務器在接收到數據流無法區分哪部分數據包獨立的,這樣產生了粘包。

或者接收方因為各種原因沒有從緩衝區里讀取數據,緩衝區的數據會積壓,等再取出數據時,也是無法區分哪部分數據包獨立的,一樣會產生粘包。
發送方的數據包大於緩存區了,其中有一部分數據會在下一次發送,接收端一次接收到時的數據不是完整的數據,就會出現半包的情況。

我們可以還原一下粘包和半包,寫一個測試代碼
服務端

func main() {
	l, err := net.Listen("tcp", ":8899")
	if err != nil {
		panic(err)
	}
	fmt.Println("listen to 8899")
	for {
		conn, err := l.Accept()
		if err != nil {
			panic(err)
		} else {
			go handleConn(conn)
		}
	}
}

func handleConn(conn net.Conn) {
	defer conn.Close()
	var buf [1024]byte
	for {
		n, err := conn.Read(buf[:])
		if err != nil {
			break
		} else {
			fmt.Printf("recv: %s \n", string(buf[0:n]))
		}
	}
}

客戶端

func main() {
	data := []byte("~測試數據:一二三四五~")
	conn, err := net.Dial("tcp", ":8899")
	if err != nil {
		panic(err)
	}
	for i := 0; i < 2000; i++ {
		if _, err = conn.Write(data); err != nil {
			fmt.Printf("write failed , err : %v\n", err)
			break
		}
	}
}

查看一下輸出

recv: ~測試數據:一二三四五~
recv: ~測試數據:一二三四五~ ~測試數據:一二三四五~ 
recv: ~測試數據:一� 
recv: ��三四五~ ~測試數據:一二三四五~ 
recv: ~測試數據:一二三四五~
recv: ~測試數據:一二三四五~ ~測試數據:一二三四五~ ~測試數據:一二三四五~ ~測試數據:一二三四五~ 
recv: ~測試數據:一二三四五~

正常情況下輸出是recv: ~測試數據:一二三四五~,發生粘包的時候會輸出多個數據包,當有半包的情況下輸出的是亂碼數據,再下一次會把剩下的半包數據也輸出。
要解決也簡單的就想辦法確定數據的邊界,常見的處理方式:

  • 固定長度: 比如規定所有的數據包長度為100byte,如果不夠則補充至100長度。優點就是實現很簡單,缺點就是空間有極大的浪費,如果傳遞的消息中大部分都比較短,這樣就會有很多空間是浪費的,同樣浪費的還有流量。
  • 分隔符:用分隔符來確定數據的邊界,這樣做比較簡單也不浪費空間,但數據包內就不能包含相應的分隔符,如果有會造成錯誤的解析。
  • 數據頭:通過數據頭部來解析數據包長度,比如用4個字節來當數據頭,保存每個實數據包的長度。

個人更推薦數據頭方式來確定數據邊界,在發送和接收數據時做好規定,每個數據包是不定長的,比如4字節的包頭+真實的數據可以根據自己的業務進行擴展,比如上更多的包頭或者包尾,加上數據校驗等。
我修改一下上面的代碼:
客戶端

	data := []byte("~測試數據:一二三四五~")
	conn, err := net.Dial("tcp", ":8899")
	if err != nil {
		panic(err)
	}
	for i := 0; i < 2000; i++ {
		var buf [4]byte
		bufs := buf[:]
		binary.BigEndian.PutUint32(bufs, uint32(len(data)))
		if _, err := conn.Write(bufs); err != nil {
			fmt.Printf("write failed , err : %v\n", err)
			break
		}
		if _, err = conn.Write(data); err != nil {
			fmt.Printf("write failed , err : %v\n", err)
			break
		}
	}

服務端

func main() {
	l, err := net.Listen("tcp", ":8899")
	if err != nil {
		panic(err)
	}
	fmt.Println("listen to 8899")
	for {
		conn, err := l.Accept()
		if err != nil {
			panic(err)
		} else {
			go handleConn(conn)
		}
	}
}
func handleConn(conn net.Conn) {
	defer conn.Close()
	for {
		var msgSize int32
		err := binary.Read(conn, binary.BigEndian, &msgSize)
		if err != nil {
			break
		}
		buf := make([]byte, msgSize)
		_, err = io.ReadFull(conn, buf)
		if err != nil {
			break
		}
		fmt.Printf("recv: %s \n", string(buf))
	}
}

執行再看一下輸出,沒有粘包或者半包的情況

recv: ~測試數據:一二三四五~ 
recv: ~測試數據:一二三四五~ 
recv: ~測試數據:一二三四五~ 
recv: ~測試數據:一二三四五~ 
recv: ~測試數據:一二三四五~ 
recv: ~測試數據:一二三四五~

也可以像第一個例子一樣用一個指定大小的buf var buf [1024]byte,每次從conn里取出指定大小的數據,然後進行數據解析,如果發現有半包的情況,就再讀取一次,加上上次未解析的數據,再次重新解析。

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

【其他文章推薦】

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

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

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

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

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

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

聚甘新

tensorflow-TFRecord 文件詳解

TFRecord 是 tensorflow 內置的文件格式,它是一種二進制文件,具有以下優點:

1. 統一各種輸入文件的操作

2. 更好的利用內存,方便複製和移動

3. 將二進制數據和標籤(label)存儲在同一個文件中

 

引言

在了解如下操作後進一步詳細講解TFRecord

 

tf.train.Int64List(value=list_data)

它的作用是 把 list 中每個元素轉換成 key-value 形式,

注意,輸入必須是 list,且 list 中元素類型要相同,且與 Int 保持一致;

# value = tf.constant([1, 2])     ### 這會報錯的
ss = 1               ### Int64List 對應的元素只能是 int long,其他同理
tt = 2
out1 = tf.train.Int64List(value = [ss, tt])
print(out1)
# value: 1
# value: 2

ss = [1 ,2]
out2 = tf.train.Int64List(value = ss)
print(out2)
# value: 1
# value: 2

 

同類型的 方法還有 2 個

tf.train.FloatList
tf.train.BytesList

 

tf.train.Feature(int64_list=)

它的作用是 構建 一種類型的特徵集,比如 整型

out = tf.train.Feature(int64_list=tf.train.Int64List(value=[33, 22]))
print(out)
# int64_list {
#   value: 33
#   value: 22
# }

也可以是其他類型

tf.train.Feature(float_list=tf.train.FloatList())
tf.train.Feature(bytes_list=tf.train.BytesList())

 

tf.train.Features(feature=dict_data)

它的作用是 構建 多種類型 的特徵集,可以 dict 格式表達 多種類型

ut = tf.train.Features(feature={
                            "suibian": tf.train.Feature(int64_list=tf.train.Int64List(value=[1, 2, 4])),
                            "a": tf.train.Feature(float_list=tf.train.FloatList(value=[5., 7.]))
                        })
print(out)
# feature {
#   key: "a"
#   value {
#     float_list {
#       value: 5.0
#       value: 7.0
#     }
#   }
# }
# feature {
#   key: "suibian"
#   value {
#     int64_list {
#       value: 1
#       value: 2
#       value: 4
#     }
#   }
# }

 

tf.train.Example(features=tf.train.Features())

它的作用是創建一個 樣本,Example 對應一個樣本

example = tf.train.Example(features=
                           tf.train.Features(feature={
                               'a': tf.train.Feature(int64_list=tf.train.Int64List(value=range(2))),
                               'b': tf.train.Feature(bytes_list=tf.train.BytesList(value=[b'm',b'n']))
                           }))
print(example)
# features {
#   feature {
#     key: "a"
#     value {
#       int64_list {
#         value: 0
#         value: 1
#       }
#     }
#   }
#   feature {
#     key: "b"
#     value {
#       bytes_list {
#         value: "m"
#         value: "n"
#       }
#     }
#   }
# }

 

一幅圖總結一下上面的代碼

 

Example 協議塊

它其實是一種 數據存儲的 格式,類似於 xml、json 等;

用上述方法實現該格式;

一個 Example 協議塊對應一個樣本,一個樣本有多種特徵,每種特徵下有多個元素,可參看上圖;

message Example{
    Features features = 1;
}
message Features{
    map<string,Features> feature = 1;
}
message Feature {
    oneof kind {
        BytesList bytes_list = 1;
        FloateList float_list = 2;
        Int64List int64_list = 3;
    }
}

TFRecord 文件就是以 Example協議塊 格式 存儲的;

 

TFRecord 文件

該類文件具有寫功能,且可以把其他類型的文件轉換成該類型文件,其實相當於先讀取其他文件,再寫入 TFRecord 文件;

該類文件也具有讀功能;

 

TFRecord 存儲

存儲分兩步:

1.建立存儲器 

2. 構造每個樣本的 Example 協議塊

 

tf.python_io.TFRecordWriter(file_name)

構造存儲器,存儲器有兩個常用方法

  • write(record):向文件中寫入一個樣本
  • close():關閉存儲器

注意:此處的 record 為一個序列化的 Example,通過 Example.SerializeToString()來實現,它的作用是將 Example 中的 map 壓縮為二進制,節約大量空間

 

示例代碼1:將 MNIST 數據集保存成 TFRecord 文件

import tensorflow as tf
import numpy as np
import input_data


# 生成整數型的屬性
def _int64_feature(value):
    return tf.train.Feature(int64_list = tf.train.Int64List(value = [value]))

# 生成字符串類型的屬性,也就是圖像的內容
def _string_feature(value):
    return tf.train.Feature(bytes_list = tf.train.BytesList(value = [value]))

# 讀取圖像數據 和一些屬性
mniset = input_data.read_data_sets('../../../data/MNIST_data',dtype=tf.uint8, one_hot=True)
images = mniset.train.images
labels = mniset.train.labels
pixels = images.shape[1]        # (55000, 784)
num_examples = mniset.train.num_examples        # 55000

file_name = 'output.tfrecords'          ### 文件名
writer = tf.python_io.TFRecordWriter(file_name)     ### 寫入器

for index in range(num_examples):
    ### 遍歷樣本
    image_raw = images[index].tostring()        ### 圖片轉成 字符型
    example = tf.train.Example(features = tf.train.Features(feature = {
        'pixel': _int64_feature(pixels),
        'label': _int64_feature(np.argmax(labels[index])),
        'image_raw': _string_feature(image_raw)
    }))
    writer.write(example.SerializeToString())       ### 寫入 TFRecord
writer.close()

 

示例代碼2:將 csv 保存成 TFRecord 文件

train_frame = pd.read_csv("../myfiles/xx3.csv")
train_labels_frame = train_frame.pop(item="label")
train_values = train_frame.values
train_labels = train_labels_frame.values
print("values shape: ", train_values.shape)     # values shape:  (2, 3)
print("labels shape:", train_labels.shape)      # labels shape: (2,)

writer = tf.python_io.TFRecordWriter("xx3.tfrecords")

for i in range(train_values.shape[0]):
    image_raw = train_values[i].tostring()
    example = tf.train.Example(
        features=tf.train.Features(
            feature={
                "image_raw": tf.train.Feature(bytes_list=tf.train.BytesList(value=[image_raw])),
                "label": tf.train.Feature(int64_list=tf.train.Int64List(value=[train_labels[i]]))
            }
        )
    )
    writer.write(record=example.SerializeToString())
writer.close()

 

示例3:將 png 文件保存成 TFRecord 文件

# filenames = tf.train.match_filenames_once('../myfiles/*.png')
filenames = glob.iglob('..\myfiles\*.png')

writer = tf.python_io.TFRecordWriter('png.tfrecords')

for filename in filenames:
    img = Image.open(filename)
    img_raw = img.tobytes()
    label = 1
    example = tf.train.Example(
        features=tf.train.Features(
            feature={
                "image_raw": tf.train.Feature(bytes_list=tf.train.BytesList(value=[img_raw])),
                "label": tf.train.Feature(int64_list=tf.train.Int64List(value=[label]))
            }
        )
    )
    writer.write(record=example.SerializeToString())
writer.close()

 

TFRecord 讀取

參考鏈接:https://www.cnblogs.com/nbk-zyc/p/13159986.html(案例6)、https://www.cnblogs.com/nbk-zyc/p/13168313.html

 

tf.TFRecordReader()

建立讀取器,有 read 和 close 方法

tf.parse_single_example(serialized,features=None,name= None)

解析單個 Example 協議塊

  • serialized : 標量字符串的Tensor,一個序列化的Example,文件經過文件閱讀器之後的value
  • features :字典數據,key為讀取的名字,value為FixedLenFeature
  • return : 一個鍵值對組成的字典,鍵為讀取的名字

features中的value還可以為tf.VarLenFeature(),但是這種方式用的比較少,它返回的是SparseTensor數據,這是一種只存儲非零部分的數據格式,了解即可。

tf.FixedLenFeature(shape,dtype)

  • shape : 輸入數據的形狀,一般不指定,為空列表
  • dtype : 輸入數據類型,與存儲進文件的類型要一致,類型只能是float32,int 64, string
  • return : 返回一個定長的 Tensor (即使有零的部分也存儲)

 

示例代碼

filename = 'png.tfrecords'
file_queue = tf.train.string_input_producer([filename], shuffle=True)

reader = tf.TFRecordReader()
key, value = reader.read(file_queue)

### features 的 key 必須和 寫入時 一致,數據類型也必須一致,shape 可為 空
dict_data= tf.parse_single_example(value, features={'label': tf.FixedLenFeature(shape=(1,1), dtype=tf.int64),
                                                        'image_raw': tf.FixedLenFeature(shape=(), dtype=tf.string)})
label = tf.cast(dict_data['label'], tf.int32)
img = tf.decode_raw(dict_data['image_raw'], tf.uint8)       ### 將 string、bytes 轉換成 int、float

image_tensor = tf.reshape(img, [500, 500, -1])

sess = tf.Session()
sess.run(tf.local_variables_initializer())
tf.train.start_queue_runners(sess=sess)

while 1:
    # print(sess.run(key))        # b'png.tfrecords:0'
    image = sess.run(image_tensor)
    img_PIL = Image.fromarray(image)
    img_PIL.show()

 

參考資料:

https://blog.csdn.net/chengshuhao1991/article/details/78656724

https://www.cnblogs.com/yanshw/articles/12419616.html

,

TFRecord 是 tensorflow 內置的文件格式,它是一種二進制文件,具有以下優點:

1. 統一各種輸入文件的操作

2. 更好的利用內存,方便複製和移動

3. 將二進制數據和標籤(label)存儲在同一個文件中

 

引言

在了解如下操作後進一步詳細講解TFRecord

 

tf.train.Int64List(value=list_data)

它的作用是 把 list 中每個元素轉換成 key-value 形式,

注意,輸入必須是 list,且 list 中元素類型要相同,且與 Int 保持一致;

# value = tf.constant([1, 2])     ### 這會報錯的
ss = 1               ### Int64List 對應的元素只能是 int long,其他同理
tt = 2
out1 = tf.train.Int64List(value = [ss, tt])
print(out1)
# value: 1
# value: 2

ss = [1 ,2]
out2 = tf.train.Int64List(value = ss)
print(out2)
# value: 1
# value: 2

 

同類型的 方法還有 2 個

tf.train.FloatList
tf.train.BytesList

 

tf.train.Feature(int64_list=)

它的作用是 構建 一種類型的特徵集,比如 整型

out = tf.train.Feature(int64_list=tf.train.Int64List(value=[33, 22]))
print(out)
# int64_list {
#   value: 33
#   value: 22
# }

也可以是其他類型

tf.train.Feature(float_list=tf.train.FloatList())
tf.train.Feature(bytes_list=tf.train.BytesList())

 

tf.train.Features(feature=dict_data)

它的作用是 構建 多種類型 的特徵集,可以 dict 格式表達 多種類型

ut = tf.train.Features(feature={
                            "suibian": tf.train.Feature(int64_list=tf.train.Int64List(value=[1, 2, 4])),
                            "a": tf.train.Feature(float_list=tf.train.FloatList(value=[5., 7.]))
                        })
print(out)
# feature {
#   key: "a"
#   value {
#     float_list {
#       value: 5.0
#       value: 7.0
#     }
#   }
# }
# feature {
#   key: "suibian"
#   value {
#     int64_list {
#       value: 1
#       value: 2
#       value: 4
#     }
#   }
# }

 

tf.train.Example(features=tf.train.Features())

它的作用是創建一個 樣本,Example 對應一個樣本

example = tf.train.Example(features=
                           tf.train.Features(feature={
                               'a': tf.train.Feature(int64_list=tf.train.Int64List(value=range(2))),
                               'b': tf.train.Feature(bytes_list=tf.train.BytesList(value=[b'm',b'n']))
                           }))
print(example)
# features {
#   feature {
#     key: "a"
#     value {
#       int64_list {
#         value: 0
#         value: 1
#       }
#     }
#   }
#   feature {
#     key: "b"
#     value {
#       bytes_list {
#         value: "m"
#         value: "n"
#       }
#     }
#   }
# }

 

一幅圖總結一下上面的代碼

 

Example 協議塊

它其實是一種 數據存儲的 格式,類似於 xml、json 等;

用上述方法實現該格式;

一個 Example 協議塊對應一個樣本,一個樣本有多種特徵,每種特徵下有多個元素,可參看上圖;

message Example{
    Features features = 1;
}
message Features{
    map<string,Features> feature = 1;
}
message Feature {
    oneof kind {
        BytesList bytes_list = 1;
        FloateList float_list = 2;
        Int64List int64_list = 3;
    }
}

TFRecord 文件就是以 Example協議塊 格式 存儲的;

 

TFRecord 文件

該類文件具有寫功能,且可以把其他類型的文件轉換成該類型文件,其實相當於先讀取其他文件,再寫入 TFRecord 文件;

該類文件也具有讀功能;

 

TFRecord 存儲

存儲分兩步:

1.建立存儲器 

2. 構造每個樣本的 Example 協議塊

 

tf.python_io.TFRecordWriter(file_name)

構造存儲器,存儲器有兩個常用方法

  • write(record):向文件中寫入一個樣本
  • close():關閉存儲器

注意:此處的 record 為一個序列化的 Example,通過 Example.SerializeToString()來實現,它的作用是將 Example 中的 map 壓縮為二進制,節約大量空間

 

示例代碼1:將 MNIST 數據集保存成 TFRecord 文件

import tensorflow as tf
import numpy as np
import input_data


# 生成整數型的屬性
def _int64_feature(value):
    return tf.train.Feature(int64_list = tf.train.Int64List(value = [value]))

# 生成字符串類型的屬性,也就是圖像的內容
def _string_feature(value):
    return tf.train.Feature(bytes_list = tf.train.BytesList(value = [value]))

# 讀取圖像數據 和一些屬性
mniset = input_data.read_data_sets('../../../data/MNIST_data',dtype=tf.uint8, one_hot=True)
images = mniset.train.images
labels = mniset.train.labels
pixels = images.shape[1]        # (55000, 784)
num_examples = mniset.train.num_examples        # 55000

file_name = 'output.tfrecords'          ### 文件名
writer = tf.python_io.TFRecordWriter(file_name)     ### 寫入器

for index in range(num_examples):
    ### 遍歷樣本
    image_raw = images[index].tostring()        ### 圖片轉成 字符型
    example = tf.train.Example(features = tf.train.Features(feature = {
        'pixel': _int64_feature(pixels),
        'label': _int64_feature(np.argmax(labels[index])),
        'image_raw': _string_feature(image_raw)
    }))
    writer.write(example.SerializeToString())       ### 寫入 TFRecord
writer.close()

 

示例代碼2:將 csv 保存成 TFRecord 文件

train_frame = pd.read_csv("../myfiles/xx3.csv")
train_labels_frame = train_frame.pop(item="label")
train_values = train_frame.values
train_labels = train_labels_frame.values
print("values shape: ", train_values.shape)     # values shape:  (2, 3)
print("labels shape:", train_labels.shape)      # labels shape: (2,)

writer = tf.python_io.TFRecordWriter("xx3.tfrecords")

for i in range(train_values.shape[0]):
    image_raw = train_values[i].tostring()
    example = tf.train.Example(
        features=tf.train.Features(
            feature={
                "image_raw": tf.train.Feature(bytes_list=tf.train.BytesList(value=[image_raw])),
                "label": tf.train.Feature(int64_list=tf.train.Int64List(value=[train_labels[i]]))
            }
        )
    )
    writer.write(record=example.SerializeToString())
writer.close()

 

示例3:將 png 文件保存成 TFRecord 文件

# filenames = tf.train.match_filenames_once('../myfiles/*.png')
filenames = glob.iglob('..\myfiles\*.png')

writer = tf.python_io.TFRecordWriter('png.tfrecords')

for filename in filenames:
    img = Image.open(filename)
    img_raw = img.tobytes()
    label = 1
    example = tf.train.Example(
        features=tf.train.Features(
            feature={
                "image_raw": tf.train.Feature(bytes_list=tf.train.BytesList(value=[img_raw])),
                "label": tf.train.Feature(int64_list=tf.train.Int64List(value=[label]))
            }
        )
    )
    writer.write(record=example.SerializeToString())
writer.close()

 

TFRecord 讀取

參考鏈接:https://www.cnblogs.com/nbk-zyc/p/13159986.html(案例6)、https://www.cnblogs.com/nbk-zyc/p/13168313.html

 

tf.TFRecordReader()

建立讀取器,有 read 和 close 方法

tf.parse_single_example(serialized,features=None,name= None)

解析單個 Example 協議塊

  • serialized : 標量字符串的Tensor,一個序列化的Example,文件經過文件閱讀器之後的value
  • features :字典數據,key為讀取的名字,value為FixedLenFeature
  • return : 一個鍵值對組成的字典,鍵為讀取的名字

features中的value還可以為tf.VarLenFeature(),但是這種方式用的比較少,它返回的是SparseTensor數據,這是一種只存儲非零部分的數據格式,了解即可。

tf.FixedLenFeature(shape,dtype)

  • shape : 輸入數據的形狀,一般不指定,為空列表
  • dtype : 輸入數據類型,與存儲進文件的類型要一致,類型只能是float32,int 64, string
  • return : 返回一個定長的 Tensor (即使有零的部分也存儲)

 

示例代碼

filename = 'png.tfrecords'
file_queue = tf.train.string_input_producer([filename], shuffle=True)

reader = tf.TFRecordReader()
key, value = reader.read(file_queue)

### features 的 key 必須和 寫入時 一致,數據類型也必須一致,shape 可為 空
dict_data= tf.parse_single_example(value, features={'label': tf.FixedLenFeature(shape=(1,1), dtype=tf.int64),
                                                        'image_raw': tf.FixedLenFeature(shape=(), dtype=tf.string)})
label = tf.cast(dict_data['label'], tf.int32)
img = tf.decode_raw(dict_data['image_raw'], tf.uint8)       ### 將 string、bytes 轉換成 int、float

image_tensor = tf.reshape(img, [500, 500, -1])

sess = tf.Session()
sess.run(tf.local_variables_initializer())
tf.train.start_queue_runners(sess=sess)

while 1:
    # print(sess.run(key))        # b'png.tfrecords:0'
    image = sess.run(image_tensor)
    img_PIL = Image.fromarray(image)
    img_PIL.show()

 

參考資料:

https://blog.csdn.net/chengshuhao1991/article/details/78656724

https://www.cnblogs.com/yanshw/articles/12419616.html

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

【其他文章推薦】

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

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

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

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

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

聚甘新

為什麼Web開發人員在2020年不用最新的CSS功能

轉載請註明出處:葡萄城官網,葡萄城為開發者提供專業的開發工具、解決方案和服務,賦能開發者。

原文出處:https://dzone.com/articles/why-masses-are-not-using-latest-css-features-in-20

 

儘管CSS每年都會發布全新的特性,但實際上這些新功能很少會被web開發人員實際在生產項目中使用到,甚至去了解它們的動力也不會比去多完成幾個需求更多。那究竟是什麼原因導致的呢? 

1.使用最新特性不是優先事項

在一個新項目的初期階段,它用到的可能只是幾條CSS規則,但隨着項目的持續更新和迭代,項目中使用到的規則就會變得越來越複雜,CSS也會越來越複雜尺寸也會隨之不斷膨脹。因此,作為項目優化的第一要務,作為資源的CSS需要盡可能的精簡和減少複雜度,第一是為了便於更好地理解和維護,第二也是為了加載更為高效。那麼,更實用且可投入生產環境的一些CSS特性會被高頻使用,其他的特性則會被暫時擱置一旁。

並且,在一般情況下,樣式和品牌在一段時間內都會相對固定,完成任務的需求要比使用最新CSS的特性要更緊迫。 

 

 

(圖片來源於網絡)

 

2.預算限制

預算成本是影響了所有項目的主要因素。它在開發階段會高度影響事項的優先級。集成新的CSS功能需要時間,而開發團隊來說,增加的這部分時間成本會影響到項目的整體進度。因此,開發進度會重視在優化其他功能(而不是CSS功能)時花費的時間成本。

另外,引入了最新的CSS特性,還可能會使開發團隊把一部分精力放在解決瀏覽器兼容性問題上。這點和JavaScript不同,JavaScript有Babel來完成編譯,而CSS沒有提供類似功能。

 

 

 (圖片來源於網絡)

 

3.社區發展還未跟上

JavaScript每隔一段時間舉行一次會議。同樣,Vue和React也會為了幫助開發人員跟上社區的步伐而定期舉行會議。但是,對於CSS而言,它們根本沒有這樣的活動!因此,開發人員很難掌握其功能和路線圖。他們應該如何保持對新功能發展趨勢的了解? 沒有版本發布說明,也沒有定期的發布會,這根本不能點燃社區用戶的學習激情。 

對普通用戶而言,既然舊的技術已經滿足了需求,那麼又何必那麼麻煩閱讀文檔學習新的功能呢?

和框架和其他編程語言不同,CSS沒有針對安全問題的補丁程序。他只是一套標準,反正大多數客戶只需要關心網站看起來UI差不多就行了。

4.很難提升簡歷的含金量

即使你在掌握CSS方面付出了很多的努力,對CSS的新特性也了如指掌,但你也很難向你的客戶或老闆證明這一點,因為類似像這樣“熟練掌握CSS3以外的CSS特性”對他人而講是沒有意義的,因為它不是CSS3。在CSS開發領域,CSS3的出現是很有意義的,因為它完成了前端領域的統一:

  • Web開發人員提升了技能
  • 加速瀏覽器廠商統一支持了全新的CSS標準
  • 企業的技術棧更新

巨大的需求帶來了巨大的機會。除了大量的書籍、課程和視頻來幫助人們了解CSS3外,還催生了全新的布局模型,如Flexbox和Grid,儘管它們不是CSS3的一部分。

但這裏我們指的是CSS3外的特性,它們本身除了認可程度很低外,對開發團隊來講也是個相對不熟悉的東西,因此,開發團隊很難會把時間花在對市場沒有意義的事情上,客戶也不會關心你到底用不用新的技術。

5.缺乏時間

編寫CSS的主要目的是使你的網站的表現內容的形式更美觀及易於理解。CSS通過控制兩類事物來幫助開發人員去實現這個目標:布局和設計。布局(Layout)負責元素列和行排布,而設計(design)指顏色、字體、間距、動畫和邊框等基礎外觀。

但目前,舊的特性已經能處理的很好了,為什麼要花更多時間去使用新特性去替代已經很好的形式呢?

總結

CSS發布周期沒有固定的周期和計劃,導致一切都來的很突然 ,另外舊的CSS特性已經能很好的完成日常工作了,這讓很多Web開發人員沒有特別的動力去升級它們。

另外,新的特性知名度也不高,對最終用戶的吸引力也不足,很難從需求層面驅動使用。所以這就是為什麼都2020年了,CSS的新特性仍然使用的人較少的原因。

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

【其他文章推薦】

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

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

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

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

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

聚甘新

.NET Framework、.NET Core 和 .NET 5+ 的產品生命周期

.NET Framework、.NET Core 和 .NET 5+ 的產品生命周期

本文整理記錄了 .NET Framework、.NET Core 和 .NET 各個版本的產品支持周期和操作系統兼容性。

早於 .NET Framework 2.0 和 .NET Core 2.1 的 .NET 版本以及 .NET Core 2.2、.NET Core 3.0 已經停止了任何形式的支持,因此本文不做討論。

相關文章:

  • .NET Framework、.NET Core 和 .NET 5+ 的產品生命周期(本文)
  • Visual Studio 的產品生命周期
  • DevExpress 各個版本與 .NET、Visual Studio 的版本兼容性

.NET 版本說明

  • .NET Framework 4.5 是可替換計算機上的 .NET Framework 4 的就地更新,同樣,.NET Framework 4.5.1、4.5.2、4.6、4.6.1、4.6.2、4.7、4.7.1、4.7.2 和 4.8 是對 .NET Framework 4.5 的就地更新。 就地更新意味着它們使用相同的運行時版本,但是程序集版本會更新,並且包括新類型和成員。 安裝其中一個更新后,.NET Framework 4、.NET Framework 4.5、.NET Framework 4.6 或 .NET Framework 4.7 應用應繼續運行,而無需重新編譯。 但是,反過來則不行。 建議不要在較早版本的 .NET Framework 上運行面向更高版本的 .NET Framework 的應用。 例如,建議在 .NET Framework 4.5 上運行面向 .NET Framework 4.6 的應用。(參見 版本 4.5 及更高版本的備註)

  • .NET Core 為一個全新的跨平台框架,支持 Windows、Linux 和 macOS 等多種平台,以 MIT 協議完全開源。.NET Core 最早於 2014 年公布,首個版本 .NET Core 1.0 發佈於 2016 年。隨着版本的演進,.NET Core 不斷加入 .NET Framework 原有的功能,直到 .NET Core 3.1,完成這一進程。剩餘少量 .NET Core 不支持的 .NET Framework 技術 不再向 .NET Core 移植。

  • .NET Core 3.1 之後,隨着技術移植進程的結束,.NET Core 的後續版本將作為 .NET Framework 和 .NET Core 的繼任者,移除 “Core” 字樣直接稱作 “.NET”,版本號自 “.NET 5” 開始。因此,.NET Framework 4.8 將會是 .NET Framework 的最後一個版本。

.NET 支持政策

.NET Core 和 .NET 的版本類型

本節整理自 .NET Core 支持政策。

.NET Core/.NET 分為長期支持 (LTS) 版本和最新 (Current) 版本。自 .NET Core 2.2 起,兩者的支持周期如下:

  • LTS (Long Term Support): 在初始發布后的三年內受支持。
  • Current:在初始發布后,直到下一個 Current 或 LTS 版本發布后的三個月內受支持。

.NET Core 和 .NET 發布節奏

本節整理自 .NET 5 簡介

  • 自 2020 年起,每年 11 月為 .NET 發布新的主要版本,版本號自 5.0 起遞增。即 2020 年 11 月發布 .NET 5.0,2021 年 11 月發布 .NET 6.0,以此類推。

  • 自 2021 年起,將隔年發布的主要版本標記為 LTS 版本(即偶數的主要版本為 LTS 版本,奇數的為 Current 版本)。

.NET Core 和 .NET 生命周期詳情

本節整理自 .NET 5 簡介 以及 .NET Core 支持政策,僅列出了生命周期尚未結束的版本。

版本 初始發布時間 支持級別 結束支持時間
.NET 8 2023 年 11 月(預計) LTS 2025 年 11 月(預計)
.NET 7 2022 年 11 月(預計) Current 2023 年 2 月(預計)
.NET 6 2021 年 11 月(預計) LTS 2024 年 11 月(預計)
.NET 5 2020 年 11 月(預計) Current 2022 年 2 月(預計)
.NET Core 3.1 2019 年 12 月 3 日 LTS 2022 年 12 月 3 日
.NET Core 2.1 2018 年 5 月 30 日 LTS 2021 年 8 月 21 日

.NET Framework 各版本支持政策

本節內容整理自 .NET Framework 生命周期常見問題。

  • .NET Framework 4.5.2 及以上版本被定義為 Windows 操作系統的一個組件,與其父產品獲得相同的生命周期,詳見下節內容。

  • .NET Framework 4、4.5 和 4.5.1 已於 2016 年 1 月 12 日停止支持,客戶和開發人員必須就地更新到 .NET Framework 4.5.2 及以上版本,才能技術獲得技術支持和安全更新。

  • .NET Framework 3.5 SP1 在 Windows 10 v1809 和 Windows Server 2019 及以上版本中作為獨立的產品存在,自 2018 年 10 月 2 日起獲得 5 年主流支持和 5 年擴展支持。

  • .NET Framework 3.5 SP1 在 Windows 10 v1809 和 Windows Server 2019 以前的操作系統中,作為操作系統的組件存在,其生命周期與其父產品相同。

  • .NET Framework 2.0、3.0 和 3.5 已先後停止支持,客戶和開發人員可就地更新到 .NET Framework 3.5 SP1,以便在後者的生命周期內獲得技術支持和安全更新。由於 .NET Framework 3.5 依賴於 2.0 以及 3.0,因此 .NET Framework 2.0 SP2 和 .NET Framework 3.0 SP2 組件在安裝了 .NET Framework 3.5 SP1 環境當中得到支持。

.NET Framework 版本和操作系統版本的關係

本節內容整理自 .NET Framework 版本和依賴關係 以及 .NET Framework 系統需求。

  • .NET Framework 4.5 預裝在了 Windows 8 和 Windows Server 2012 中。此後,每個版本的 Windows 操作系統都包含了特定版本的 .NET Framework 4.x。

  • .NET Framework 4.8 預裝在了 Windows 10 v1903 (build 18362) 及以上版本中。

  • .NET Framework 4.6.1 及以上版本可以安裝在 Windows 7 和 Windows Server 2008 R2 SP1 及以上版本的 Windows 操作系統中,但不可以安裝低於預裝於操作系統中的版本。

  • .NET Framework 4.6 為 Windows Vista 和 Windows 2008 SP2 支持的最高版本。

  • .NET Framework 4.0.3 為 Windows XP 和 Windows Server 2003 支持的最高版本。(參見 在 Windows XP 和 Windows Server 2003 上安裝 .NET Framework)

    注意:.NET Framework 4、.NET Framework 4.0.3 和 Windows XP、Windows Server 2003 已經停止支持,不會再接收任何形式的安全更新。

  • .NET Framework 3.5 SP1 在 Windows XP 和 Windows Server 2013 及以上版本的 Windows 操作系統中,可以使用 安裝程序 進行安裝。

  • .NET Framework 3.5 SP1 在 Windows 10,Window Server 2016 和 Windows Server 2019 中可以通過控制面板直接啟用。

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

【其他文章推薦】

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

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

※超省錢租車方案

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

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

聚甘新

福斯汽車、SMA Solar傳聯手發展電動車

福斯汽車(Volkswagen)深陷柴油車排氣造假案使得品牌形象受重創,為了早點擺脫「柴油門」陰影,轉移消費者的眼光,福斯近來大力推動電動車,雄心勃勃的發展電動車的同時,傳出找來德國逆變器大廠SMA Solar 結盟。

SMA Solar 成立於1981 年,公司名來自「系統、測量、系統工程」(System, Mess and Anlagentechnik)德文簡寫,為全球最大逆變器廠,逆變器應用於直流電交流電轉換,不僅應用於太陽能,也應用於電池能源儲存系統,SMA Solar 市場地位穩固,特斯拉(Tesla)於2016 年5 月宣布Powerwall 將進行小規模規格提升,其重點之一就是改為可支援SMA Solar 產品。

福斯在「柴油門」事件後,積極將事業目標轉向電動車,以便洗刷受到作假事件影響的聲譽,投注數十億歐元資金,大力發展零碳排放的純電動車以及隨選共乘服務,計劃在2025 年以前推出30 款電動車,攻佔四分之一的全球電動車市場。

但是分析師指出,福斯在2015 年只不過出貨6.7 萬輛電動車與油電混合車,以這樣的市佔與進度,要在2025 年攻佔四分之一電動車市場的目標可能很難達成,尤其是競爭對手早已起步,為了追上豐田(Toyota)與雷諾(Renault)日產(Nissan)聯盟,福斯需要找尋強大的合作夥伴。

德國地方日報《黑森下薩克森大眾報》(Hessische Niedersaechsische Allgemeine)於2016 年8 月初報導,福斯尋求能源儲存與綠能大廠SMA Solar 的合作。

福斯的電動車廠表示,SMA Solar 在靜態能源儲存領域相當強勢,對福斯來說,尋求正確的合作夥伴,將是發展電動車的重要關鍵。不過,SMA Solar 目前已經與賓士製造商戴姆勒(Daimler)以及特斯拉在能源儲存方面合作,目前對於福斯的可能合作消息不表示意見。

(本文授權自《》──〈〉。照片來源:)

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

【其他文章推薦】

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

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

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

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

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

聚甘新

IEA:今之電動車有如10年前的太陽能

英國金融時報31日報導,瑞銀(UBS)預估2021年歐洲未經補貼的純電動車整體持有成本將與傳統內燃機汽車相當、中國也可望在2025年達到這項里程碑,美國則因油價相對低廉、在可預見的未來都無法看到。國際能源署(IEA)首席經濟學家Laszlo Varro指出,電動車目前對商品(原油)市場的影響力大約就像是10年前的太陽能一樣。他說,太陽能現在已是一個規模達數百億美元的市場、擁有龐大的影響力。Varro提到,電動車需達5千萬至1億台的規模、才能取代相當於100萬桶的石油日消費量。

IEA數據顯示,2009年全球40個國家合計僅有不到6千台的電動車、去年已升至120萬台。麥格理集團全球能源策略師Vikas Dwivedi指出,沙烏地阿拉伯對電動車的長期發展存有戒心,這可能就是它為何宣布將讓沙烏地阿拉伯國家石油公司(Saudi Aramco)初次公開發行(IPO)的原因之一。

CNNMoney去年底報導,石油輸出國組織(OPEC)發表的年度「世界石油展望(World Oil Outlook)」報告顯示,2040年高達94%的使用中車輛仍將是依靠石油燃料。OPEC報告顯示,除非出現重大技術性突破,否則在可預見的未來電動車將難以大幅取得市佔率。油國組織預估2040年僅有1%的車輛銷售量是來自純電動車款。

華爾街日報6月報導,根據能源咨詢公司Wood Mackenzie發布的報告,未來20年電動車的普及可能會導致美國汽油需求縮減5-20%。美國目前平均每天的汽油使用量超過900萬桶。報告顯示,如果電動車2035年市占比重因特斯拉(Tesla)等廠商開始推出較低價車款以及續航力和便利性(註:目前大約每100英里就得充電一次)顯著突破而站上35%,美國日需求量可能會減少200萬桶。

即便電動車現在還沒有茁壯到可以侵蝕汽油需求的地步,美國依舊面臨油品供給過剩的問題。

美國石油協會(API)8月18日公布,2016年7月衡量消費者汽油需求的指標(汽油交運量)創下史上最高紀錄、日均量接近970萬桶。美國7月汽油日均產量同樣創下歷史新高、年增1.9%(月增1.3%)至1,020萬桶!

能源情報署(EIA)公布,截至2016年8月19日為止當週美國商用汽油庫存報2.327億桶、較去年同期高出8.5%。EIA公布的數據顯示,美國一般汽油每加侖零售均價8月22日報2.193美元,較一年前短少0.444美元。

(本文內容由授權提供)

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

【其他文章推薦】

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

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

※超省錢租車方案

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

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

聚甘新

cute-cnblogs 自定義博客園樣式美化二期來啦~

cute-cnblogs 自定義博客園樣式美化二期來啦~

說明

cute-cnblogs 可愛的博客園樣式美化、自定義博客園樣式 二期樣式已經編寫完畢了,如果說 一期樣式 給人的感覺是簡潔清爽的小嬰兒的話,那麼 二期樣式 就是一個有自己小個性(花樣)的小朋友了~

與一期一樣,需要文件的可以來 github ,喜歡我寫的樣式可以幫我點個 star 喔 ღゝ◡╹)ノ

(PS:有什麼問題也可以留言到 github issues 中喔~)

好了,讓我們擼起袖子開始更換二期樣式吧~

博客示例

ღゝ◡╹)ノ 麋鹿魯喲的博客園

介紹

可愛的博客園樣式美化、自定義博客園樣式 ღゝ◡╹)ノ

  • 本樣式以簡約可愛為核心,美化博客園的显示效果,增加自定義導航;
  • 基於博客園主題“Custom”進行的樣式修改;
  • 閱讀目錄導航;
  • 支持響應式;

功能

一期功能

  • 頂部背景點點動效隨鼠標而動
  • 導航欄自定義
  • 頁面詩意詩句模塊
  • 看板娘-貓(ฅ´ω`ฅ) (自行決定是否添加,因為這個有些影響加載速度)
  • 音樂-網易雲 (自行決定是否添加)
  • 上弔的貓(PS:回到頂部)(已用其餘按鈕代替此功能)
  • 底部跳動的魚<・)))><<
  • 點擊頁面跳動的小豆子及可愛的文字(自行決定是否添加可愛文字的點擊)
  • 評論增加OωO聊天表情
  • 頁面不同的導航背景及人物背景

二期增加功能

  • 側邊欄显示
  • 側邊欄公告欄及個人信息显示
  • 閱讀目錄(標題 h1 > h2 > h3 寫了三級目錄)
  • ️ 主題皮膚切換(淺白、暗黑、閱讀)
  • 仿主播點贊功能點擊推薦
  • ️ 讚賞模塊功能

模版選定

博客皮膚選定: 博客園 Custom 標準模板(與一期不同喔)

使用方法

基本操作

請按照順序進行操作喔~

  • 首先記得申請JS權限

  • 其次博客皮膚選擇 Custom

  • 在此需要獲取數據(不然點擊頭像的關注會失敗)
    找一個沒有登陸的瀏覽器訪問自己的博客園,F12彈出窗口,找到 +加關注,複製follow括號里的內容,暫且先存在一個地方

  • 勾選禁用模板默認CSS

  • 創建一個新隨筆(這裏使用選項中的TinyMCE(推薦)來編寫的) —— “友鏈”;(注意,此處已與一期不同)
  • 點擊 “編輯 HTML 源代碼” 插入以下代碼,修改自己的文本內容后,點擊更新;
  • 只勾選 高級選項中的 “發布”、“允許評論”;
<p style="text-align: center;">歡迎來到我的友鏈小屋</p>
<div class="friendsbox">
<div id="app">
<h6 style="text-align: center; color: #2daebf;">展示本站所有友情站點,排列不分先後,均勻打亂算法隨機渲染的喔!</h6>
<div class="unionbox-box" style="display: flex; flex-wrap: wrap; justify-content: space-between; margin-bottom: 1.5rem; margin-top: 1.5rem;">&nbsp;</div>
<hr style="position: relative; margin: 1rem 0; border: 1px dashed #9eabb3; width: calc(100%); height: 0;" />
<h2 style="text-align: center;">友鏈信息</h2>
<h5 style="text-align: left; line-height: 30px;">博客名稱:<a href="javascript:void(0)">麋鹿魯喲</a><br />博客網址:<a href="javascript:void(0)">https://www.cnblogs.com/miluluyo/</a><br />博客頭像:<a href="javascript:void(0)">https://pic.cnblogs.com/avatar/1273193/20190806180831.png</a><br />博客介紹:<a href="javascript:void(0)">大道至簡,知易行難。</a></h5>
<h2 style="text-align: center;">join us</h2>
<h5 style="text-align: center; color: #2daebf;">如需友鏈,請添加微信(s978761)告知,格式如下</h5>
<table class="table friendstable" style="margin: 0 auto;">
<tbody>
<tr><th><strong>字段</strong></th><th><strong>字義</strong></th></tr>

</tbody>

</table>

</div>

</div>

  • 最後分別複製以下區域代碼,並根據參數更改數據(PS:路徑可進行更改也可不更改,我覺得更改后速度會快一點,自行down文件上傳到博客園文件中,並更改引入路徑,文件都在 github 中,喜歡記得給我個star喔~)

頁面定製CSS代碼

複製 https://blog-static.cnblogs.com/files/miluluyo/cute-cnblogs2.css 的文件內容放到 頁面定製CSS代碼 區域

博客側邊欄公告

<link href="https://blog-static.cnblogs.com/files/miluluyo/tippy.min.css" rel="stylesheet">
<script src="https://blog-static.cnblogs.com/files/miluluyo/jquery2.min.js"></script>
<script src="https://blog-static.cnblogs.com/files/miluluyo/tippy.js"></script>
<script src="https://blog-static.cnblogs.com/files/miluluyo/milusidebar.js"></script>

<script>
milusidebar({
	'names' : '麋鹿魯喲',/*你的博客園名吶*/
	'notice' : '<b>溫馨提示</b><span><a href="https://github.com/miluluyo/cute-cnblogs" target="_black">cute-cnblogs</a> &nbsp;樣式已開源</span><b style="margin-top: 3px;"><a style="font-size:10px" href="https://www.cnblogs.com/IsAlpaca/" target="_black">查看一期樣式</a></b>',/*裏面文字自己可以更改喔*/
	'headerUrl' : 'https://images.cnblogs.com/cnblogs_com/miluluyo/1765646/o_200519075219notice5.png',/*這個是公告欄的背景圖啦,我覺得這個可愛,如果你有更好看的可以自行更改喔*/
	'follow' : 'a1e76459-101d-47af-a8b6-08d523685c8c', /*還記的開始讓你複製follow括號里的內容嗎,對,就放到這裏就好啦*/
	'sidebarInfo' : [[
	      {'icon':'#icon-github1','url':'https://github.com/miluluyo','title':'github'},
	      {'icon':'#icon-weixin','url':'','title':'微信','classname':'popper_weixin','click':false},
	      {'icon':'#icon-QQ','url':'http://wpa.qq.com/msgrd?v=3&uin=978761587&site=qq&menu=yes','title':'QQ'},
	      {'icon':'#icon-juejin','url':'https://juejin.im/user/5d18adce5188256e98090e33','title':'掘金'}
	  ],[
	      {'icon':'#icon-weibobangding','url':'https://www.weibo.com/6001406082/profile?topnav=1&wvr=6','title':'微博'},
	      {'icon':'#icon-csdn','url':'https://blog.csdn.net/qq_39394518','title':'CSDN'},
	      {'icon':'#icon-bilibili','url':'https://space.bilibili.com/100007925','title':'bilibili'},
	      {'icon':'#icon-yuquemianlogo','url':'https://www.yuque.com/miluluyo','title':'語雀'}
	]],/*這個模塊是個人信息內那些小圖標們,別忘記更改喔,具體參數,可以參考下面的表格喔*/
	'signature':'靡不有初  鮮克有終',/*來一句你自己喜歡的句子吧*/
	'popper_weixin':'<div class="popper_box"><p><b>很高興認識你鴨~  (づ。◕ᴗᴗ◕。)づ</b> </p><div class="popper_box_con"><div class="popper_box_con_li"><img src="https://images.cnblogs.com/cnblogs_com/miluluyo/1765646/o_200614064005qrcode.jpg" alt="">公眾號:麋鹿魯喲</div><div class="popper_box_con_li"><img src="https://images.cnblogs.com/cnblogs_com/miluluyo/1493340/t_wxh.jpg" alt="">微信號:s978761</div></div><p>(加我記得備註 博客園 喔)</div>',/*這裡是微信圖標的彈窗內容,可以自行更改內容喔*/
	'portrait':'https://images.cnblogs.com/cnblogs_com/miluluyo/1765646/o_200515061851tx.jpg'
})/*這個是頭像圖片喔,你可以上傳到相冊里,然後F12獲取,或者使用博客園的那個鏈接也可以的撒~*/
</script>

參數說明

名稱 類型 默認值/實例 描述
names 字符串 ‘麋鹿魯喲’ 博客園名稱
notice 字符串 ‘<b>溫馨提示</b><span><a href=”https://github.com/miluluyo/cute-cnblogs” target=”_black”>cute-cnblogs</a>  樣式已開源</span><b style=”margin-top: 3px;”><a style=”font-size:10px” href=”https://www.cnblogs.com/IsAlpaca/” target=”_black”>查看一期樣式</a></b>’ 公告內容
headerUrl 字符串 ‘https://images.cnblogs.com/cnblogs_com/miluluyo/1765646/o_200519075219notice5.png’ 公告欄的背景圖
follow 字符串 ‘a1e76459-101d-47af-a8b6-08d523685c8c’ 複製follow括號里的內容,這是關注的那個碼
sidebarInfo 數組 [[ {‘icon’:’#icon-github1′,’url’:’https://github.com/miluluyo’,’title’:’github’}, {‘icon’:’#icon-weixin’,’url’:”,’title’:’微信’,’classname’:’popper_weixin’,’click’:false}, {‘icon’:’#icon-QQ’,’url’:’http://wpa.qq.com/msgrd?v=3&uin=978761587&site=qq&menu=yes’,’title’:’QQ’}, {‘icon’:’#icon-juejin’,’url’:’https://juejin.im/user/5d18adce5188256e98090e33′,’title’:’掘金’} ],[ {‘icon’:’#icon-weibobangding’,’url’:’https://www.weibo.com/6001406082/profile?topnav=1&wvr=6′,’title’:’微博’}, {‘icon’:’#icon-csdn’,’url’:’https://blog.csdn.net/qq_39394518′,’title’:’CSDN’}, {‘icon’:’#icon-bilibili’,’url’:’https://space.bilibili.com/100007925′,’title’:’bilibili’}, {‘icon’:’#icon-yuquemianlogo’,’url’:’https://www.yuque.com/miluluyo’,’title’:’語雀’} ]] 個人信息內那些小圖標們
icon 圖標
url 跳轉鏈接
title 提示名字
classname 要添加的class名
click 是否允許點擊跳轉
本框架有擴展的icon,文件在 github 中的 icon 文件夾內,可以下載去查看
signature 字符串 ‘靡不有初 鮮克有終’ 個人信息簽名 (寫一句喜歡的話吧)
popper_weixin 字符串 ‘< div class=”popper_box”>< p>< b>很高興認識你鴨~ (づ。◕ᴗᴗ◕。)づ< /b> < /p>< div class=”popper_box_con”>< div class=”popper_box_con_li”>< img src=”https://images.cnblogs.com/cnblogs_com/miluluyo/1765646/o_200614064005qrcode.jpg” alt=””>公眾號:麋鹿魯喲< /div>< div class=”popper_box_con_li”>< img src=”https://images.cnblogs.com/cnblogs_com/miluluyo/1493340/t_wxh.jpg” alt=””>微信號:s978761< /div>< /div>< p>(加我記得備註 博客園 喔)< /div>’ 微信焦點彈窗,內容可自行更改,可以放一些公眾號啊啥的~
portrait 字符串 ‘https://images.cnblogs.com/cnblogs_com/miluluyo/1765646/o_200515061851tx.jpg’ 頭像圖片路徑

頁首Html代碼

  <div id="set_btn_box">
    <div class="set_btn fly_top fadeIn animated">
        <svg class="icon" aria-hidden="true"><use xlink:href="#icon-zhiding"></use></svg>
    </div>
    <div class="set_btn article_icon_btn catalogue_btn">
        <svg class="icon" aria-hidden="true" style="color:#97A1A7"><use xlink:href="#icon-dagang"></use></svg>
    </div>
    <div class="set_btn article_icon_btn comment">
        <a href="#comment_form_container"><svg class="icon" aria-hidden="true" style="color:#97A1A7"><use xlink:href="#icon-linedesign-01"></use></svg></a>
    </div>
    <div class="set_btn skin_btn">
        <svg class="icon" aria-hidden="true" style="color:#97A1A7"><use xlink:href="#icon-pifu"></use></svg>
    </div>
    <div class="set_btn gratuity">
        <svg class="icon" aria-hidden="true" style="color:#97A1A7"><use xlink:href="#icon-dashang"></use></svg>
    </div>
    <div class="set_btn article_icon_btn artice_recommend">
        <svg class="icon" aria-hidden="true" style="color:#97A1A7"><use xlink:href="#icon-tuijian2"></use></svg>
    </div>
     <canvas id="thumsCanvas" width="200" height="400" style="width:100px;height:200px"></canvas>
    <div class="set_btn catalogue">
        <svg class="icon" aria-hidden="true" style="color:#97A1A7"><use xlink:href="#icon-cebianlan-"></use></svg>
    </div>
</div>
<script src='https://blog-static.cnblogs.com/files/miluluyo/canvas2.js'></script>
<!--
<link href="//files.cnblogs.com/files/linianhui/lnh.cnblogs.css" rel="stylesheet"/>-->

頁腳Html代碼

  <style id="ceshicss">
@media (max-width: 767px){
#set_btn_box {width: 100vw;left: 0;right: 0;bottom: 0;background: hsla(0,0%,100%,.6);height: 49px;display: flex;justify-content: space-between;align-items: center;padding: 12px 40px;border-top: 1px solid #e8e8e8;box-sizing: border-box;}
.set_btn {margin-top: 0;}
.set_btn.fly_top.fadeIn.animated {position: absolute;right: 10px;bottom: 60px;}
.container{bottom:50px}}
#mainContent{width:90%}
</style>
<link href="https://blog-static.cnblogs.com/files/miluluyo/tippy.min.css" rel="stylesheet">
<script src="https://unpkg.com/@popperjs/core@2.4.2/dist/umd/popper.min.js"></script>
<script src="https://blog-static.cnblogs.com/files/miluluyo/tippy.js"></script>
<link rel='stylesheet' href='https://cdn.bootcss.com/animate.css/3.7.2/animate.min.css'>
<script src="https://at.alicdn.com/t/font_1825850_klax1ao4o6.js"></script>
<script src="https://blog-static.cnblogs.com/files/miluluyo/three.min.js"></script>
<script src='https://blog-static.cnblogs.com/files/miluluyo/star.js'></script>
<link rel="stylesheet" href="https://blog-static.cnblogs.com/files/miluluyo/OwO.min.css" />
<script src="https://blog-static.cnblogs.com/files/miluluyo/OwO2.min.js"></script>
<script src="https://blog-static.cnblogs.com/files/miluluyo/cute-cnblogs2.js"></script>
<script src="https://blog-static.cnblogs.com/files/miluluyo/monitoring2.js"></script>

<script>

miluframe({
  Youself:'https://www.cnblogs.com/miluluyo/', /*個人的博客園鏈接*/
  /*博客園導航信息*/
    custom:[{
      name:'首頁',
      link:'https://www.cnblogs.com/miluluyo/',
      istarget:false
    },{
      name:'聯繫',
      link:'https://msg.cnblogs.com/send/%E9%BA%8B%E9%B9%BF%E9%B2%81%E5%93%9F',
      istarget:true
    },{
      name:'技能樹',
      link:'https://miluluyo.github.io/',
      istarget:true
    },{
      name:'留言板',
      link:'https://www.cnblogs.com/miluluyo/p/11578505.html',
      istarget:false
    },{
      name:'相冊',
      link:'https://www.cnblogs.com/miluluyo/gallery.html',
      istarget:false
    },{
      name:'友鏈',
      link:'https://www.cnblogs.com/miluluyo/p/11633791.html',
      istarget:false
    },{
      name:'維護',
      link:'https://www.cnblogs.com/miluluyo/p/12092009.html',
      istarget:false
    },{
      name:'投喂',
      link:'https://www.cnblogs.com/miluluyo/p/gratuity.html',
      istarget:false
    },{
      name:'管理',
      link:'https://i.cnblogs.com/',
      istarget:true
    }],
    /*向別人展示自己的友鏈信息*/
    resume:{
        "name":"麋鹿魯喲",
        "link":"https://www.cnblogs.com/miluluyo/",
        "headurl":"https://images.cnblogs.com/cnblogs_com/elkyo/1558759/o_o_my.jpg",
        "introduction":"大道至簡,知易行難。"
    },
    /*友鏈信息*/
    unionbox:[{
        "name":"麋鹿魯喲",
        "introduction":"生活是沒有標準答案的。",
        "url":"https://www.cnblogs.com/miluluyo",
        "headurl":"https://images.cnblogs.com/cnblogs_com/elkyo/1558759/o_o_my.jpg"
      },{
        "name":"麋鹿魯喲的技能樹",
        "introduction":"大道至簡,知易行難。",
        "url":"https://miluluyo.github.io/",
        "headurl":"https://images.cnblogs.com/cnblogs_com/elkyo/1558759/o_o_my.jpg"
      }],
    /*友鏈表格頭信息,這個可以忽略*/
    details:[{
        field: 'name',
        literal: '昵稱',
      },{
        field: 'introduction',
        literal: '標語',
      },{
        field: 'url',
        literal: '鏈接地址',
      },{
        field: 'headurl',
        literal: '頭像地址',
      }],
    /*瀏覽器頂部小圖標*/
    logoimg:'https://images.cnblogs.com/cnblogs_com/miluluyo/1765646/o_200519070633f12.png',
    /*文章頁面標題前的圖標,此處圖標有擴展,下面會提到圖標*/
    cuteicon:['icon-caomei','icon-boluo','icon-huolongguo','icon-chengzi','icon-hamigua','icon-lizhi','icon-mangguo','icon-liulian','icon-lizi','icon-lanmei','icon-longyan','icon-shanzhu','icon-pingguo','icon-mihoutao','icon-niuyouguo','icon-xigua','icon-putao','icon-xiangjiao','icon-ningmeng','icon-yingtao','icon-taozi','icon-shiliu','icon-ximei','icon-shizi'],
    /*讚賞,若true則显示此按鈕,false則不显示*/
    isGratuity:true,
    /*讚賞按鈕焦點显示讚賞內容,內容可自行更改*/
    gratuity:'<div class="popper_box"><p><b>要請我喝奶茶嗎  (づ。◕ᴗᴗ◕。)づ</b> </p><div class="popper_box_con"><div class="popper_box_con_li"><img src="https://images.cnblogs.com/cnblogs_com/miluluyo/1765646/o_200521053817wx.png" alt="">微信掃碼</div><div class="popper_box_con_li"><img src="https://images.cnblogs.com/cnblogs_com/miluluyo/1765646/o_200521053827zfb.png" >支付寶掃碼</div></div><p><b>留下一句你覺得很勵志與美的話給我吧~</b>&nbsp;&nbsp;<b><a href="https://www.cnblogs.com/miluluyo/p/12930946.html">GO</a></b></div>'
})
</script>
<!-- 點贊 -->
<canvas width="1777" height="841" style="position: fixed; left: 0px; top: 0px; z-index: 2147483647; pointer-events: none;"></canvas><script src="https://blog-static.cnblogs.com/files/miluluyo/mouse-click.js"></script>

<!-- 以下內容是否添加你隨意 -->

<script>
  /*在文章頁面添加古詩詞*/
  $("#navigator").after('<div class="poem-wrap"><div class="poem-border poem-left"></div><div class="poem-border poem-right"></div><h1>念兩句詩</h1><div id="poem_sentence"></div><div id="poem_info"></div></div>')
</script>
<script src="https://sdk.jinrishici.com/v2/browser/jinrishici.js" charset="utf-8"></script>
<script type="text/javascript">
  jinrishici.load(function(result) {
    var sentence = document.querySelector("#poem_sentence")
    var info = document.querySelector("#poem_info")
    sentence.innerHTML = result.data.content
    info.innerHTML = '【' + result.data.origin.dynasty + '】' + result.data.origin.author + '《' + result.data.origin.title + '》'
  });
</script>

<script type="text/javascript">
/* 鼠標特效,我覺得太花哨了就註釋了,喜歡的自己打開註釋就可以 */
/*var a_idx = 0;
jQuery(document).ready(function($) {
    $("body").click(function(e) {
        var a = new Array("去活出你自己。","今天的好計劃勝過明天的完美計劃。","不要輕言放棄,否則對不起自己。","緊要關頭不放棄,絕望就會變成希望。","如果不能改變結果,那就完善過程。","好好活就是干有意義的事,有意義的事就是好好活!","你真正是誰並不重要,重要的是你的所做所為。","你不想為你的信仰冒一下險嗎?難道想等你老了,再後悔莫及嗎?","有些鳥兒是關不住的,它的每一根羽毛都閃耀着自由的光輝。","決定我們成為什麼樣人的,不是我們的能力,而是我們的選擇。","掉在水裡你不會淹死,呆在水裡你才會淹死,你只有游,不停的往前游。","有些路,只能一個人走。","希望你眼眸有星辰,心中有山海。","從此以夢為馬,不負韶華。","人的成就和差異決定於其業餘時間。","佛不要你皈依,佛要你歡喜。","ダーリンのこと 大好きだよ","小貓在午睡時,地球在轉。","我,混世大魔王,申請做你的小熊軟糖。","決定好啦,要暗暗努力。","吶,做人呢最緊要開心。","好想邀請你一起去雲朵上打呼嚕呀。","永遠年輕,永遠熱淚盈眶。","我生來平庸,也生來驕傲。","我走得很慢,但我從不後退。","人間不正經生活手冊。","我是可愛的小姑娘,你是可愛。","數學里,有個溫柔霸道的詞,有且僅有。","吧唧一口,吃掉難過。","你頭髮亂了哦。","健康可愛,沒有眼袋。","日月星辰之外,你是第四種難得。","你是否成為了了不起的成年人?","大家都是第一次做人。","何事喧嘩?!","人間有味是清歡。","你笑起來真像好天氣。","風填詞半句,雪斟酒一壺。","除了自渡,他人愛莫能助。","昨日種種,皆成今我。","一夢入混沌 明月撞星辰","保持獨立 適當擁有","謝謝你出現 這一生我很喜歡","做自己就好了 我會喜歡你的","太嚴肅的話,是沒辦法在人間尋歡作樂的","願你餘生可隨遇而安,步步慢。","黃瓜在於拍,人生在於嗨","奇變偶不變,符號看象限。","從來如此,便對么?","今天我這兒的太陽,正好適合曬鈣 你呢","未來可期,萬事勝意。","星光不問趕路人 時光不負有心人","我當然不會試圖摘月,我要月亮奔我而來","女生要修鍊成的五樣東西: 揚在臉上的自信,長在心底的善良, 融進血里的骨氣,刻進命里的堅強,深到骨子里的教養","燕去燕歸,滄海桑田。縱此生不見,平安惟願","我想認識你 趁風不注意","我一直想從你的窗子里看月亮","長大應該是變溫柔,對全世界都溫柔。","別在深夜做任何決定","山中何事,松花釀酒,春水煎茶。","桃李春風一杯酒,江湖夜雨十年燈。","欲買桂花同載酒,終不似,少年游。");
        var le = Math.ceil(Math.random()*a.length); 
        var $i = $("<span></span>").text(a[le]);/*a[a_idx]*/
        /*a_idx = (a_idx + 1) % a.length;
        var x = e.pageX,
        y = e.pageY;
        $i.css({
            "z-index": 999999999999999999999999999999999999999999999999999999999999999999999,
            "top": y - 20,
            "left": x,
            "position": "absolute",
            "font-weight": "bold",
            "color": "rgb("+~~(255*Math.random())+","+~~(255*Math.random())+","+~~(255*Math.random())+")"
        });
        $("body").append($i);
        $i.animate({
            "top": y - 180,
            "opacity": 0
        },
        2000,
        function() {
            $i.remove();
        });
    });
});*/
</script>


<!--音樂,只在PC端寬度>1000px時显示-->
<link rel="stylesheet" href="https://blog-static.cnblogs.com/files/miluluyo/APlayer.min.css">
<div id="player" class="aplayer aplayer-withlist aplayer-fixed" data-id="3116636104" data-server="netease" data-type="playlist" data-order="random" data-fixed="true" data-listfolded="true" data-theme="#2D8CF0"></div>
<script src="https://blog-static.cnblogs.com/files/miluluyo/APlayer.min.js"></script>
<script src="https://blog-static.cnblogs.com/files/miluluyo/Meting.min.js"></script>

<!--貓,只在PC端显示,移動端不加載了,因為會卡頓頁面-->
<script src="https://eqcn.ajz.miesnfu.com/wp-content/plugins/wp-3d-pony/live2dw/lib/L2Dwidget.min.js"></script>
<script>
  var mobile_flag = isMobile();
  if(mobile_flag){
    //console.info("移動端")
  }else{
    //console.info("PC端")
    L2Dwidget.init({
        "model": {
            "jsonPath": "https://unpkg.com/live2d-widget-model-hijiki/assets/hijiki.model.json",
            "scale": 1
        },
        "display": {
            "position": "left",
            "width": 100,
            "height": 200,
            "hOffset": 70,
            "vOffset": 0
        },
        "mobile": {
            "show": true,
            "scale": 0.5
        },
        "react": {
            "opacityDefault": 0.7,
            "opacityOnHover": 0.2
        }
    });
    window.onload = function(){
      $("#live2dcanvas").attr("style","position: fixed; opacity: 0.7; left: 70px; bottom: 0px; z-index: 1; pointer-events: none;")
    }
  }

</script>

<script>

/*記錄訪問數據,我用了兩個,一個是這個在 https://clustrmaps.com/ 網站,另一個是 https://www.51.la/ 這個網站*/
/*
	第一種:https://clustrmaps.com/
	註冊賬號,添加自己博客園的鏈接,選擇自定義Customize,
	選擇 Image based (basic version for websites that don't support javascript),調整到你喜歡的樣式,然後複製
	:這個我插入在了側邊欄的最底部,把生成的代碼粘貼到append內,這就完事了
*/
$('#sideBarMain').append('')

/*
	第二種:https://www.51.la/
	註冊賬號,點控制台,添加統計ID,統計圖標显示我是不显示的
	這個目前插入的js好像報錯,我的是很早之前生成的,還能用,因此還是推薦用第一種吧

	別的地方也有這種很多統計訪問數據的,可以自己找找看呢

*/
</script>

參數說明

名稱 類型 默認值/實例 描述
Youself 字符串 https://www.cnblogs.com/miluluyo/ 個人博客園首鏈接
custom 數組 [{ name:’首頁’, link:’https://www.cnblogs.com/miluluyo/’, istarget:false },{ name:’聯繫’, link:’https://msg.cnblogs.com/send/%E9%BA%8B%E9%B9%BF%E9%B2%81%E5%93%9F’, istarget:true },{ name:’技能樹’, link:’https://miluluyo.github.io/’, istarget:true },{ name:’留言板’, link:’https://www.cnblogs.com/miluluyo/p/11578505.html’, istarget:false },{ name:’相冊’, link:’https://www.cnblogs.com/miluluyo/gallery.html’, istarget:false },{ name:’友鏈’, link:’https://www.cnblogs.com/miluluyo/p/11633791.html’, istarget:false },{ name:’維護’, link:’https://www.cnblogs.com/miluluyo/p/12092009.html’, istarget:false },{ name:’投喂’, link:’https://www.cnblogs.com/miluluyo/p/gratuity.html’, istarget:false },{ name:’管理’, link:’https://i.cnblogs.com/’, istarget:true }] 導航信息
name 導航名
link 導航鏈接
istarget true跳轉到新頁面上,false當前頁面打開
resume 對象 {
“name”:”麋鹿魯喲”,
“link”:”https://www.cnblogs.com/miluluyo/”,
“headurl”:”https://images.cnblogs.com/cnblogs_com/
elkyo/1558759/o_o_my.jpg”,
“introduction”:”大道至簡,知易行難。”
}
自己的友鏈信息
name 導航名
link 導航鏈接
headurl 頭像
introduction 語錄
unionbox 數組 [{
“name”:”麋鹿魯喲”,
“introduction”:”生活是沒有標準答案的。”,
“url”:”https://www.cnblogs.com/miluluyo”,
“headurl”:”https://images.cnblogs.com/cnblogs_com/
elkyo/1558759/o_o_my.jpg”
},{
“name”:”麋鹿魯喲的技能樹”,
“introduction”:”大道至簡,知易行難。”,
“url”:”https://miluluyo.github.io/”,
“headurl”:”https://images.cnblogs.com/cnblogs_com/
elkyo/1558759/o_o_my.jpg”
}]
友鏈數組
name 昵稱
introduction 標語
url 鏈接地址
headurl 頭像地址
clicktext 數組 [{ field: ‘name’, literal: ‘昵稱’, },{ field: ‘introduction’, literal: ‘標語’, },{ field: ‘url’, literal: ‘鏈接地址’, },{ field: ‘headurl’, literal: ‘頭像地址’, }] 友鏈表格頭信息,這項可以忽略掉
logoimg 字符串 ‘https://images.cnblogs.com/cnblogs_com/miluluyo/1765646/o_200519070633f12.png’ 瀏覽器頂部小圖標
cuteicon 數組 [‘icon-caomei’,’icon-boluo’,’icon-huolongguo’,’icon-chengzi’,’icon-hamigua’,’icon-lizhi’,’icon-mangguo’,’icon-liulian’,’icon-lizi’,’icon-lanmei’,’icon-longyan’,’icon-shanzhu’,’icon-pingguo’,’icon-mihoutao’,’icon-niuyouguo’,’icon-xigua’,’icon-putao’,’icon-xiangjiao’,’icon-ningmeng’,’icon-yingtao’,’icon-taozi’,’icon-shiliu’,’icon-ximei’,’icon-shizi’] 文章頁面標題前的圖標,此處圖標我只放入了一些水果的icon,不過可以自己引入文件進行修改名字添加自己想加的,本框架有擴展的icon,文件在 github 中的 icon 文件夾內,可以下載去查看
gratuity 字符串 ‘<div class=”popper_box”><p><b>要請我喝奶茶嗎 (づ。◕ᴗᴗ◕。)づ</b> </p><div class=”popper_box_con”><div class=”popper_box_con_li”><img src=”https://images.cnblogs.com/cnblogs_com/miluluyo/1765646/o_200521053817wx.png” alt=””>微信掃碼</div><div class=”popper_box_con_li”><img src=”https://images.cnblogs.com/cnblogs_com/miluluyo/1765646/o_200521053827zfb.png” >支付寶掃碼</div></div><p><b>留下一句你覺得很勵志與美的話給我吧~</b>  <b><a href=”https://www.cnblogs.com/miluluyo/p/12930946.html”>GO</a></b></div>’ 讚賞按鈕焦點显示讚賞內容,內容可自行更改
isGratuity 布爾值 true 默認true,若true則显示此按鈕,false則不显示

更換頂部背景圖

當前框架使用了一張圖片,也可以自己進行更換成隨機圖片API

在css樣式中

 #blogTitle{background:url(https://images.cnblogs.com/cnblogs_com/miluluyo/1764887/o_20051406472117.jpg) center center / cover no-repeat #222;overflow:hidden;width:100%;height:40vh;max-height:40vh;box-shadow:0 1px 2px rgba(150,150,150,.7);       /*搜索這個 更換 background: url() 里的鏈接 即可*/

最後

更多內容請查看 cute-cnblogs 自定義番外篇
(PS:可以使用番外篇里的隨機圖片API喔~)

請吃糖

如果您喜歡這裏,感覺對你有幫助,並且有多餘的軟妹幣的話,不妨投喂一顆糖喔~

<(▰˘◡˘▰)> 謝謝老闆~

微信掃碼

支付寶掃碼

讚賞的時候,留下一句你覺得很勵志與美的話給我吧~

(也可以加一個博客園給我喔,會添加在名字的旁邊喔~點擊可以跳轉~ 例如:去瞧瞧都有誰讚賞了

為了響應大家的號召,方便大家技術交流,之前建立了一個微信群,如果大家有需要可以掃碼(或者搜我微信號:s978761)加我好友,我邀請你加入~本群是一個純交流學習工作的群,不準發布廣告、營銷相關的信息!對了,加我記得備註上:博客園+名稱 加群 喔~

微信號:s978761

公眾號:麋鹿魯喲

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

【其他文章推薦】

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

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

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

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

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

聚甘新