基于Strview.js項目腳手架StrviewApp是怎么搭建起來的?
前言
前幾天,因為借著看源碼的熱乎勁,搞了一個玩具Js庫Strview.js。為什么會搞這么一個玩具庫呢?其實也不全是因為晚上閑的沒事,主要還是想通過實操來鍛煉自己的開發(fā)能力。之前,我也寫過一篇文章,那篇文章只是大體介紹了一下,沒有深究。之前大家可能覺得它跟Vue.js差不多,是的,正是借鑒Vue.js的思想,但是有些地方還是不一樣(個人覺得)。所以,今天,這篇文章介紹基于Strview.js搭建的項目腳手架工具StrviewApp。如果你覺得對自己有用,可以繼續(xù)看下去。如果覺得這篇肯定是篇垃圾文章,你也可以避而遠之。好了,我們現(xiàn)在就進去正題。準備好了嗎?一起跟我來吧!
快速上手StrviewAPP
你可以通過StrviewCLI快速初始化StrviewAPP項目,你可以這樣:
全局安裝。
- npm i strview-cli -g
安裝完成之后,你可以查看版本。
- strview-cli -v
最后,就是初始化項目了,
- strview-cli init <projectName>
or
- strview-cli i <projectName>
這樣,一個StrviewAPP項目就這么搭建完成了。
StrviewAPP項目結(jié)構(gòu)
下圖就是StrviewAPP項目組織結(jié)構(gòu)。
下面,我將介紹每個文件及文件夾的作用。
- config
這個是webpack配置文件夾,關(guān)于webpack的配置都在這配置。文件夾中里面有如下三個文件,分別如下:
- - webpack.base.js // 基礎(chǔ)配置
- - webpack.dev.js // 開發(fā)環(huán)境配置
- - webpack.pro.js // 生產(chǎn)環(huán)境配置
- public
資源文件夾。
- - favicon.ico // 網(wǎng)站標識
- - index.html // 模板文件
- .gitignore
哪些文件不需要添加到版本管理中。
- .prettierrc
Prettier 規(guī)則配置文件。
- package.json
定義了這個項目所需要的各種模塊,以及項目的配置信息(比如名稱、版本、許可證等元數(shù)據(jù))。
- src
這個文件夾是StrviewAPP項目的主要文件夾,下面我們來看下這個文件夾里面到底有什么。
- - assets //存放靜態(tài)文件
- - components // 組件文件夾
- - data // 公用狀態(tài)文件夾
- - methods // 方法文件夾
- - style // 樣式文件夾
- - template // 模板文件夾
- - App.js // 頁面入口
- - main.js // 項目入口文件
Src文件夾詳析
上面我們分析完了項目結(jié)構(gòu),那么下面我們將進一步分析Src文件夾中的文件構(gòu)成以及它們之間如何配合的。
1. main.js
首先,我們看下main.js文件,這是項目入口文件,我們來看下文件中的內(nèi)容。
- import { createView } from 'strview';
- import data from './data';
- import App from './App';
- import methods from './methods';
- createView({
- el: "#app",
- template: App,
- data
- });
- // The event is handled after the createview API
- methods();
我們先引入了strview.js,導入createView這個API用于創(chuàng)建視圖。那么,我們我們跳到下面看下這個API是怎么使用的。首先我們傳入一個對象字面量,第一個屬性是el屬性,它是掛載的DOM節(jié)點。第二個屬性是template屬性,它是用于顯示視圖的模板。第三個屬性是data屬性,傳入值為顯示的數(shù)據(jù)。最后,我們看到有這么一行注釋The event is handled after the createview API,意思是事件方法必須要在createViewAPI之后調(diào)用,即這里的methods();。
2. App.js
上面說到,App.js用與顯示視圖的模板,那么下面我們來看下。
- import myParagraph from './components/myParagraph';
- import card from './components/card';
- import helloTemplate from './template/helloTemplate';
- import './style/index.css';
- const App = `
- ${helloTemplate}
- <div class="content">
- <button class="color-red">點擊</button>
- <p class="txt">{a},,(a和b都改變)</p>
- <ul class="list">
- <li>{age}</li>
- <li>{name}</li>
- <li>{msg}</li>
- </ul>
- <p class="txt">{a},(a會改變)</p>
- <p class="txt">,(b會改變)</p>
- <input value="{msg}"></input>
- <p>{obj.a.b}</p>
- <p>{arr}</p>
- <p>{ob.name}</p>
- </div>
- ${myParagraph}
- ${card}<my-card><span slot="my-card-txt"></span></my-card>
- `
- export default App
我們看到在代碼的末尾導出了一個模板字符串,也就是常量App。我們可以看到模板字符串中都是些類似標簽語句的代碼。是的,這也是Strview.js的關(guān)鍵之處,使用含有類似標簽語句的模板字符串來構(gòu)建視圖。
另外,我們看到頂部除了引入樣式文件,還從components文件夾引入了兩個文件,template文件夾中引入了一個文件。我們從前面目錄結(jié)構(gòu)知道,components文件夾存放的是組件,而template文件夾存放的是模板文件。如何將導入模板與組件呈現(xiàn)到頁面上呢?那么就需要在模板字符串中使用${}占位符。在這里你可能會感到很困惑,因為沒有看到這些文件中什么內(nèi)容,不過不要著急,我們慢慢來。你在這里只需要記住它們在這里占位就可以了。
你可能會看到
最后,我們在標簽中都會發(fā)現(xiàn)類似這種{}符號,它是用來掛載數(shù)據(jù)的,也就是為了動態(tài)更新數(shù)據(jù)的。數(shù)據(jù)這塊我們后面再細講。
3. template
上面說到,這個文件夾是存放模板文件的,我們就一探究竟。
- - helloTemplate.css
- - helloTemplate.js
helloTemplate.css樣式文件沒有什么好說的。
- .container {
- text-align: center;
- margin-top: 100px;
- line-height: 46px;
- }
- .container > img {
- margin-bottom: 40px;
- }
helloTemplate.js我們來看下這個js文件。
- import logo from '../assets/logo.png';
- import './helloTemplate.css';
- export default `
- <div class="container">
- <img src="${logo}"/>
- <h1>Hello Strview.js</h1>
- </div>
- `;
在上面代碼中可以看到我們頭部引入了一個圖片還有一個樣式文件,下面接著導出了一個模板字符串。引入的圖片呢!使用${}占位符來綁定到img標簽上。
簡單介紹下template文件夾之后,我們下面看下components文件夾。
4. components
這個文件夾的是存放組件的,組件這個概念大家可能非常熟悉,在目前Vue、React這些前端框架中都有相應(yīng)的應(yīng)用。
我們先來看下這個文件夾的目錄結(jié)構(gòu)。
- - card.js
- - myParagraph.js
可以看到,有兩個js文件。
先看myParagraph.js這個文件。
- customElements.define('my-paragraph',
- class extends HTMLElement {
- constructor() {
- super();
- const template = document.getElementById('my-paragraph');
- const templateContent = template.content;
- this.attachShadow({ mode: 'open' }).appendChild(
- templateContent.cloneNode(true)
- );
- }
- }
- );
- const myParagraph = `<template id="my-paragraph">
- <style>
- p {
- color: white;
- background-color: #666;
- padding: 5px;
- }
- </style>
- <p>
- <slot name="my-text">My default text</slot>
- </p>
- </template>
- <my-paragraph>
- <span slot="my-text">Let's have some different text!</span>
- </my-paragraph>
- <my-paragraph>
- <ul slot="my-text">
- <li>Let's have some different text!</li>
- <li>In a list!</li>
- </ul>
- </my-paragraph>`
- export default myParagraph
我們先看上一部分,customElements對象下有一個define方法。這是什么方法呢?其實這部分利用了Web Components。它是什么呢?我們在MDN這樣定義它的。
Web Components 是一套不同的技術(shù),允許您創(chuàng)建可重用的定制元素(它們的功能封裝在您的代碼之外)并且在您的web應(yīng)用中使用它們。
Web Components拆開來講其實也挺復雜,我們在這里就不詳細分析了。以下是MDN網(wǎng)址,大家可以跟著做幾個例子。
- https://developer.mozilla.org/zh-CN/docs/Web/Web_Components
我們在這里是需要知道define方法第一個參數(shù)需要傳一個自定義標簽名,第二個參數(shù)是傳入一個類。需要自定義的地方是第一個參數(shù)與第二個參數(shù)中g(shù)etElementById()方法中的參數(shù),推薦使用相同的字符串。
調(diào)用define方法完成后,你需要在下面模板字符串中首先要使用template標簽包裹起來,你可以理解成初始化。我們可以看到在template標簽上有一個id選擇器與上面的getElementById()方法中的參數(shù)一樣。是的,這地方必須一一對應(yīng)。另外,我們看到緊接著下面有一個style標簽,這是定義組件樣式的。最后就是組件的內(nèi)容了。這里定義了一個p標簽,里面是一個插槽,定義了一個name屬性。并且這里有一個標簽文本,這個文本內(nèi)容是默認顯示的,如果組件中沒有內(nèi)容,則這個內(nèi)容就會默認顯示。
- <template id="my-paragraph">
- <style>
- p {
- color: white;
- background-color: #666;
- padding: 5px;
- }
- </style>
- <p>
- <slot name="my-text">My default text</slot>
- </p>
- </template>
我們接著看下面代碼,它們都是用
- <my-paragraph>
- <span slot="my-text">Let's have some different text!</span>
- </my-paragraph>
- <my-paragraph>
- <ul slot="my-text">
- <li>Let's have some different text!</li>
- <li>In a list!</li>
- </ul>
- </my-paragraph>
分析完了myParagraph.js文件,我們接著分析card.js文件。
其實與myParagraph.js文件一樣,只不過它是負責定義組件。在上面的App.js中,我們提到我們需要在自定義組件前使用一個占位符${},如這里的${card},card是引入的組件,就是指的它。
- customElements.define('my-card',
- class extends HTMLElement {
- constructor() {
- super();
- const template = document.getElementById('my-card');
- const templateContent = template.content;
- this.attachShadow({ mode: 'open' }).appendChild(
- templateContent.cloneNode(true)
- );
- }
- }
- );
- const card = `<template id="my-card">
- <style>
- div {
- color: #333;
- background-color: #f4f4f4;
- padding: 5px;
- }
- </style>
- <div>
- <slot name="my-card-txt"></slot>
- </div>
- </template>
- `
- export default card
5. data
這個文件夾是負責存放數(shù)據(jù)狀態(tài)的文件,里面主要有這兩個文件。
- - index.js
- - ob.js
我們先來看下index.js文件,非常簡單,就是單純的導出一個對象,另外ob.js文件也是。
index.js
- import ob from './ob';
- export default {
- a: "Hello",
- b: 18,
- name: "maomin",
- age: 9,
- msg: 'Strview',
- arr: ['0'],
- obj: {
- a: {
- b: 1
- }
- },
- ob
- }
ob.js
- export default {
- name: 'kk'
- }
6. methods
我們在main.js文件中中提到一點。
- import methods from './methods';
- // The event is handled after the createview API
- methods();
就是調(diào)用這個方法。那么,我們下面看下這個methods文件夾,我們知道這個文件夾的作用是提供事件處理方法的。它的目錄結(jié)構(gòu)如下:
- - index.js
- - item.js
先來看下item.js這個文件。
- import { reactive, ref } from 'strview'
- function executes() {
- reactive().obj.a.b = 3;
- ref().name = 'Strview.js';
- }
- function useItem() {
- ref().b = 100;
- }
- export {
- executes,
- useItem
- }
我們可以看到在頭部引入了兩個方法,reactive、ref這兩個方法前者負責處理復雜類型的數(shù)據(jù),如數(shù)組、嵌套對象,后者處理簡單類型的數(shù)據(jù),如單一對象、原始值。可以看到在上面代碼我們通過調(diào)用reactive()、ref()這兩個方法來實現(xiàn)數(shù)據(jù)的響應(yīng)式,然后導出這兩個executes()、useItem()方法。
接著,我們來看下index.js文件。
- import { eventListener } from 'strview';
- import { executes, useItem } from './item';
- const eventList = [
- ['.color-red', 'click', executes],
- ['.list>li:nth-child(2)', 'click', useItem]
- ]
- function methods() {
- for (let index = 0; index < eventList.length; index++) {
- const element = eventList[index];
- eventListener(...element);
- }
- }
- export default methods
我們首先在文件頂部引入了一個eventListener方法,然后接著從item文件夾引入的之前導出的兩個方法。通過定義一個數(shù)組,來不斷地循環(huán)調(diào)用eventListener方法。最后導出methods方法。
7. style
這個是存放樣式的文件,不過多介紹了。
index.css
- * {
- margin: 0;
- padding: 0;
- font-family: Avenir, Helvetica, Arial, sans-serif;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
- }
- .content {
- text-align: center;
- margin-top: 50px;
- }
8. assets
這個文件夾存放的是靜態(tài)資源,比如圖片之類的資源。
項目啟動
1.初始化安裝依賴
- yarn install
OR
- npm run start
2.啟動項目
- yarn build
OR
- npm run start
3.打包部署
- yarn build
OR
- npm run build
項目一覽
結(jié)語
謝謝你的閱讀!
這個腳手架相比于現(xiàn)在熱門的前端框架中的腳手架肯定是沒有可比性,可以當做是玩具吧!也可以當做自己看源碼之后自己的一些感悟吧!