2020-03-04:vue-styled-components


總結

import styled,{ThemeProvider,injectGlobal} from 'vue-styled-components';

// 返回組件選項對象
styled.div`...`

// 可通過props傳參的組件
const StyledButton = styled('button', { primary: { 
  type:Boolean,
  default:"some"
})`...` 

// 通過組件創建樣式組件
const RouterLink = Vue.component('router-link') 
const StyledLink = styled(RouterLink)`...`

// 主題組件
const Wrapper = styled.section` 
  background: ${props => props.theme.primary};
`; 
<theme-provider :theme="{
  primary: 'palevioletred'
}">
  <wrapper>
    ...
  </wrapper>
</theme-provider>

// 擴展原有樣式組件
const TomatoButton = StyledButton.extend`...` 

// 復制樣式創建新的樣式組件
const Link = Button.withComponent('a') 

// 添加全局樣式
injectGlobal`...` 

——————————————————————————————————————————————————————————————————————————————————

基礎

https://es6.ruanyifeng.com/#docs/string#模板字符串

  • 注釋:模板字符串返回字符串類型
  • 如果${...}中的值不是字符串,將按照一般的規則轉為字符串。比如,大括號中是一個對象,將默認調用對象的toString方法
  • 模板字符串能夠嵌套
    • 注釋:在${...}使用另一個模板字符串

https://es6.ruanyifeng.com/#docs/string#標簽模板

  • 模板字符串可以緊跟在一個函數名后面,該函數將被調用來處理這個模板字符串。這被稱為“標簽模板”功能
alert`hello`
// 等同於
alert(['hello'])
  • 如果模板字符里面有變量,就不是簡單的調用了,而是會將模板字符串先處理成多個參數,再調用函數
    • 注釋:參數一這個字符串數組是以${}為參考位進行split的,例如'bacada'.split('a') // ["b", "c", "d", ""]'abacad'.split('a') // ["", "b", "c", "d"],即當變量在前后頭部時會在前后多出一個空字符串的數組項。也可以理解為常量數組比變量參數長度多1
    • 注釋:參數一字符串數組其他還包含一個名為raw的屬性stringArr.raw,保存的是轉義后的原字符串數組。為了方便取得轉義之前的原始模板而設計的
let a = 5;
let b = 10;

tag`Hello ${ a + b } world ${ a * b }`;
// 等同於
tag(['Hello ', ' world ', ''], 15, 50);

function tag(stringArr, value1, value2){
  // ...
}
// 等同於
function tag(stringArr, ...values){
  // ...
}
  • “標簽模板”的一個重要應用,就是過濾 HTML 字符串,防止用戶輸入惡意內容
function SaferHTML(templateData) {
  let s = templateData[0];
  for (let i = 1; i < arguments.length; i++) {
    let arg = String(arguments[i]);

    // Escape special characters in the substitution.
    s += arg.replace(/&/g, "&amp;")
            .replace(/</g, "&lt;")
            .replace(/>/g, "&gt;");

    // Don't escape special characters in the template.
    s += templateData[i];
  }
  return s;
}

let sender = '<script>alert("abc")</script>'; // 惡意代碼
let message = SaferHTML`<p>${sender} has sent you a message.</p>`;
// <p>&lt;script&gt;alert("abc")&lt;/script&gt; has sent you a message.</p>
  • 標簽模板的另一個應用,就是多語言轉換(國際化處理)
i18n`Welcome to ${siteName}, you are visitor number ${visitorNumber}!`
// "歡迎訪問xxx,您是第xxxx位訪問者!"
  • 使用標簽模板,在 JavaScript 語言之中嵌入其他語言
    • 疑問:vue中的jsx是否采用同樣的方式實現?可以幫助理解JSX的屬性綁定
    • 疑問:在JS中執行其他語言的代碼,實際上是文本處理后轉化為相同功能的當前語言后執行?
jsx`
  <div>
    <input
      ref='input'
      onChange='${this.handleChange}'
      defaultValue='${this.state.value}' />
      ${this.state.value}
   </div>
`
  • 模板處理函數的第一個參數(模板字符串數組),還有一個raw屬性,保存的是轉義后的原字符串數組。為了方便取得轉義之前的原始模板而設計的
    • 疑問:JS中各種遍歷的本質和區別?
    • 注釋:\n解析為文本換行,在字符串和模板字符串中都一樣。要定義'\n'字符串應轉義為\\n
tag`First line\nSecond line`

function tag(strings) {
  console.log(strings.raw[0]);
  // strings.raw[0] 為 "First line\\nSecond line"
  // 打印輸出 "First line\nSecond line"
}

https://es6.ruanyifeng.com/#docs/string#模板字符串的限制

  • 模板字符串默認會將\u當作Unicode 字符、\x當作十六進制字符和\n進行轉義,前兩個由於格式問題可能導致轉義失敗,這時包含該字符串的數組項將被填充為undefined,在raw中能拿到轉義前字符串
    • 疑問:在其他語言中如果存在${}的語法應該也會導致解析有誤
function tag(strs) {
  strs[0] === undefined
  strs.raw[0] === "\\unicode and \\u{55}";
}
tag`\unicode and \u{55}`

————————————————————————————————————————————————————————————————————————————

https://github.com/styled-components/vue-styled-components

  • 使用建立在language-sass和language-css之上的CSS語法

Support

yarn add vue-styled-components

Usage

Basic

  • 注釋:styled生成的組件默認含有插槽
  • 注釋:styled.div返回的是組件的選項對象
