當初使用 jQuery 做了幾個簡單的項目,算是有一點點瞭解,現在學習Vue3,發現了一個可以快速轉換思維的通道 —— 使用CDN的方式模擬 Vite 建立的項目! CDN方式 jQuery的使用非常方便,用 script 引入 js文件即可,然後找到DOM即可開始操作。 而 Vue3 也支持直接用 ...
當初使用 jQuery 做了幾個簡單的項目,算是有一點點瞭解,現在學習Vue3,發現了一個可以快速轉換思維的通道 —— 使用CDN的方式模擬 Vite 建立的項目!
CDN方式
jQuery的使用非常方便,用 script 引入 js文件即可,然後找到DOM即可開始操作。
而 Vue3 也支持直接用 script 引入的方式,然後使用插值的方式綁定數據,我們來看一下使用方法:
- 引入 vue.js
<head>
<meta charset="UTF-8" />
<!--載入 vue3 -->
<script src="https://unpkg.com/[email protected]/dist/vue.global.js"></script>
<!--載入 element-plus -->
<script src="https://unpkg.com/[email protected]/dist/index.full.js"></script>
<link href="https://unpkg.com/[email protected]/dist/index.css" rel="stylesheet"/>
<title>Vue3 CDN的簡單演示</title>
</head>
這樣我們就可以在網頁裡面使用 Vue 了,另外我們引入了一個UI庫——element-plus。
- 綁定數據和事件
然後我們寫一個 hello word:
<body>
<div id="app">
<button @click="count++">自增</button> <br>
<el-button @click="count++" >自增</el-button> <br>
{{ count }}
</div>
<script>
const { ref, createApp } = Vue
const app = {
setup() {
const count = ref(0)
return {
count
}
}
}
createApp(app)
.use(ElementPlus)
.mount('#app')
</script>
</body>
-
插值
在模板裡面使用雙大括弧即可實現數據綁定。 -
事件
可以使用原生button,也可以使用UI庫提供的button,用v-on(簡寫:@)添加事件。 -
定義數據
這裡採用 composition API 的方式,使用 ref,實現簡單的計數功能。 -
掛載
使用 createApp 創建一個App,然後掛載插件、UI庫、路由、狀態等。
本篇只做簡單介紹,詳細介紹請移步官網:https://staging-cn.vuejs.org/
組件化
一個項目有很多功能,顯然不能把所有代碼都放在一起,那麼如何管理代碼呢?Vue提供了組件化的方式,便於組織代碼。
我們可以建立一個 count.js 文件(單文件組件),實現上面那個簡單的計數功能:
- count.js
const { ref } = Vue
export default {
name: 'count',
template: `
<button @click="count++">自增</button> <br>
<el-button @click="count++" >自增</el-button> <br>
{{ count }}
`
setup() {
const count = ref(0)
return {
count
}
}
}
這樣就可以建立一個單獨的Vue組件,相關的代碼都可以放在這裡,管理起來就更容易了。
工程化項目
一般我們可以用 Vite 建立一個項目,然後安裝需要的各種插件,但是這需要我們先瞭解 node、npm、yarn、vite等,還要先配置好環境,這些對於新手來說容易懵。
那麼能不能暫時跳過這些,直接建立一個工程化的項目呢?當然是可以的!
我們可以模仿 Vite 建立的項目的文件結構,用CDN的方式實現一個項目。
為啥要用CDN的方式模擬一下呢?因為這樣可以先不用瞭解node等前置知識點,可以比較清晰的看到 Vue 的運作方式,快速理解Vue的特點,可以作為一種過渡方式。
目錄結構
可以發現和 Vite 建立的項目的結構是基本一樣的,只是把.vue尾碼變成了.js尾碼。
載入各種插件
<head>
<meta charset="UTF-8" />
<link rel="icon" href="../nfwt.ico" />
<script src="src/script/appImport.js?v=1"></script>
<!--載入 axios -->
<script src="https://unpkg.com/[email protected]/dist/axios.min.js"></script>
<!--載入 vue3 -->
<script src="https://unpkg.com/[email protected]/dist/vue.global.js"></script>
<!--載入 vue-router -->
<script src="https://unpkg.com/[email protected]/dist/vue-router.global.js"></script>
<!--載入 pinia -->
<script src="https://unpkg.com/[email protected]/lib/index.iife.js"></script>
<script src="https://unpkg.com/[email protected]/dist/pinia.iife.js"></script>
<!--載入 element-plus -->
<script src="https://unpkg.com/[email protected]/dist/index.full.js"></script>
<link href="https://unpkg.com/[email protected]/dist/index.css" rel="stylesheet"/>
</head>
- pinia 狀態管理
pinia 需要載入兩個文件,一個是pinia.js,另一個是其依賴項 vue-demi,實現相容vue2的功能。
載入 main.js
main.js 是入口文件,需要在 index.html 使用 type="module"
的方式引入,這樣main裡面才可以使用“import”。
<body>
<div id="app">
這裡是CDN仿工程化開發的演示...
</div>
<script type="module" src="src/main.js"></script>
</body>
設置 main.js
然後在main裡面載入根節點、路由設置、狀態設置、UI庫等操作。
const ver = window.__ver || '?v=0'
const pinia = Pinia.createPinia()
Promise.all([
import('./app.js' + ver),
import('./router/index.js' + ver),
]).then((res) => {
Vue.createApp(res[0].default)
.use(res[1].default) // 掛載路由
.use(ElementPlus) // 載入ElementPlus
.use(pinia) // 狀態管理
.mount('#app') // 對應div
})
可以直接使用 import App from './app.js'
的方式載入,但是不好管理緩存。
所以採用了這種增加版本號的方式,以確保可以載入最新文件。
App.js
可以在 app.js 做頁面佈局,當然也可以實現其他功能。
const { ref, defineAsyncComponent } = Vue
// 載入菜單組件
const myMenu = defineAsyncComponent(() => import('./views/menu.js' + window.__ver))
export default {
name: 'app',
components: {
myMenu
},
template: `
<el-container>
<el-header>
CND的方式 模仿工程化項目
</el-header>
<el-container>
<el-aside width="200px">
<!--菜單-->
<my-menu/>
</el-aside>
<el-container>
<el-main>
<!--路由容器 -->
<router-view></router-view>
</el-main>
<el-footer>
CND的簡單演示。by Vue3、element-plus、Pinia、vue-Router
</el-footer>
</el-container>
</el-container>
</el-container>
`,
setup() {
return {
}
}
}
這裡採用非同步組件的方式載入子組件,方便設置版本號,確保可以載入最新文件。
設置路由
為了更方便的載入組件,我們可以使用 vue-router 設置路由。
// 定義路由
const routes = [
{
path: '/',
name: 'Home',
component: () => myImport('views/home')
},
{
path: '/pinia',
name: 'pinia',
component: () => myImport('views/state/pinia')
},
{
path: '/',
name: 'ui',
component: () => myImport('views/ui/ui-elp')
},
{
path: '/h',
name: 'h-test',
component: () => myImport('views/h/h')
},
{
path: '/jsx',
name: 'jsx-test',
component: () => myImport('views/h/jsx')
}
]
const base = '/cdn3/'
const router = VueRouter.createRouter({
history: VueRouter.createWebHistory(base),
routes
})
export default router
如果組件只有js文件,那麼可以直接使用 import 來載入,如果組件由js+html組成,需要使用 myImport 來載入,myImport 是我自己封裝的函數,在最後介紹。
設置菜單
我們先做一個簡單的菜單:
- menu.js
export default {
name: 'menu',
template: `
<router-link :to="{name:'Home'}">首頁</router-link><br><br>
<router-link :to="{name:'pinia'}">pinia</router-link><br><br>
<router-link :to="{name:'h-test'}">h的演示</router-link><br><br>
<router-link :to="{name:'jsx-test'}">jsx的演示</router-link><br><br>
`,
setup() {
return {
}
}
}
這裡先使用 router-link 做個簡單的連接,也可以使用 el-menu 做菜單。
狀態管理
這裡採用最新的 pinia 進行狀態管理,因為 Vuex 有點臃腫。
首先需要在 main.js 裡面掛載pinia,見 main 的部分。
然後我們建立一個js文件,定義一個狀態,再建立一個js文件作為組件。
- count.js
const { defineStore } = Pinia
const testPromie = () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(100)
}, 500)
})
}
export const useCounterStore = defineStore('counter', {
state: () => {
return { count: 0, name: '' }
},
actions: {
increment() {
this.count ++
},
async loadData(val, state) {
const foo = await testPromie()
this.count += foo
this.name = 'async 賦值:' + new Date().valueOf()
},
loadData2(val, state) {
testPromie().then((val) => {
this.count += val
this.name = '非同步賦值:' + new Date().valueOf()
})
}
}
})
- pinia.js
然後在組件裡面引入:
// 狀態
import { useCounterStore } from './count.js'
export default {
name: 'pinia-test',
setup() {
const test = useCounterStore()
return { count }
}
}
- pinia.html
我們可以把 template 部分拿出去,做成 html 文件:
<div>
測試pinia的狀態<br>
{{ test }}<br>
<el-button type="" @click="test.increment()">修改</el-button>
</div>
這樣一個簡單的項目結構就搭建起來了。
小結
本篇僅為過渡,並不是說正式項目要用這種方式開發,因為缺點也是很明顯的。
當然也是有一些優點:
- 可以更充分的利用CDN,緩存vue.js這類的變化頻率低的 js 文件,只需要更新業務相關的代碼即可。
- 如果CDN不卡的話,載入速度可以更快。
- 可以利用CDN的資源,緩解自己伺服器的壓力。
- 項目可以分模塊開發,穩定且基礎的模塊可以打包、發佈到CDN裡面使用。
源碼和演示
補充
template 部分,如果用字元串的方式寫,那麼比較麻煩,所以可以分為 html 文件的方式來寫,這樣可以使用提示、補全和驗證等功能。
然後做一個載入的函數 myImport :
window.myImport = (url) => {
return new Promise((resolve, reject) => {
const ver = window.__ver || ''
const baseUrl = window.__basrUrl || '/src/'
// 先載入 js
import(baseUrl + url + '.js' + ver).then((resjs) => {
const js = resjs.default
if (!js.template) {
// 如果模板是空的,表示需要載入 html作為模板
axios.get(baseUrl + url + '.html' + ver).then((resHTML) => {
js.template = resHTML.data
resolve(js)
})
} else {
// 否則直接使用 js 註冊組件
resolve(js)
}
})
})
}