這樣一個需求:當前作用域內(nèi)有未知的一些變量,其中一個函數(shù)中可以拿到某個變量名字符串,怎么能在函數(shù)內(nèi)通過傳進來的字符串取到作用域鏈中的變量值,示例小 demo 如下:
const name = '周小黑'
const age = 18
/**
* @param {String} e 變量名字符串
* @returns value 通過變量名字符串在作用域鏈中取到的變量值
*/
function fn(e) {
let value
// ...
return value
}
const str = fn('name')
要解決上面的問題,主要就是怎么將字符串轉(zhuǎn)變成可執(zhí)行的代碼?主要有三種方式:
eval() 函數(shù)會將傳入的字符串當做 JavaScript 代碼進行執(zhí)行,所以下面的字符串可以正確取到變量對應的值,eval 對比 new Function 和 setTimeout 它是可以訪問局部作用域的,后兩者都只能訪問全局作用域。
const name = '周小黑'
const age = 18
function fn(e) {
let value = eval(e)
return value
}
const str = fn('name')
console.log(str)
很多地方都能看到這句名言:eval is evil,eval 是魔鬼。所以使用 eval 的時候要注意,性能低而且有安全風險。
const name = '周小黑'
const age = 18
function fn(e) {
let value = new Function('return ' + e)
return value
}
const str = fn('name')
console.log(str)
對于函數(shù)我們平時都是直接用 function 或者箭頭函數(shù)創(chuàng)建,不會用構(gòu)造函數(shù)來創(chuàng)建函數(shù),一般使用也是為了來動態(tài)創(chuàng)建函數(shù),因為 new Function 最后一個參數(shù)是函數(shù)體字符串,這樣我們就可以用來動態(tài)生成拼接,具體語法如下:
let func = new Function([arg1, arg2, ...argN], functionBody)
注意函數(shù)體中只能訪問全局作用域,不能訪問局部作用域。
定時器 setTimeout 的第一個參數(shù)我們平時都是傳一個函數(shù),它其實也是可以傳字符串進去的,在瀏覽器中是可以正常執(zhí)行的,在node環(huán)境中會報錯。
實際上瀏覽器中也是不推薦這么用的,另外需要注意的是字符串中的變量只能訪問全局作用域,不能訪問局部作用域,如果全局作用域中沒有,就是 undefined。
前端學習中,我們經(jīng)常會遇到寫的字符不太對想改變它的如果重新些可能太麻煩,這時候我們就要用到轉(zhuǎn)義字符串來改變。
顧名思義,所謂的轉(zhuǎn)義字符就是能夠改變字符原本意義的特殊字符。
在實際應用中,總有一些具有特殊含義的字符無法直接輸入,比如換行。
這時候轉(zhuǎn)義的字符的威力就得以顯現(xiàn),代碼實例如下:
console.log(“網(wǎng)站名稱:\n興趣部落”);
我們無法直接在代碼中直接鍵入換行,使用\n即可實現(xiàn)換行功能。
n的原本意義就是字符”n”,但是加上反斜杠\之后,它就具有了換行功能。
一.轉(zhuǎn)義字符的定義:
轉(zhuǎn)義字符以反斜杠(\)開頭,后面可以是一個或者多個字符
它是一種特殊的字符常量,能夠表達與原本字符不同的特殊功能,也可以說失去原本的功能獲取另外的功能。
再來看一段常見的代碼實例:
console.log(“”轉(zhuǎn)義字符串”的定義”);
上述代碼,我們原本是想打印出”轉(zhuǎn)義字符串”的定義,但是會報錯。
因為前兩個引號會首先配對,于是就會導致錯誤。
解決方案一:
console.log(‘”轉(zhuǎn)義字符串”的定義’);
外層的雙引號用單引號替代,解決了配對問題。
解決方案二:
console.log(“\”轉(zhuǎn)義字符串\”的定義”);
雙引號在代碼中是有特殊意義,用以說明它所包裹的內(nèi)容是字符串。
但是前面添加反斜杠之后,雙引號就失去了這個功能,而是將其作為普通字符使用。
個人需求,需要將html格式轉(zhuǎn)換成PDF并加上水印圖片。于是乎第一次接觸這種需求的小菜鳥博主我,在某度搜索引擎上不斷地查閱關(guān)鍵字資料、踩坑,終于有了一個相應的解決方案。以下是解決步驟,記錄下來方便以后的回顧,以及各位大神們的品鑒。
1、在 NuGet 搜索 itextsharp 關(guān)鍵字 下載以下截圖圈中的兩個包,一般下載完后項目會自動引用。
2、在項目文件中引入以下命名空間(建議下面提及的代碼封裝成類庫,方便項目間調(diào)用,個人取舍)
3、Html字符串轉(zhuǎn)pdf文件流,加水印圖片以及未加水印重載 精簡幫助類(由博主踩坑整理,僅完成個人業(yè)務需求)
1 /// <summary>
2 /// Html字符串轉(zhuǎn)PDF輸出幫助類
3 /// </summary>
4 public class HtmlToPdfHelper
5 {
6 #region HtmlToPDF
7
8 /// <summary>
9 /// 判斷是否有亂碼
10 /// </summary>
11 /// <param name="txt"></param>
12 /// <returns></returns>
13 private static bool IsMessyCode(string txt)
14 {
15 var bytes = Encoding.UTF8.GetBytes(txt);
16 for (var i = 0; i < bytes.Length; i++)
17 {
18 if (i < bytes.Length - 3)
19 if (bytes[i] == 239 && bytes[i + 1] == 191 && bytes[i + 2] == 189)
20 {
21 return true;
22 }
23 }
24 return false;
25 }
26
27 /// <summary>
28 /// 將Html字符串 輸出到PDF檔里
29 /// </summary>
30 /// <param name="htmlText"></param>
31 /// <returns></returns>
32 public static byte[] ConvertHtmlTextToPdf(string htmlText)
33 {
34 return ConvertHtmlTextToPdf(htmlText, "", 0, 0, 0, 0);
35 }
36
37 /// <summary>
38 /// 將Html字符串 輸出到PDF檔里,并添加水印
39 /// </summary>
40 /// <param name="htmlText">網(wǎng)頁代碼</param>
41 /// <param name="picPath">水印路徑</param>
42 /// <param name="left">距離左邊距離</param>
43 /// <param name="top">距頂部距離</param>
44 /// <param name="width">水印寬度</param>
45 /// <param name="height">水印高度</param>
46 /// <returns></returns>
47 public static byte[] ConvertHtmlTextToPdf(string htmlText, string picPath, int left, int top, int width, int height)
48 {
49 if (string.IsNullOrEmpty(htmlText))
50 {
51 return null;
52 }
53 //避免當htmlText無任何html tag標簽的純文字時,轉(zhuǎn)PDF時會掛掉,所以一律加上<p>標簽
54 htmlText = "<p>" + htmlText + "</p>";
55 MemoryStream outputStream = new MemoryStream();//要把PDF寫到哪個串流
56 byte[] data = Encoding.UTF8.GetBytes(htmlText);//字串轉(zhuǎn)成byte[]
57 MemoryStream msInput = new MemoryStream(data);
58 Document doc = new Document();//要寫PDF的文件,建構(gòu)子沒填的話預設(shè)直式A4
59 PdfWriter writer = PdfWriter.GetInstance(doc, outputStream);
60 //指定文件預設(shè)開檔時的縮放為100%
61 PdfDestination pdfDest = new PdfDestination(PdfDestination.XYZ, 0, doc.PageSize.Height, 1f);
62 //開啟Document文件
63 doc.Open();
64
65 //寫入水印圖片
66 if (!string.IsNullOrEmpty(picPath))
67 {
68 Image img = Image.GetInstance(picPath);
69 //設(shè)置圖片的位置
70 img.SetAbsolutePosition(width + left, (doc.PageSize.Height - height) - top);
71 //設(shè)置圖片的大小
72 img.ScaleAbsolute(width, height);
73 doc.Add(img);
74 }
75 try
76 {
77 //使用XMLWorkerHelper把Html parse到PDF檔里
79 XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, msInput, null, Encoding.UTF8);
80 //將pdfDest設(shè)定的資料寫到PDF檔
81 PdfAction action = PdfAction.GotoLocalPage(1, pdfDest, writer);
82 writer.SetOpenAction(action);
83 }
84 catch (Exception)
85 {
86 return null;
87 }
88 doc.Close();
89 msInput.Close();
90 outputStream.Close();
91 //回傳PDF檔案
92 return outputStream.ToArray();
94 }
95
96 #endregion
97
98 }
4、獲取網(wǎng)頁字符串的方法
1 /// <summary>
2 /// 獲取網(wǎng)站內(nèi)容,包含了 HTML+CSS+JS
3 /// </summary>
4 /// <returns>String返回網(wǎng)頁信息</returns>
5 public static string GetWebContent(string inpath)
6 {
7 try
8 {
9 WebClient myWebClient = new WebClient();
10 //獲取或設(shè)置用于向Internet資源的請求進行身份驗證的網(wǎng)絡(luò)憑據(jù)
11 myWebClient.Credentials = CredentialCache.DefaultCredentials;
12 //從指定網(wǎng)站下載數(shù)據(jù)
13 Byte[] pageData = myWebClient.DownloadData(inpath);
14 //如果獲取網(wǎng)站頁面采用的是GB2312,則使用這句
15 string pageHtml = Encoding.UTF8.GetString(pageData);
16 bool isBool = IsMessyCode(pageHtml);//判斷使用哪種編碼 讀取網(wǎng)頁信息
17 if (!isBool)
18 {
19 string pageHtml1 = Encoding.UTF8.GetString(pageData);
20 pageHtml = pageHtml1;
21 }
22 else
23 {
24 string pageHtml2 = Encoding.Default.GetString(pageData);
25 pageHtml = pageHtml2;
26 }
27 return pageHtml;
28 }
29 catch (WebException webEx)
30 {
31 return webEx.Message;
32 }
33 }
5、MVC設(shè)計模式下獲取控制器視圖Html方法,很XX的一個問題就是只能獲取調(diào)用此方法的控制器下所有視圖,不能跨控制器獲取視圖,有待優(yōu)化
1 /// <summary>
2 /// 獲取MVC視圖Html
3 /// </summary>
4 /// <param name="context">控制器上下文</param>
5 /// <param name="viewName">視圖名稱</param>
6 /// <param name="param"></param>
7 /// <returns></returns>
8 public static string GetViewHtml(ControllerContext context, string viewName)
9 {
10 if (string.IsNullOrEmpty(viewName))
11 viewName = context.RouteData.GetRequiredString("action");
12 using (var sw = new StringWriter())
13 {
14 ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(context, viewName);
15 var viewContext = new ViewContext(context, viewResult.View, context.Controller.ViewData, context.Controller.TempData, sw);
16 try
17 {
18 viewResult.View.Render(viewContext, sw);
19 }
20 catch (Exception ex)
21 {
22 throw;
23 }
24
25 return sw.GetStringBuilder().ToString();
26 }
27 }
6、將pdf流輸出至客戶瀏覽器下載方法
1 /// <summary>
2 /// 將pdf文件流輸出至瀏覽器下載
3 /// </summary>
4 /// <param name="pdfFile">PDF文件流</param>
5 public static void PdfDownload(byte[] pdfFile)
6 {
7 byte[] buffer = pdfFile;
8 Stream iStream = new MemoryStream(buffer);
9 try
10 {
11 int length;
12 long dataToRead;
13 string filename = DateTime.Now.ToString("yyyyMMddHHmmss") + ".pdf";//保存的文件名稱
14 dataToRead = iStream.Length;
15 HttpContext.Current.Response.Clear();
16 HttpContext.Current.Response.ClearHeaders();
17 HttpContext.Current.Response.ClearContent();
18 HttpContext.Current.Response.ContentType = "application/pdf"; //文件類型
19 HttpContext.Current.Response.AddHeader("Content-Length", dataToRead.ToString());//添加文件長度,進而顯示進度
20 HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=" + HttpUtility.UrlEncode(filename, Encoding.UTF8));
21 while (dataToRead > 0)
22 {
23 if (HttpContext.Current.Response.IsClientConnected)
24 {
25 length = buffer.Length;
26 HttpContext.Current.Response.OutputStream.Write(buffer, 0, length);
27 HttpContext.Current.Response.Flush();
28 buffer = new Byte[length];
29 dataToRead = dataToRead - length;
30 }
31 else
32 {
33 dataToRead = -1;
34 }
35 }
36 }
37 catch (Exception ex)
38 {
39 HttpContext.Current.Response.Write("文件下載時出現(xiàn)錯誤!");
40 }
41 finally
42 {
43 if (iStream != null)
44 {
45 iStream.Close();
46 }
47 //結(jié)束響應,否則將導致網(wǎng)頁內(nèi)容被輸出到文件,進而文件無法打開
48 HttpContext.Current.Response.Flush();
49 HttpContext.Current.Response.End();
50
51 }
52 }
7、MVC控制器下調(diào)用Demo(步驟4、6 方法封裝至幫助類)
1 public class HomeController : Controller
2 {
3 //
4 // GET: /Home/
5
6 public ActionResult Index()
7 {
8 //從網(wǎng)址下載Html字符串(方法一)
9 string inpath = System.Web.HttpContext.Current.Server.MapPath("~/PDFTemplate/test.html");
10 string htmlText = HtmlToPdfHelper.GetWebContent(inpath);//此處調(diào)用步驟4方法
11
12 //獲取MVC視圖Html字符串(方法二)
13 //string htmlText = GetViewHtml(ControllerContext, "Test");//此處調(diào)用步驟5方法
14
15 //水印圖片路徑
16 string picPath = Server.MapPath("~/PDFTemplate/TemplateImg/authentication-iocn.png");
17 //html轉(zhuǎn)pdf并加上水印
18 byte[] pdfFile = HtmlToPdfHelper.ConvertHtmlTextToPdf(htmlText, picPath, 100, 200, 100, 100);
19 //輸出至客戶端
20 HtmlToPdfHelper.PdfDownload(pdfFile);//此處調(diào)用步驟6方法
21
22 return View();
23 }
24
25 public ActionResult Test()
26 {
27 return View();
28 }
29
30 /// <summary>
31 /// 獲取MVC視圖Html
32 /// </summary>
33 /// <param name="context"></param>
34 /// <param name="viewName">視圖名稱</param>
35 /// <returns></returns>
36 public static string GetViewHtml(ControllerContext context, string viewName)
37 {
38 if (string.IsNullOrEmpty(viewName))
39 viewName = context.RouteData.GetRequiredString("action");
40 using (var sw = new StringWriter())
41 {
42 ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(context, viewName);
43 var viewContext = new ViewContext(context, viewResult.View, context.Controller.ViewData,
44 context.Controller.TempData, sw);
45 try
46 {
47 viewResult.View.Render(viewContext, sw);
48 }
49 catch (Exception ex)
50 {
51 throw;
52 }
53
54 return sw.GetStringBuilder().ToString();
55 }
56 }
57 }
總結(jié):我理解的解決思路是將html讀取轉(zhuǎn)換成字符串,之后再通過 itextsharp 轉(zhuǎn)換成 pdf 比特幣 傳輸至客戶端或直接保存至服務器生成鏈接供用戶下載。(新手上路,不妥之處,歡迎各位大神指教)
以上代碼僅滿足個人業(yè)務邏輯需求,謝謝瀏覽。
*請認真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。