做者:JT
譯者:前端小智
來源: https://scotch.io/
點贊再看,養成習慣本文
GitHub
https://github.com/qq44924588... 上已經收錄,更多往期高贊文章的分類,也整理了不少個人文檔,和教程資料。歡迎Star和完善,你們面試能夠參照考點複習,但願咱們一塊兒有點東西。html
Vue.js 具備簡單的 API 和幾個選項,可用於在咱們的組件中定義HTML模板。前端
咱們可使用<template>
標籤選項,在根組件實例上定義template
屬性,或者使用單文件組件。vue
上面的選項很棒而且能夠完美地工做,可是,在您的應用程序的生命週期中,有時會感到笨拙,設計過分或很是不靈活。node
那麼,咱們爲何要使用 JSX 而不是其餘模板定義呢?git
<div></div>
的寫法一看就是比 this.$createElement('div', {}, [...])
簡潔不少。先舉一個例子來講明爲何 JSX 是好的。github
咱們要構建一個<TextField/>
組件,該組件能夠是普通的單行文本輸入或多行輸入(文本區域)。 咱們的模板聲明可能看起來像這樣。面試
<div> <textarea v-if="multiline" v-model="content" :name="name" :placeholder="placeholder" :aria-invalid="false"> <input v-else v-model="content" :name="name" :placeholder="placeholder" :aria-invalid="false"> </div>
從上面的代碼片斷中能夠看到,咱們很快就會遇到一些問題,好比重複代碼等等。想象一下,必須支持input
上面所列的各類屬性。上面的這個小片斷將會增加併成爲一個難以維護的噩夢。npm
要解決這個問題,咱們須要使用Vue進行降級處理,所以須要使用理接近Vue的內部API來解決這個問題。編程
注意:這裏並非說沒有JSX就沒有一種簡單的方法來處理上面的問題,只是說將這個邏輯移動到帶有JSX的
render()
方法可使組件更直觀。
咱們在 Vue 中建立的每一個組件都有一個render
方法。這個就是 Vue 選擇渲染組件的地方。即便咱們不定義這個方法,Vue 也會爲咱們作這件事。json
這意味着當咱們在 Vue 中定義 HTML 模板時,Vue 的模板編譯器將其編譯爲一個createElement
函數,該函數帶有幾個參數並從render
函數返回結果。
爲了修復上一節中的代碼,咱們刪除了template
屬性或template
標籤,並在組件上定義了render()
方法。 若是在組件上定義了render
方法,則 Vue 將忽略template
定義。
... export default { name: 'TextField', render (createElement) { const tag = this.multiline ? 'textarea' : 'input' return createElement(tag, { class: { 'text-input': true, 'is-disabled': false }, attrs: { name: this.name, placeholder: this.placeholder, 'aria-invalid': false } }) } } ...
上面的代碼作了幾件事:
render
方法從Vue獲取一個createElement
助手。createElement
的選項不少。咱們爲 Vue 組件定義的每一個模板都將轉換爲可返回createElement
函數的render
方法。 由於這個緣由,render
方法將優先於模板定義。
舉個例子:
// HTML <div> <p>Only you can stop forest fires</p> </div>
模板編譯器將把上面的 HTML 轉換成:
... render (createElement) { return createElement( 'div', {}, createElement( 'p', {}, 'Only you can stop forest fires' ) ) } ...
如今你可能會問這個問題:「對可讀性來講這很差嗎?」 答案是確定的。 一旦定義了具備許多元素嵌套級別或具備多個同級元素的組件,咱們就會遇到這個新問題。
這就是 JSX 出現的緣由,它能夠很好的解決此類問題。
JSX 是 Facebook 工程團隊創造的一個術語。
JSX 是 JavaScript 的相似XML的語法擴展,沒有任何定義的語義。
JSX 不打算由引擎或瀏覽器實現。相反,咱們將使用 Babel 之類的轉置器將JSX轉換成常規的 JS 。
// 此行是JSX的示例 const heading = <h1>Welcome to Scotch</h1>;
基本上,JSX 容許咱們在 JS 中使用相似 Html 的語法。
若是使用的 Vue-cli 大於或等於 3.0 版本,那麼就直接可使用JSX的語法了。
若是您使用的是不支持 JSX 的Vue-cli較舊版本,則能夠經過安裝babel-preset-vue-app
來添加它,並將其添加到您的.babelrc
文件中。
# Using npm npm install --save-dev babel-preset-vue-app # Using yarn yarn add --dev babel-preset-vue-app
在.babelrc
文件中,添加:
{ "presets": ["vue-app"] }
咱們如今能夠在組件的render
函數中使用 JSX。
在 Vue 中使用JSX須要注意幾點。
要監聽 JSX 中的事件,咱們須要「on」
前綴。 例如,將onClick
用於單擊事件。
render (createElement) { return ( <button onClick={this.handleClick}></button> ) }
要修改事件,請使用
render (createElement) { return ( <button onClick:prevent={this.handleClick}></button> ) }
綁定變量,注意這裏不是使用 :
render (createElement) { return ( <button content={this.generatedText}></button> ) }
將HTML字符串設置爲元素的內容,使用domPropsInnerHTML
而不是使用v-html
render (createElement) { return ( <button domPropsInnerHTML={htmlContent}></button> ) }
咱們也能夠展開一個大對象:
render (createElement) { return ( <button {...this.largeProps}></button> ) }
回到咱們最初的「TextField」
組件。如今咱們已經在 Vue 應用程序中啓用了 JSX,咱們如今能夠這樣作了。
render (createElement) { const inputAttributes = { class: 'input-field has-outline', // class definition onClick: this.handleClick // event handler backdrop: false // custom prop } const inputMarkup = this.multiline ? <textarea {...inputAttributes}></textarea> : <input {...inputAttributes}/> return inputMarkup }
在 Vue 中使用JSX的另外一個好處是,咱們再也不須要註冊所需的每一個組件。 咱們只是導入和使用。
import {Button} from '../components' export default { render (createElement) { return <Button primary={true}>Edit</Button> } }
TypeScript 用做一種向 JavaScript添加類型檢查的機制。要在 JSX 支持 TypeScript中,須要修改 tsconfig.json
。
要在 TypeScript 中啓用 JSX,請先將該文件另存爲.tsx
文件,而後將tsconfig.json
修改成包括:
{ "compilerOptions": { .... "jsx": "preserve", } }
將jsx
選項設置爲「preserve」
意味着 TypeScript 不該處理JSX。 這樣作使 Babel 能夠控制全部JSX 和 TypeScript 堅持使用類型,由於它尚不支持 Vue JSX。
而後在項目中建立一個jsx.d.ts
文件,併爲 Vue 添加 TypeScript JSX 聲明。
import Vue, {VNode} from 'vue' declare global { namespace JSX { interface Element extends VNode {} interface ElementClass extends Vue {} interface ElementAttributesProperty { $props: {} } interface IntrinsicElements { [elemName: string]: any } } }
確保 TypeScript 能夠加載聲明文件。 或者,能夠經過如下方式在tsconfig.json
中爲其添加自動加載功能:
{ "compilerOptions": { ... "typesRoot": ["./node_modules/@types", "./types"] } }
代碼部署後可能存在的BUG無法實時知道,過後爲了解決這些BUG,花了大量的時間進行log 調試,這邊順便給你們推薦一個好用的BUG監控工具 Fundebug。
原文:https://scotch.io/tutorials/u...
文章每週持續更新,能夠微信搜索「 大遷世界 」第一時間閱讀和催更(比博客早一到兩篇喲),本文 GitHub https://github.com/qq449245884/xiaozhi 已經收錄,整理了不少個人文檔,歡迎Star和完善,你們面試能夠參照考點複習,另外關注公衆號,後臺回覆福利,便可看到福利,你懂的。