import styled from 'vue-styled-components';
const App = styled.div`
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
`;
const Nav = styled.div`
  padding: 30px;
  a {
    font-weight: bold;
    color: #2c3e50;
    &.router-link-exact-active {
      color: #42b983;
    }
  }
`

export default {
  render() {
    return <App>
      <Nav>
        <router-link to="/">Home</router-link> | <router-link to="/about">About</router-link>
      </Nav>
      <router-view />
    </App>
  }
}

Adapting based on props

  • 注釋:可以傳入參數控制的styled組件,帶有props
  • 注釋:這是一個真實的vue props選項,遵循vue的方式
import styled from 'vue-styled-components';

const btnProps = { primary: Boolean };

const StyledButton = styled('button', btnProps)`
  font-size: 1em;
  margin: 1em;
  padding: 0.25em 1em;
  border: 2px solid palevioletred;
  border-radius: 3px;
  background: ${props => props.primary ? 'palevioletred' : 'white'};
  color: ${props => props.primary ? 'white' : 'palevioletred'};
`;

export default StyledButton;

<styled-button primary>Primary</styled-button>

Theming

  • 注釋:ThemeProvider只需要在根結點綁定theme對象,采用inject方式向子孫組件傳遞theme對象,所以普通的對象是不具備響應的
  • 注釋:ThemeProvider是一個組件選項對象
  • 疑問:styled.default.div在實際情況中報錯,是筆誤?
  • 注釋:Wrapper中的props.theme並非一個真實的props選項
import styled,{ThemeProvider} from 'vue-styled-components'

const Wrapper = styled.default.section`
  padding: 4em;
  background: ${props => props.theme.primary};
`;

<theme-provider :theme="{
  primary: 'palevioletred'
}">
  <wrapper>
    // ...
  </wrapper>
</theme-provider>
  • 注釋:styled作為函數時第一個參數不僅可以傳入原生標簽名字符串還可以傳入組件的構造函數來創建樣式組件
  • 疑問:傳入構造函數應該可以和傳入字符串一樣使用第二參數創建props供外部傳入樣式變量
  • 疑問:Vue.component('router-link')不能正確獲取組件函數,正確應為Vue.component('RouterLink')
import styled from 'vue-styled-components';
const RouterLink = Vue.component('router-link')
const StyledLink = styled(RouterLink)`
  color: palevioletred;
  font-size: 1em;
  text-decoration: none;
`;

<styled-link to="/">Custom Router Link</styled-link>
  • 使用.extend方法擴展已經定義好了的樣式組件,保留組件原有樣式並加以擴展或覆蓋
import StyledButton from './StyledButton';

const TomatoButton = StyledButton.extend`
  color: tomato;
  border-color: tomato;
`;

export default TomatoButton;

withComponent

  • 注釋:可以復制其他組件的樣式生成一個新的組件
const Button = styled.button`
  background: green;
  color: white;
`
const Link = Button.withComponent('a')

injectGlobal

  • 全局樣式,每個應用最多使用一次
  • 注釋:可以在多個組件內使用,使用一次並不是硬性規定
// global-styles.js

import { injectGlobal } from 'vue-styled-components';

injectGlobal`
  @font-face {
    font-family: 'Operator Mono';
    src: url('../fonts/Operator-Mono.ttf');
  }
  body {
    margin: 0;
  }
`;

Syntax highlighting

  • 在vscode中vscode-styled-components插件用來支持語法高亮
  • 注釋:目前該插件不支持styled('div',propsObj)...這樣的高亮提醒
  • .extend...這個方法也不支持高亮

————————————————————————————————————————————————————————————————————————————

https://github.com/Microsoft/typescript-styled-plugin

  • 注釋:用於在ts中實現styled-components高亮提醒,及相關設置
  • 疑問:vscode-styled-components插件在JS中存在問題,是否在TS中表現會更好點?

Usage

With VS Code

  • 疑問:如果使用的是工作區版本的TypeScript,則必須在工作區中的TypeScript版本旁邊手動安裝插件?

Configuration

Tags

  • 可以通過配置為其他標記名稱啟用IntelliSense
  • 注釋:當需要使用sty來代替styled時需要進行配置
  • 注釋:在JS中無法生效,不知道是不是配置文件錯誤
// tsconfig.json
{
  "compilerOptions": {
    "plugins": [
      {
        "name": "typescript-styled-plugin",
        "tags": [
          "styled",
          "css",
          "sty"
        ]
      }
    ]
  }
}

import sty from 'styled-components'

sty.button`
    color: blue;
`

Linting

  • 疑問:禁用錯誤報告,TS中對模板語法會出現錯誤嗎?
{
  "compilerOptions": {
    "plugins": [
      {
        "name": "typescript-styled-plugin",
        "validate": false
      }
    ]
  }
}
  • 還可以配置使用linter設置報告錯誤的方式
{
  "compilerOptions": {
    "plugins": [
      {
        "name": "typescript-styled-plugin",
        "lint": {
          "vendorPrefix": "error",
          "zeroUnits": "ignore"
        }
      }
    ]
  }
}
  • 支持以下選項
    • 注釋:略,需要eslint基礎

Emmet in completion list

  • 已經默認包括Emmet的輸入提醒
  • 疑問:在TS中似乎有問題,需要通過Ctrl+Space顯示輸入提醒
  • 支持以下選項
    • 注釋:略,需要Emmet基礎


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM