之前,我有提到過,當(dāng)然大家肯定也都知道,Vue3.0不在有webpack.config.js的配置;但是不可避免,在項(xiàng)目開發(fā)中我們肯定會存在一些特殊的需求需要調(diào)整webpack, 這個(gè)時(shí)候,在Vue3.0的項(xiàng)目當(dāng)中,我們就需要在根目錄創(chuàng)建vue.config.js去完成webpack的一些特殊配置,默認(rèn)它會被 @vue/cli-service 自動加載。
此刻,你需要?jiǎng)?chuàng)建vue.config.js文件。
Vue CLI 官方文檔:vue-cli-service 暴露了 inspect 命令用于審查解析好的 webpack 配置。那個(gè)全局的 vue 可執(zhí)行程序同樣提供了 inspect 命令,這個(gè)命令只是簡單的把 vue-cli-service``inspect 代理到了你的項(xiàng)目中。
被抽象化的webpack,我們要想去理解它默認(rèn)的一些配置的話是比較困難的,所以我們可以通過指令去查看。
該指令會將webpack的配置輸出到output.js文件,這樣方便去查看。
vue inspect > output.js
復(fù)制代碼
復(fù)制代碼
這個(gè)文件導(dǎo)出了一個(gè)包含了選項(xiàng)的對象:
module.exports={
// 選項(xiàng)...
}
復(fù)制代碼
復(fù)制代碼
接下來,詳細(xì)介紹一些選項(xiàng)及配置:
module.exports={
productionSourceMap: false,
publicPath: './',
outputDir: 'dist',
assetsDir: 'assets',
devServer: {
port: 8090,
host: '0.0.0.0',
https: false,
open: true
},
// 其他配置
...
復(fù)制代碼
復(fù)制代碼
在vue.config.js如果要新增/修改 webpack 的 plugins 或者 rules , 有2種方式。
configureWebpack 是相對比較簡單的一種方式
configureWebpack: {
rules:[],
plugins: []
}
configureWebpack: (config)=> {
// 例如,通過判斷運(yùn)行環(huán)境,設(shè)置mode
config.mode='production'
}
復(fù)制代碼
復(fù)制代碼
chainWebpack 鏈?zhǔn)讲僮?(高級),接下來所有的配置我都會在該選項(xiàng)中進(jìn)行配置
關(guān)于rules 的配置,我會分別從新增/修改進(jìn)行介紹。
在webpack中 rules 是 module 的配置項(xiàng),而所有的配置的都是掛載到 config 下的,所以新增一個(gè)rule方式:
config.module
.rule(name)
.use(name)
.loader(loader)
.options(options)
復(fù)制代碼
復(fù)制代碼
module.exports={
chainWebpack: (config)=> {
// 通過 style-resources-loader 來添加less全局變量
const types=['vue-modules', 'vue', 'normal-modules', 'normal'];
types.forEach(type=> {
let rule=config.module.rule('less').oneOf(type)
rule.use('style-resource')
.loader('style-resources-loader')
.options({
patterns: [path.resolve(__dirname, './lessVariates.less')]
});
});
// `svg-sprite-loader`: 將svg圖片以雪碧圖的方式在項(xiàng)目中加載
config.module
.rule('svg')
.test(/.svg$/) // 匹配svg文件
.include.add(resolve('src/svg')) // 主要匹配src/svg
.end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader') // 使用的loader,主要要npm該插件
.options({symbolId: 'svg-[name]'}) // 參數(shù)配置
}
}
復(fù)制代碼
復(fù)制代碼
針對已經(jīng)存在的 rule , 如果需要修改它的參數(shù), 可以使用 tap 方法:
config.module
.rule(name)
.use(name)
.tap(options=> newOptions)
復(fù)制代碼
復(fù)制代碼
module.exports={
chainWebpack: (config)=> {
// `url-loader`是webpack默認(rèn)已經(jīng)配置的,現(xiàn)在我們來修改它的參數(shù)
config.module.rule('images')
.use('url-loader')
.tap(options=> ({
name: './assets/images/[name].[ext]',
quality: 85,
limit: 0,
esModule: false,
}))
}
}
復(fù)制代碼
復(fù)制代碼
關(guān)于 plugins 的配置,我會分別從新增/修改/刪除進(jìn)行介紹。
config
.plugin(name)
.use(WebpackPlugin, args)
復(fù)制代碼
復(fù)制代碼
const HotHashWebpackPlugin=require('hot-hash-webpack-plugin');
module.exports={
chainWebpack: (config)=> {
// 新增一個(gè)`hot-hash-webpack-plugin`
// 注意:這里use的時(shí)候不需要使用`new HotHashWebpackPlugin()`
config.plugin('hotHash')
.use(HotHashWebpackPlugin, [{ version: '1.0.0' }]);
}
}
復(fù)制代碼
復(fù)制代碼
同理, plugin 參數(shù)的修改也是通過 tap 去修改。
config
.plugin(name)
.tap(args=> newArgs)
復(fù)制代碼
復(fù)制代碼
const HotHashWebpackPlugin=require('hot-hash-webpack-plugin');
module.exports={
chainWebpack: (config)=> {
// 修改打包時(shí)css抽離后的filename及抽離所屬目錄
config.plugin('extract-css')
.tap(args=> [{
filename: 'css/[name].[contenthash:8].css',
chunkFilename: 'css/[name].[contenthash:8].css'
}]);
// 正式環(huán)境下,刪除console和debugger
config.optimization
.minimize(true)
.minimizer('terser')
.tap(args=> {
let { terserOptions }=args[0];
terserOptions.compress.drop_console=true;
terserOptions.compress.drop_debugger=true;
return args
});
}
}
復(fù)制代碼
復(fù)制代碼
對于一些webpack默認(rèn)的 plugin ,如果不需要可以進(jìn)行刪除
config.plugins.delete(name)
復(fù)制代碼
復(fù)制代碼
module.exports={
chainWebpack: (config)=> {
// vue-cli3.X 會自動進(jìn)行模塊分割抽離,如果不需要進(jìn)行分割,可以手動刪除
config.optimization.delete('splitChunks');
}
}
復(fù)制代碼
復(fù)制代碼
webpack 默認(rèn)的 entry 入口是 scr/main.ts
config.entryPoints.clear(); // 清空默認(rèn)入口
config.entry('test').add(getPath('./test/main.ts')); // 重新設(shè)置
復(fù)制代碼
復(fù)制代碼
定義全局全局變量,DefinePlugin 是 webpack 已經(jīng)默認(rèn)配置的,我們可以對參數(shù)進(jìn)行修改
config.plugin('define').tap(args=> [{
...args,
"window.isDefine": JSON.stringify(true),
}]);
復(fù)制代碼
復(fù)制代碼
自定義打包后js文件的路徑及文件名字
config.output.filename('./js/[name].[chunkhash:8].js');
config.output.chunkFilename('./js/[name].[chunkhash:8].js');
復(fù)制代碼
復(fù)制代碼
html-webpack-plugin 是 webpack 已經(jīng)默認(rèn)配置的,默認(rèn)的源模版文件是 public/index.html ;我們可以對其參數(shù)進(jìn)行修改
config.plugin('html')
.tap(options=> [{
template: '../../index.html' // 修改源模版文件
title: 'test',
}]);
復(fù)制代碼
復(fù)制代碼
webpack默認(rèn)是將src的別名設(shè)置為@, 此外,我們可以進(jìn)行添加
config.resolve.alias
.set('@', resolve('src'))
.set('api', resolve('src/apis'))
.set('common', resolve('src/common'))
復(fù)制代碼
復(fù)制代碼
、MVVM簡介
如果你是第一次學(xué)前端,那么本節(jié)知識一定要了解,什么是MVVM。
MVVM是Model-View-ViewModel的簡寫。它本質(zhì)上就是MVC 的改進(jìn)版。MVVM 就是將其中的View 的狀態(tài)和行為抽象化,讓我們將視圖 UI 和業(yè)務(wù)邏輯分開。當(dāng)然這些事 ViewModel 已經(jīng)幫我們做了,它可以取出 Model 的數(shù)據(jù)同時(shí)幫忙處理 View 中由于需要展示內(nèi)容而涉及的業(yè)務(wù)邏輯。MVVM的核心是ViewModel層,負(fù)責(zé)轉(zhuǎn)換Model中的數(shù)據(jù)對象來讓數(shù)據(jù)變得更容易管理和使用。是一種簡化用戶界面的事件驅(qū)動編程方式。
下邊我們來畫張圖來大體了解下MVVM的工作原理圖:
該層向上與視圖層進(jìn)行雙向數(shù)據(jù)綁定
向下與Model層通過接口請求進(jìn)行數(shù)據(jù)交互
(1)View
View是視圖層, 也就是用戶界面。前端主要由HTH L和csS來構(gòu)建, 為了更方便地展現(xiàn)vi eu to del或者Hodel層的數(shù)據(jù), 已經(jīng)產(chǎn)生了各種各樣的前后端模板語言, 比如FreeMarker,Thyme leaf等等, 各大MV VM框架如Vue.js.Angular JS, EJS等也都有自己用來構(gòu)建用戶界面的內(nèi)置模板語言。
(2)Model
Model是指數(shù)據(jù)模型, 泛指后端進(jìn)行的各種業(yè)務(wù)邏輯處理和數(shù)據(jù)操控, 主要圍繞數(shù)據(jù)庫系統(tǒng)展開。這里的難點(diǎn)主要在于需要和前端約定統(tǒng)一的接口規(guī)則
(3)ViewModel
ViewModel是由前端開發(fā)人員組織生成和維護(hù)的視圖數(shù)據(jù)層。在這一層, 前端開發(fā)者對從后端獲取的Model數(shù)據(jù)進(jìn)行轉(zhuǎn)換處理, 做二次封裝, 以生成符合View層使用預(yù)期的視圖數(shù)據(jù)模型。
View Model所封裝出來的數(shù)據(jù)模型包括視圖的狀態(tài)和行為兩部分, 而Model層的數(shù)據(jù)模型是只包含狀態(tài)的
視圖狀態(tài)和行為都封裝在了View Model里。這樣的封裝使得View Model可以完整地去描述View層。由于實(shí)現(xiàn)了雙向綁定, View Model的內(nèi)容會實(shí)時(shí)展現(xiàn)在View層, 這是激動人心的, 因?yàn)榍岸碎_發(fā)者再也不必低效又麻煩地通過操縱DOM去更新視圖。 MVVM框架已經(jīng)把最臟最累的一塊做好了, 我們開發(fā)者只需要處理和維護(hù)View Model, 更新數(shù)據(jù)視圖就會自動得到相應(yīng)更新,真正實(shí)現(xiàn)事件驅(qū)動編程。 View層展現(xiàn)的不是Model層的數(shù)據(jù), 而是ViewModel的數(shù)據(jù), 由ViewModel負(fù)責(zé)與Model層交互, 這就完全解耦了View層和Model層, 這個(gè)解耦是至關(guān)重要的, 它是前后端分離方案實(shí)施的重要一環(huán)。
2、為什么要使用MVVM
MVVM模式和MVC模式一樣,主要目的是分離視圖(View)和模型(Model),有幾大優(yōu)點(diǎn)
(1) 低耦合。視圖(View)可以獨(dú)立于Model變化和修改,一個(gè)ViewModel可以綁定到不同的"View"上,當(dāng)View變化的時(shí)候Model可以不變,當(dāng)Model變化的時(shí)候View也可以不變。
(2) 可重用性。你可以把一些視圖邏輯放在一個(gè)ViewModel里面,讓很多view重用這段視圖邏輯。
(3)獨(dú)立開發(fā)。開發(fā)人員可以專注于業(yè)務(wù)邏輯和數(shù)據(jù)的開發(fā)(ViewModel),設(shè)計(jì)人員可以專注于頁面設(shè)計(jì),使用Expression Blend可以很容易設(shè)計(jì)界面并生成xaml代碼。
(4)可測試。界面素來是比較難于測試的,測試可以針對ViewModel來寫
3、VUE概述
(1)什么是vue?
Vue是一套用于構(gòu)建用戶界面的漸進(jìn)式框架。與其它大型框架不同的是,Vue 被設(shè)計(jì)為可以自底向上逐層應(yīng)用。Vue 的核心庫只關(guān)注視圖層,不僅易于上手,還便于與第三方庫或既有項(xiàng)目整合
這是官網(wǎng)給出的介紹,可能不是那么容易理解。簡單來說,Vue是一個(gè)視圖層框架,幫助我們更好的構(gòu)建應(yīng)用。
使用Vue和原生JS一個(gè)最顯著的差別就是,Vue不再對DOM直接進(jìn)行操作,而是通過對數(shù)據(jù)的操作,來改變頁面。使用Vue構(gòu)建的頁面,是有一個(gè)個(gè)的組件組成的,當(dāng)組件中定義的數(shù)據(jù)發(fā)生變化時(shí),組件的顯示也會跟著變化,且此過程無需刷新頁面。
(2)MVVM模式的實(shí)現(xiàn)者
Model:模型層, 在這里表示JavaScript對象 View:視圖層, 在這里表示DOM(HTML操作的元素) ViewModel:連接視圖和數(shù)據(jù)的中間件, Vue.js就是MVVM中的View Model層的實(shí)現(xiàn)者 在MVVM架構(gòu)中, 是不允許數(shù)據(jù)和視圖直接通信的, 只能通過ViewModel來通信, 而View Model就是定義了一個(gè)Observer觀察者
ViewModel能夠觀察到數(shù)據(jù)的變化, 并對視圖對應(yīng)的內(nèi)容進(jìn)行更新 ViewModel能夠監(jiān)聽到視圖的變化, 并能夠通知數(shù)據(jù)發(fā)生改變 至此, 我們就明白了, Vue.js就是一個(gè)MV VM的實(shí)現(xiàn)者, 他的核心就是實(shí)現(xiàn)了DOM監(jiān)聽與數(shù)據(jù)綁定
(3)為什么要使用Vue
易用:熟悉HTML、CSS、JavaScript之后,可快速度上手vue。學(xué)習(xí)曲線平穩(wěn)。
輕量級:Vue.js壓縮后有只有20多kb,超快虛擬DOM
高效:吸取了Angular(模塊化) 和React(虛擬DOM) 的優(yōu)勢, 并擁有自己獨(dú)特的功能
開源:文檔齊全,社區(qū)活躍度高
4、VUE之Hello World!
步驟一:創(chuàng)建空文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
</body>
</html>
步驟二:引入vue.js (本人下載的開發(fā)版的vue.js,跟本html文件放在了同一目錄下,所以直接引用)
<script type="text/javascript" src="vue.js"></script>
步驟三:創(chuàng)建vue實(shí)例
<script type="text/javascript">
var vm=new Vue({
el:'#app',
data:{
msg:'Hello World'
}
});
</script>
步驟四:數(shù)據(jù)與頁面元素綁定
<div id="app">
{{msg}}
</div>
完整的html
<!DOCTYPE html>
<html lang="en">
<body>
<div id="app">
{{msg}}
</div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript">
var vm=new Vue({
el:'#app',
data:{
msg:'Hello World'
}
});
</script>
</body>
</html>
瀏覽器打開:
參數(shù)分析:
el : '#app' -- 綁定元素的ID(元素的掛載位置,值可以是CSS選擇器或者是DOM元素)
data : { msg : 'Hello World' } -- 模型數(shù)據(jù),屬性名:msg 值:Hello World
{{msg}} : 在綁定的元素中使用{{ }}將Vue創(chuàng)建的名為msg的屬性包起來, 即可實(shí)現(xiàn)數(shù)據(jù)綁定功能,我們在調(diào)試狀態(tài)下手動修改下msg的值,在不刷新頁面的情況下就會展示我們修改后的值,這就是借助了Vue的數(shù)據(jù)綁定功能實(shí)現(xiàn)的。 MV VM模式中要求View Model層就是使用觀察者模式來實(shí)現(xiàn)數(shù)據(jù)的監(jiān)聽與綁定, 以做到數(shù)據(jù)與視圖的快速響應(yīng)
下一篇:VUE入門教程(二)之模板語法(指令)
信小程序開發(fā)過程中,許多開發(fā)者會遇到 小程序 與 Web 端一起的需求,由于 小程序 與 Web 端的運(yùn)行環(huán)境不同,開發(fā)者往往需要維護(hù)兩套類似的代碼,這對開發(fā)者來說比較耗費(fèi)力氣,并且會出現(xiàn)不同步的情況。
小程序作為web的配套必需品,已經(jīng)成為開發(fā)者不可避免的工作。多終端、多形態(tài)的開發(fā)無疑徒增工作量,費(fèi)力不討好。Kbone 就是一個(gè)致力于微信小程序和 Web 端同構(gòu)的解決方案。一套代碼同時(shí)開發(fā)完微信小程序以及web端。
基本結(jié)構(gòu)
首先,我們來看下一個(gè)基本的 kbone 項(xiàng)目的目錄結(jié)構(gòu)(這里的 todo 是基于 Vue 的示例, kbone 也有 React , Preact , Omi 等版本,詳情可移步 kbone github )。
因?yàn)?kbone 是為了解決 小程序 與 Web 端的問題,所以每個(gè)目錄下的配置都會有兩份(小程序 與 Web 端各一份)
入口
不管是 小程序 端還是 Web 端,都需要入口文件。在 src/index 目錄下, main.js 為 Web 端用主入口, main.mp.js 則為 小程序 端用主入口。
當(dāng)然,Web 端會比 小程序 多一個(gè)入口頁面,即 index.html (位于根目錄下)。
下面兩段代碼分別是 小程序端 入口與 Web 端入口的代碼,可以看到 小程序端的入口代碼封裝在 createApp 函數(shù)里面(這里固定即可),內(nèi)部會比 Web 端多一個(gè)創(chuàng)建 app 節(jié)點(diǎn)的操作,其他的基本就是一致的。
todo.vue
在上面的入口圖可以看到,源碼目錄中,除了入口文件分開之前,頁面文件就是共用的了,這里直接使用 Vue 的寫法即可,不用做特殊的適應(yīng)。
配置
寫完代碼之后,我們要怎么跑項(xiàng)目呢?這時(shí),配置就派上用場啦。
Web 端配置為正常的 Vue 配置,小程序端配置與 Web 端配置的唯一不同就是需要引入 mp-webpack-plugin 插件來將 Vue 組件轉(zhuǎn)化為小程序代碼。
構(gòu)建代碼
接著,我們需要構(gòu)建代碼,讓代碼可以運(yùn)行到各自的運(yùn)行環(huán)境中去。構(gòu)建完成后,生產(chǎn)代碼會位于 dist 目錄中。
小程序端 的構(gòu)建會比 Web 端的構(gòu)建多一個(gè)步驟,就是 npm 構(gòu)建。
進(jìn)入 dist/mp 目錄,執(zhí)行 npm install 安裝依賴,用開發(fā)者工具將 dist/mp 目錄作為小程序項(xiàng)目導(dǎo)入之后,點(diǎn)擊工具欄下的 構(gòu)建 npm ,即可預(yù)覽效果。
效果
最后,我們來看一下 todo 的效果。kbone 初體驗(yàn),done~
todo 代碼可到 kbone/demo13 自提。
具體方案實(shí)現(xiàn)
接下來就來探討下具體方案的實(shí)現(xiàn)。
社區(qū) Web 端是基于 Vue 實(shí)現(xiàn)的,使用了 Vue-router、Vuex 等插件。Vue 想必大家挺熟悉的了,它是市面上一款非常流行的 Web 框架,提供組件化等特性,其原理大致如下:
Vue 模板可以認(rèn)為是一種附加了一些特殊語法的 HTML 片段,一般來說一份 Vue 模板對應(yīng)一個(gè)組件,在構(gòu)建階段編譯成調(diào)用 Dom 接口的 JS 函數(shù),調(diào)用此 JS 函數(shù)就會創(chuàng)建出組件對應(yīng)的 Dom 樹片段進(jìn)而渲染到瀏覽器上。小程序里是支持運(yùn)行 JS 的,但是這里用到的 Dom 接口和渲染到瀏覽器上的功能小程序不具備,所以無法直接將 Web 端社區(qū)代碼移植到小程序中。原因就在于小程序?yàn)榱税踩托阅芏捎昧穗p線程的架構(gòu),運(yùn)行用戶 JS 代碼的邏輯層是一個(gè)純粹的 JSCore,沒有任何瀏覽器相關(guān)的實(shí)現(xiàn),這里得想辦法將 Web 端代碼轉(zhuǎn)成小程序代碼。
業(yè)界常見做法:將 Vue 模板直接轉(zhuǎn)成小程序的 WXML 模板
那么問題來了,如何將 Vue 代碼轉(zhuǎn)成小程序代碼?這里先看下業(yè)界常見的做法:將 Vue 模板直接轉(zhuǎn)成小程序的 WXML 模板。
使用做法相當(dāng)于拋棄了瀏覽器中建 Dom 樹的過程,而是直接交由小程序來對模板進(jìn)行編譯創(chuàng)建出小程序的模板樹,進(jìn)而渲染到小程序頁面中。
一般來說這個(gè)做法對于普通場景是夠用的,但是對于一些更復(fù)雜的場景就很不好處理了,比如社區(qū)中的一個(gè)簡單例子:社區(qū)帖子詳情展示富文本內(nèi)容,點(diǎn)擊內(nèi)容中的圖片可預(yù)覽。
這主要是因?yàn)?Vue 模板和 WXML 模板的語法并不是直接對等的,Vue 的特性設(shè)計(jì)也和小程序的設(shè)計(jì)無法劃等號,這自然就導(dǎo)致了部分 Vue 特性的丟失。比如像 Vue 中的 v-html 指令、ref 獲取 Dom 節(jié)點(diǎn)、過濾器等就通通用不了。當(dāng)然不止是 Vue 自身的特性,一些原本依賴 Dom/Bom 接口的 Vue 插件也無法使用,比如 Vue-router 等,而這些正是社區(qū)高度依賴的,在不對社區(qū)代碼做大范圍改造的話是無法使用此方案的。
此路不通,那還有其他的方法么?
換個(gè)思路:做一個(gè)適配層
答案是有的,這里我們就得換一種思路來解決這個(gè)問題。回到最初的點(diǎn)上,我們無法將 Web 端代碼移植到小程序中是因?yàn)樾〕绦驔]有 Dom 接口,那么我們想辦法做出一個(gè)適配層,將這個(gè)差異給抹掉不就行了么?
有了想法就要實(shí)施,仿造出 Dom 接口并不難,事實(shí)上在 Nodejs 端就有人做過類似的事,比如 jsDom 這個(gè)庫的實(shí)現(xiàn),讓我們可以在沒有真實(shí)瀏覽器環(huán)境下可以對一些依賴 Dom 接口的 Web 端代碼進(jìn)行測試。
仿造了 Dom 接口給 Vue 調(diào)用,進(jìn)而創(chuàng)建出了仿造 Dom 樹。根據(jù)前面提到的小程序架構(gòu),用戶的 JS 代碼是執(zhí)行在邏輯層的,也就是說我們創(chuàng)建出的 Dom 樹也是存在與邏輯層的內(nèi)存之中,接下來要解決的難題是如何將這棵 Dom 樹渲染到小程序頁面中。
這里需要先簡單介紹一下小程序的渲染原理:小程序的雙線程架構(gòu),邏輯層會執(zhí)行用戶的 JS 代碼進(jìn)而產(chǎn)生一組數(shù)據(jù),這組數(shù)據(jù)會發(fā)往視圖層;視圖層接收到數(shù)據(jù)后,結(jié)合用戶的 WXML 模板創(chuàng)建出組件樹,之后小程序再將組件樹渲染出來。這里的組件樹和 Dom 樹很類似,只是它是由官方內(nèi)置組件或自定義組件拼接而成而不是 Dom 節(jié)點(diǎn)。這里我們能不能將仿造出來的 Dom 樹映射到小程序的組件樹上?
小程序組件樹是根據(jù) WXML 模板創(chuàng)建出來的,而仿造 Dom 樹結(jié)構(gòu)是不穩(wěn)定的,我們無法提前預(yù)知它會生成什么樣的結(jié)構(gòu),也就無法提前準(zhǔn)備后可以描述任意 Dom 樹的 WXML 模板,除非直接將 Vue 模板轉(zhuǎn)換成 WXML 模板,但這樣又繞回前面的問題上了。
小程序組件樹中的組件有兩種:內(nèi)置組件和自定義組件,內(nèi)置組件是由官方提供的如 video、map 這樣的組件,而自定義組件是一種支持由用戶利用現(xiàn)有組件自行組裝的組件,能否利用它來做些什么?
使用 Web 端概念來做個(gè)簡單解釋,內(nèi)置組件就像是 div、span 這些 HTML 標(biāo)簽,而自定義組件就像是 Web 中的 Vue 組件。Vue 組件可以將 HTML 標(biāo)簽以及其他的 Vue 組件進(jìn)行組裝,自定義組件同理,主要用于功能模塊的抽象、封裝和復(fù)用。不過自定義組件有個(gè)很奇妙的特性,它支持自引用,也就是說它可以自己引用自己來進(jìn)行組裝。
自定義組件可以自己引用自己,那么我們就可以利用這個(gè)特性來進(jìn)行遞歸創(chuàng)建組件,進(jìn)而創(chuàng)建出一棵組件樹:
比如上圖的例子,我們封裝了一個(gè) custom-dom 組件,這個(gè)組件里面也使用了 custom-dom 組件用于渲染子組件。那么只要我們執(zhí)行一下 setData,把 children 數(shù)據(jù)傳遞過去就可以創(chuàng)建出子組件,子組件本身也是 custom-dom 組件,它同樣可以執(zhí)行這個(gè)邏輯把各自的子組件創(chuàng)建出來,這樣就實(shí)現(xiàn)了組件的遞歸創(chuàng)建,只要我們擁有完整的 Dom 樹結(jié)構(gòu),就可以創(chuàng)建出相對應(yīng)的一棵組件樹。
這里遞歸的終止條件是遇到特定節(jié)點(diǎn)、文本節(jié)點(diǎn)或者孩子節(jié)點(diǎn)為空。然后在創(chuàng)建出組件樹后,將 Dom 節(jié)點(diǎn)和自定義組件實(shí)例進(jìn)行綁定以便后續(xù)的 Dom 更新和操作即可。
我們將其歸納為兩個(gè)模塊:仿造接口和自定義組件。正因?yàn)檫@個(gè)方案是通過提供適配器的方式來仿造出 Web 環(huán)境,所以用戶代碼不需要做任何魔改,大部分特性都可以繼續(xù)使用不需要被刪減,比如 vue-router、window.location 操作等。
原本 Web 端代碼是基于 Vue 來搭建的,其中還用到了諸多插件/庫,如 Vue-router、Vuex、Markdown-it 等,同時(shí)還支持了服務(wù)端渲染。但是不管 Web 端是怎么實(shí)現(xiàn)的,底層終究是調(diào)瀏覽器的那些接口,所以對于用戶層面的代碼我們不做任何調(diào)整,只是將瀏覽器那一層替換掉即可。
整個(gè)構(gòu)建流程是基于 Webpack 來實(shí)現(xiàn)的,使用 Kbone 構(gòu)建出小程序代碼也是基于 Webpack 來實(shí)現(xiàn),只需要在原本 Web 端構(gòu)建流程上實(shí)現(xiàn)一個(gè) Webpack 插件,在構(gòu)建原本 Web 端代碼到小程序端時(shí)追加 Kbone 和一些小程序相關(guān)的代碼即可
*請認(rèn)真填寫需求信息,我們會在24小時(shí)內(nèi)與您取得聯(lián)系。