惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Vercel News
Vercel News
Recorded Future
Recorded Future
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
The GitHub Blog
The GitHub Blog
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Google DeepMind News
Google DeepMind News
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Microsoft Azure Blog
Microsoft Azure Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
M
MIT News - Artificial intelligence
云风的 BLOG
云风的 BLOG
Y
Y Combinator Blog
N
News | PayPal Newsroom
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Help Net Security
Help Net Security
博客园 - Franky
SecWiki News
SecWiki News
Recent Announcements
Recent Announcements
T
Troy Hunt's Blog
The Register - Security
The Register - Security
The Last Watchdog
The Last Watchdog
Webroot Blog
Webroot Blog
S
Security Affairs
博客园 - 司徒正美
S
Schneier on Security
I
InfoQ
博客园_首页
www.infosecurity-magazine.com
www.infosecurity-magazine.com
T
Threat Research - Cisco Blogs
Forbes - Security
Forbes - Security
腾讯CDC
N
Netflix TechBlog - Medium
N
News and Events Feed by Topic
Cloudbric
Cloudbric
T
The Exploit Database - CXSecurity.com
P
Proofpoint News Feed
A
About on SuperTechFans
Engineering at Meta
Engineering at Meta
Recent Commits to openclaw:main
Recent Commits to openclaw:main
B
Blog
V
Vulnerabilities – Threatpost
C
Check Point Blog
Google DeepMind News
Google DeepMind News
Google Online Security Blog
Google Online Security Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
Hacker News - Newest:
Hacker News - Newest: "LLM"
C
Cisco Blogs
Schneier on Security
Schneier on Security
O
OpenAI News
K
Kaspersky official blog

博客园 - 金色海洋(jyk)

【vue3】详解单向数据流,大家千万不用为了某某而某某了。 Vue3.3 的新功能的体验(下):泛型组件(Generic Component) 与 defineSlots Vue3.3 的新功能的一些体验 Vue3实现组件级基类的几种方法 【摸鱼神器】UI库秒变低代码工具——表单篇(二)子控件 【摸鱼神器】UI库秒变低代码工具——表单篇(一)设计 用Typescript 的方式封装Vue3的表单绑定,支持防抖等功能。 【摸鱼神器】UI库秒变LowCode工具——列表篇(二)维护json的小工具 【摸鱼神器】UI库秒变LowCode工具——列表篇(一)设计与实现 【摸鱼神器】一次搞定 vue3的 路由 + 菜单 + tabs 被迫开始学习Typescript —— vue3的 props 与 interface 被迫开始学习Typescript —— class 被迫开始学习Typescript —— interface 结合 Vuex 和 Pinia 做一个适合自己的状态管理 nf-state 一篇文章说清 webpack、vite、vue-cli、create-vue 的区别 简单了解一下pinia的结构 nf-Press —— 在线文档也可以加载组件和编写代码 vite2 打包的时候vendor-xxx.js文件过大的解决方法 基于 vite2 + Vue3 写一个在线帮助文档工具
从 jQuery 到 Vue3 的快捷通道
金色海洋(jyk) · 2022-05-01 · via 博客园 - 金色海洋(jyk)

当初使用 jQuery 做了几个简单的项目,算是有一点点了解,现在学习Vue3,发现了一个可以快速转换思维的通道 —— 使用CDN的方式模拟 Vite 建立的项目!

CDN方式

jQuery的使用非常方便,用 script 引入 js文件即可,然后找到DOM即可开始操作。
而 Vue3 也支持直接用 script 引入的方式,然后使用插值的方式绑定数据,我们来看一下使用方法:

  • 引入 vue.js
  <head>
    <meta charset="UTF-8" />
    <!--加载 vue3 -->
    <script src="https://unpkg.com/vue@3.2.33/dist/vue.global.js"></script>
    <!--加载 element-plus -->
    <script src="https://unpkg.com/element-plus@2.1.9/dist/index.full.js"></script>
    <link href="https://unpkg.com/element-plus@2.1.9/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的特点,可以作为一种过渡方式。

目录结构

CDN目录.png

可以发现和 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/axios@0.26.1/dist/axios.min.js"></script>
    <!--加载 vue3 -->
    <script src="https://unpkg.com/vue@3.2.33/dist/vue.global.js"></script>
    <!--加载 vue-router -->
    <script src="https://unpkg.com/vue-router@4.0.14/dist/vue-router.global.js"></script>
    <!--加载 pinia -->
    <script src="https://unpkg.com/vue-demi@0.12.5/lib/index.iife.js"></script>
    <script src="https://unpkg.com/pinia@2.0.13/dist/pinia.iife.js"></script>
    <!--加载 element-plus -->
    <script src="https://unpkg.com/element-plus@2.1.9/dist/index.full.js"></script>
    <link href="https://unpkg.com/element-plus@2.1.9/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)
      }
    })
  })
}