您当前的位置:首页 > 电脑百科 > 程序开发 > 前端

vue的两种服务器端渲染方案

时间:2023-02-27 16:00:39  来源:  作者:京东云开发者

作者:京东零售 姜欣

关于服务器端渲染方案,之前只接触了基于react的Next.js,最近业务开发vue用的比较多,所以调研了一下vue的服务器端渲染方案。 首先:长文预警,下文包括了两种方案的实践,没有耐心的小伙伴可以直接跳到方案标题下,down代码体验一下。

前置知识:1、什么是服务器端渲染(ssr)?

简单来说就是用户第一次请求页面时,页面上的内容是通过服务器端渲染生成的,浏览器直接显示服务端返回的完整html就可以,加快首屏显示速度。

举个栗子:

当我们访问一个商品列表时,如果使用客户端渲染(csr),浏览器会加载空白的页面,然后下载js文件,通过js在客户端请求数据并渲染页面。如果使用服务器端渲染(ssr),在请求商品列表页面时,服务器会获取所需数据并将渲染后的HTML发送给浏览器,浏览器一步到位直接展示,而不用等待数据加载和渲染,提高用户的首屏体验。

2、服务器端渲染的优缺点

优点:

(1)更好的seo:抓取工具可以直接查看完全渲染的页面。现在比较常用的交互是页面初始展示 loading 菊花图,然后通过异步请求获取内容,但是但抓取工具并不会等待异步完成后再行抓取页面内容。

(2)内容到达更快:不用等待所有的 js 都完成下载并执行,所以用户会更快速地看到完整渲染的页面。

缺点:

(1)服务器渲染应用程序,需要处于 Node.js server 运行环境

(2)开发成本比较高

总结:

总得来说,决定是否使用服务器端渲染,取决于具体的业务场景和需求。对于具有大量静态内容的简单页面,客户端渲染更合适一些,因为它可以更快地加载页面。但是对于需要从服务器动态加载数据的复杂页面,服务器端渲染可能是一个更好的选择,因为他可以提高用户的首屏体验和搜索引擎优化。

下面进入正文

方案一:vue插件vue-server-render

git 示例demo地址

结论前置:不建议用,配置成本高

官网地址: https://v2.ssr.vuejs.org/zh/

首先要吐槽一下官网,按官网教程比较难搞,目录安排的不太合理,一顿操作项目都没起来...

并且官网示例的构建配置代码是webpack4的,现在初始化项目后基本安装的都是webpack5,有一些语法不同

(1)首先,先初始化一个npm项目,然后安装依赖得到一个基础项目 。(此处要注意vue-server-renderer 和 vue 必须匹配版本)npm init -yyarn add vue vue-server-renderer -Syarn add express -Syarn add webpack webpack-cli friendly-errors-webpack-plugin vue-loader babel-loader @babel/core url-loader file-loader vue-style-loader css-loader sass-loader sass webpack-merge webpack-node-externals -Dyarn add clean-webpack-plugin @babel/preset-env -Dyarn add rimraf // 模拟linx的删除命令,在build时先删除distyarn add webpack-dev-middleware webpack-hot-middleware -Dyarn add chokidar -D //监听变化yarn add memory-fs -Dyarn add nodemon -D...实在太多,如有缺失可以在package.JSON中查找另外:我现在用的"vue-loader": "^15.9.0"版本,之前用的是"vue-loader": "^17.0.1",报了一个styles的错(2)配置App.js,entry-client.js,entry-server.js,将官网参考中的示例代码拷贝至对应文件。

app.js

import Vue from 'vue'import App from './App.vue'import { createRouter } from './router'import { createStore } from './store'import { sync } from 'vuex-router-sync'// 导出一个工厂函数,用于创建新的// 应用程序、router 和 store 实例export function createApp () {// 创建 router 和 store 实例const router = createRouter()const store = createStore()sync(store, router)const app = new Vue({router,store,render: h => h(App)return { app, router, store }

entry-client.js

import Vue from 'vue'import { createApp } from './app'Vue.mixin({beforeMount () {const { asyncData } = this.$optionsif (asyncData) {this.dataPromise = asyncData({store: this.$store,route: this.$routeconst { app, router, store } = createApp()if (window.__INITIAL_State__) {store.replaceState(window.__INITIAL_STATE__)router.onReady(() => {// 在初始路由 resolve 后执行,// 使用 `router.beforeResolve()`,以便确保所有异步组件都 resolve。router.beforeResolve((to, from, next) => {const matched = router.getMatchedComponents(to)const prevMatched = router.getMatchedComponents(from)// 找出两个匹配列表的差异组件let diffed = falseconst activated = matched.filter((c, i) => {return diffed || (diffed = (prevMatched[i] !== c))if (!activated.length) {return next()Promise.all(activated.map(c => {if (c.asyncData) {return c.asyncData({ store, route: to })})).then(() => {next()}).catch(next)app.$mount('#app')

entry-server.js

import { createApp } from './app'export default context => {// 返回一个promise,服务器能够等待所有的内容在渲染前,已经准备就绪,return new Promise((resolve, reject) => {const { app, router, store } = createApp()router.push(context.url)router.onReady(() => {const matchedComponents = router.getMatchedComponents()if (!matchedComponents.length) {return reject({ code: 404 })// 对所有匹配的路由组件调用 `asyncData()`Promise.all(matchedComponents.map(Component => {if (Component.asyncData) {return Component.asyncData({store,route: router.currentRoute})).then(() => {context.state = store.stateresolve(app)}).catch(reject)}, reject)(3)在根目录下创建server.js 文件

其中一个非常重要的api:createBundleRenderer,这个api上面有一个方法renderToString将代码转化成html字符串,主要功能就是把用webpack把打包后的服务端代码渲染出来。具体了解可看官网bundle renderer指引。

// server.jsconst app = require('express')()const { createBundleRenderer } = require('vue-server-renderer')const fs = require('fs')const path = require('path')const resolve = file => path.resolve(__dirname, file)const isProd = process.env.NODE_ENE === "production"const createRenderer = (bundle, options) => {return createBundleRenderer(bundle, Object.assign(options, {basedir: resolve('./dist'),runInNewContext: false,let renderer, readyPromiseconst templatePath = resolve('./src/index.template.html')if (isProd) {const bundle = require('./dist/vue-ssr-server-bundle.json')const clientManifest = require('./dist/vue-ssr-client-manifest.json')const template = fs.readFileSync(templatePath, 'utf-8')renderer = createRenderer(bundle, {template, // (可选)页面模板clientManifest // (可选)客户端构建 manifest} else {// 开发模式readyPromise = require('./config/setup-dev-server')(app, templatePath, (bundle, options) => {renderer = createRenderer(bundle, options)const render = (req, res) => {const context = {title: 'hello ssr with webpack',meta: `charset="UTF-8">`,url: req.urlrenderer.renderToString(context, (err, html) => {if (err) {if (err.code === 404) {res.status(404).end('Page not found')} else {res.status(500).end('Internal Server Error')} else {res.end(html)// 在服务器处理函数中……app.get('*', isProd ? render : (req, res) => {readyPromise.then(() => render(req, res))app.listen(8080) // 监听的是8080端口(4)接下来是config配置

在根目录新增config文件夹,然后新增四个配置文件:webpack.base.config,webpack.client.config,webpack.server.config,setup-dev-server(此方法是一个封装,为了配置个热加载,差点没搞明白,参考了好多)(官网传送门: 构建配置 )

大部分官网有示例代码,但是要在基础上进行一些更改

webpack.base.config

// webpack.base.configconst path = require('path')// 用来处理后缀为.vue的文件const { VueLoaderPlugin } = require('vue-loader')const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin')// 定位到根目录const resolve = (dir) => path.join(path.resolve(__dirname, "../"), dir)// 打包时会先清除一下// const { CleanWebpackPlugin } = require('clean-webpack-plugin')const isProd = process.env.NODE_ENV === "production"module.exports = {mode: isProd ? 'production' : 'development',output: {path: resolve('dist'),publicPath: '/dist/',filename: '[name].[chunk-hash].js'},resolve: {alias: {'public': resolve('public')},module: {noParse: /es6-promise.js$/,rules: [test: /.vue$/,loader: 'vue-loader',options: {compilerOptions: {preserveWhiteSpace: false},test: /.js$/,loader: 'babel-loader',exclude: /node_modules/},test: /.(png|jpg|gif|svg)$/,loader: 'url-loader',options: {limit: 10000,name: '[name].[ext]?[hash]'},test: /.s(a|c)ss?$/,use: ['vue-style-loader', 'css-loader', 'sass-loader']},performance: {hints: false},plugins:[new VueLoaderPlugin(),// 编译后的友好提示,比如编译完成或者编译有错误new FriendlyErrorsWebpackPlugin(),// 打包时会先清除一下// new CleanWebpackPlugin()

webpack.client.config

// webpack.client.configconst {merge} = require('webpack-merge')const baseConfig = require('./webpack.base.config.js')const VueSSRClientPlugin = require('vue-server-renderer/client-plugin')module.exports = merge(baseConfig, {entry: {app: './src/entry-client.js'},optimization: {// 重要信息:这将 webpack 运行时分离到一个引导 chunk 中,// 以便可以在之后正确注入异步 chunk。// 这也为你的 应用程序/vendor 代码提供了更好的缓存。splitChunks: {name: "manifest",minChunks: Infinity},plugins: [// 此插件在输出目录中// 生成 `vue-ssr-client-manifest.json`。new VueSSRClientPlugin()

webpack.server.config

// webpack.server.configconst {merge} = require('webpack-merge')const nodeExternals = require('webpack-node-externals')// webpack的基础配置,比如sass,less预编译等const baseConfig = require('./webpack.base.config.js')const VueSSRServerPlugin = require('vue-server-renderer/server-plugin')module.exports = merge(baseConfig, {// 将 entry 指向应用程序的 server entry 文件entry: './src/entry-server.js',target: 'node',// 对 bundle renderer 提供 source map 支持devtool: 'source-map',// 此处告知 server bundle 使用 Node 风格导出模块(Node-style exports)output: {libraryTarget: 'commonjs2'},// https://webpack.js.org/configuration/externals/#function// https://Github.com/liady/webpack-node-externals// 外置化应用程序依赖模块。可以使服务器构建速度更快,// 并生成较小的 bundle 文件。externals: nodeExternals({// 不要外置化 webpack 需要处理的依赖模块。// 你可以在这里添加更多的文件类型。例如,未处理 *.vue 原始文件,// 你还应该将修改 `global`(例如 polyfill)的依赖模块列入白名单allowlist: /.css$/}),// 这是将服务器的整个输出// 构建为单个 JSON 文件的插件。// 默认文件名为 `vue-ssr-server-bundle.json`plugins: [new VueSSRServerPlugin()

setup-dev-server:封装createRenderer方法

const webpack = require('webpack')const fs = require('fs')const path = require('path')const chokidar = require('chokidar')const middleware = require("webpack-dev-middleware")const HMR = require("webpack-hot-middleware")const MFS = require('memory-fs')const clientConfig = require('./webpack.client.config')const serverConfig = require('./webpack.server.config')const readFile = (fs, file) => {try {return fs.readFileSync(path.join(clientConfig.output.path, file), 'utf8')} catch (error) {const setupServer = (app, templatePath, cb) => {let bundlelet clientManifestlet templatelet readyconst readyPromise = new Promise(r => ready = r)template = fs.readFileSync(templatePath, 'utf8')const update = () => {if (bundle && clientManifest) {// 通知 server 进行渲染// 执行 createRenderer -> RenderToStringready()cb(bundle, {template,clientManifest// webpack -> entry-server -> bundleconst mfs = new MFS();const serverCompiler = webpack(serverConfig);serverCompiler.outputFileSystem = mfs;serverCompiler.watch({}, (err, stats) => {if (err) throw err// 之后读取输出:stats = stats.toJson()stats.errors.forEach(err => console.error(err))stats.warnings.forEach(err => console.warn(err))if (stats.errors.length) returnbundle = JSON.parse(readFile(mfs, 'vue-ssr-server-bundle.json'))update()clientConfig.plugins.push(new webpack.HotModuleReplacementPlugin()clientConfig.entry.app = ['webpack-hot-middleware/client', clientConfig.entry.app]clientConfig.output.filename = '[name].js'const clientCompiler = webpack(clientConfig);const devMiddleware = middleware(clientCompiler, {noInfo: true, publicPath: clientConfig.output.publicPath, logLevel: 'silent'app.use(devMiddleware);app.use(HMR(clientCompiler));clientCompiler.hooks.done.tap('clientsBuild', stats => {stats = stats.toJson()stats.errors.forEach(err => console.error(err))stats.warnings.forEach(err => console.warn(err))if (stats.errors.length) returnclientManifest = JSON.parse(readFile(devMiddleware.fileSystem,'vue-ssr-client-manifest.json'update()// fs -> templatePath -> templatechokidar.watch(templatePath).on('change', () => {template = fs.readFileSync(templatePath, 'utf8')console.log('template is updated');update()return readyPromisemodule.exports = setupServer(5)配置搞完了接下来是代码渲染

在src目录下,新增index.template.html文件,将官网中的例子(地址:使用一个页面模板 )复制,并进行一些更改

{{ title }}{{{ meta }}}(6)再搞个store和api模拟一下数据请求

这里介绍一下一个很重要的东西asyncData 预取数据,预取数据是在vue挂载前,所以下文这里用了上下文来获取store而不是this

asyncData: ({ store }) => { return store.dispatch('getDataAction') },

在src下创建api文件夹,并在下面创建data.js文件

// data.jsconst getData = () => new Promise((resolve) => {setTimeout(() => {resolve([id: 1,item: '测试1'},id: 2,item: '测试2'},}, 1000)export {getData

在src下创建store文件夹,并在下面创建index.js文件

// store.jsimport Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex)import { getData } from '../api/data'export function createStore () {return new Vuex.Store({state: {lists: []},actions: {getDataAction ({ commit }) {return getData().then((res) => {commit('setData', res)},mutations: {setData (state, data) {state.lists = data(7)编写组件,在src/components文件夹下写两个组件,在app.vue中引用一下,用上刚写的模拟数据

Hello.vue

这里是测试页面一

{{item}}

链接到测试页面二

 

Hello1.vue

这里是测试页面二{{item}}

(8)配置路由并在app.vue使用路由

router.js

import Vue from 'vue'import Router from 'vue-router'Vue.use(Router)export function createRouter () {return new Router({mode: 'history',routes: [path: '/hello',component: () => import('./components/Hello.vue')},path: '/hello1',component: () => import('./components/Hello1.vue')},

app.vue


(9)根目录下创建一个.babelrc,进行配置"presets": ["@babel/preset-env","modules": false(10)改写package.json执行命令"dev": "nodemon server.js","build": "rimraf dist && npm run build:client && npm run build:server","build:client": "webpack --config config/webpack.client.config.js","build:server": "webpack --config config/webpack.server.config.js"

大搞告成,执行一下dev命令,可以通过访问localhost:8080端口看到页面,记得带上路由哦~

执行build命令可看到,最后dist文件下共有三个文件:mAIn.[chunk-hash].js,vue-ssr-client-manifest.json,vue-ssr-server-bundle.json

附上文件整体目录结构


 

方案二:基于vue的nuxt.js通用应用框架

git 示例demo地址

一对比,这个就显得丝滑多了~ 官网地址: nuxt.js

先对比一下两种方案的差别

1.vue初始化虽然有cli,但是nuxt.js的cli更加完备2.nuxt有更合理的工程化目录,vue过于简洁,比如一些component,api文件夹都是要手动创建的3.路由配置:传统应用需要自己来配置,nuxt.js自动生成4.没有统一配置,需手动创建。nuxt.js会生成nuxt.config.js5.传统不易与管理底层框架逻辑(nuxt支持中间件管理,虽然我还没探索过这里)

显而易见这个上手就快多了,也不需要安装一大堆依赖,如果用了sass需要安装sass和sass-loader,反正我是用了

(1)创建一个项目 可选npm,npx,yarn,具体看官方文档npm init nuxt-app(2)pages下面创建几个文件

nuxt是通过pages页面形成动态的路由,不用手动配置路由。比如在pages下面新增了个文件about.vue,那么这个页面对应的路由就是/about

其实这个时候运行npm run dev 就可以看到简单的页面了

(3)模拟接口

这里介绍一个插件,可以快速创建一个服务

npm i json-server

安装完后,在根目录新增db.json文件,模拟几个接口

"post": [{"id": 1, "title": "json-server", "author": "jx"}],"comments": [{"id": 1, "body": "some comment", "postId": 1}],"profile": {"name": "typicode"}

运行命令json-server --watch db.json --port=8000(不加会端口冲突),就可以看到


 

因为是get请求,可以直接点击访问可以看到mock的数据已经返回了


 

(4)页面调用

先配置一下axIOS,推荐使用nuxt.js封装的axios:"@nuxtjs/axios": "^5.13.6",然后再在nuxt.config.js文件中modules下面配置一下就可以使用了

modules: [ '@nuxtjs/axios'],

随便找个接口调用一下

 

这里是测试页面一

接口返回数据:{{posts}}

 

刷新下页面就可以看到效果了,这里注意$axios有两个get方法,一个$axios.get还会返回头部等信息,另一个$axios.$get只返回结果

总结:

从页面篇幅上应该也能看到哪个容易上手了,nuxt相对于插件来说限定了文件夹的结构,并通过此预定了一些功能,更好上手。预设了利用vue.js开发服务端渲染所需要的各种配置,并且提供了提供了静态站点,异步数据加载,中间件支持,布局支持等



Tags:vue   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
前端开始“锈化”?Vue团队开源JS打包工具:基于Rust、速度极快、尤雨溪主导
Vue 团队已正式开源Rolldown —— 基于 Rust 的 JavaScrip 打包工具。Rolldown 是使用 Rust 开发的 Rollup 替代品,它提供与 Rollup 兼容的应用程序接口和插件接口...【详细内容】
2024-03-09  Search: vue  点击:(11)  评论:(0)  加入收藏
SpringBoot3+Vue3 开发高并发秒杀抢购系统
开发高并发秒杀抢购系统:使用SpringBoot3+Vue3的实践之旅随着互联网技术的发展,电商行业对秒杀抢购系统的需求越来越高。为了满足这种高并发、高流量的场景,我们决定使用Spring...【详细内容】
2024-01-14  Search: vue  点击:(91)  评论:(0)  加入收藏
React与Vue性能对比:两大前端框架的性能
React和Vue是当今最流行的两个前端框架,它们在性能方面都有着出色的表现。React的加载速度:初次加载:由于React使用了虚拟DOM(Virtual DOM)技术,它可以通过比较虚拟DOM树与实际DOM...【详细内容】
2024-01-05  Search: vue  点击:(107)  评论:(0)  加入收藏
Vue中Scope是怎么做样式隔离的?
scope样式隔离在 Vue 中,样式隔离是通过 scoped 特性实现的。当在一个组件的 <style> 标签上添加 scoped 特性时,Vue 会自动为这个样式块中的所有选择器添加一个唯一的属性,以...【详细内容】
2024-01-04  Search: vue  点击:(80)  评论:(0)  加入收藏
vue3中 ref和 reactive的区别 ?
最近有朋友在面试过程中经常被问到这么一个问题,vue3 中的ref 和 reactive的区别在哪里,为什么 要定义两个API 一个 api不能实现 响应式更新吗??带着这个疑问 ,我们 接下来进行逐...【详细内容】
2024-01-03  Search: vue  点击:(38)  评论:(0)  加入收藏
React18 与 Vue3 全方面对比
1. 编程风格 & 视图风格1.1 编程风格 React 语法少、难度大;Vue 语法多,难度小例如指令:Vue<input v-model="username"/><ul> <li v-for="(item,index) in list" :key="inde...【详细内容】
2024-01-03  Search: vue  点击:(72)  评论:(0)  加入收藏
Vue中虚拟Dom技术,你学会了吗?
在Vue中,虚拟DOM(Virtual DOM)是一项关键的技术,它是一种用JavaScript对象模拟真实DOM结构的机制。虚拟DOM的引入旨在提高DOM操作的效率,特别是在频繁的数据变化时。1. 为什么需...【详细内容】
2023-12-26  Search: vue  点击:(65)  评论:(0)  加入收藏
七个常用的 Vue 3 UI 组件
介绍:由于我在工作的公司中角色和职责的变化,作为后端开发人员的我在去年年底选择了 Vue.js。当我深入研究时,我发现 Vue.js 非常有趣。它不像 Angular 那样有很高的学习曲线,而...【详细内容】
2023-12-20  Search: vue  点击:(78)  评论:(0)  加入收藏
Vue3 学习笔记,如何使用 Watch 监听数据变化
大家好,本篇文章我们继续学习和 Vue 相关的内容,今天我们归纳总结下如何使用 watch 监听组件中的数据变化,以及 computed 和 watch 的区别。什么是 watch,以及如何使用?watch 是...【详细内容】
2023-12-14  Search: vue  点击:(166)  评论:(0)  加入收藏
Vue3 学习笔记,如何理解 Computed 计算属性
大家好,本篇文章我们继续学习和 Vue 相关的内容,今天我们归纳总结下什么是 computed 计算属性、如何使用和应用场景,以及 computed 和 Method 事件的区别和应用场景。什么是 co...【详细内容】
2023-12-11  Search: vue  点击:(200)  评论:(0)  加入收藏
▌简易百科推荐
20k级别前端是怎么使用LocalStorage的,想知道吗?
当咱们把咱们想缓存的东西,存在localStorage、sessionStorage中,在开发过程中,确实有利于咱们的开发,咱们想看的时候也是一目了然,点击Application就可以看到。前言大家好,我是林...【详细内容】
2024-03-26  前端之神  微信公众号  Tags:前端   点击:(12)  评论:(0)  加入收藏
前端不存在了?盲测64%的人更喜欢GPT-4V的设计,杨笛一等团队新作
3 月 9 日央视的一档节目上,百度创始人、董事长兼 CEO 李彦宏指出,以后不会存在「程序员」这种职业了,因为只要会说话,人人都会具备程序员的能力。「未来的编程语言只会剩下两种...【详细内容】
2024-03-11  机器之心Pro    Tags:前端   点击:(9)  评论:(0)  加入收藏
前端开始“锈化”?Vue团队开源JS打包工具:基于Rust、速度极快、尤雨溪主导
Vue 团队已正式开源Rolldown &mdash;&mdash; 基于 Rust 的 JavaScrip 打包工具。Rolldown 是使用 Rust 开发的 Rollup 替代品,它提供与 Rollup 兼容的应用程序接口和插件接口...【详细内容】
2024-03-09  OSC开源社区    Tags:Vue   点击:(11)  评论:(0)  加入收藏
两年前端经验还不会手写Promise?
什么是promise?当我们处理异步操作时,我们经常需要进行一系列的操作,如请求数据、处理数据、渲染UI等。在过去,这些操作通常通过回调函数来处理,但是回调函数嵌套过多会导致代码...【详细内容】
2024-03-07  海燕技术栈  微信公众号  Tags:Promise   点击:(23)  评论:(0)  加入收藏
网站开发中的前端和后端开发有什么区别
前端开发和后端开发都是干什么的?有哪些区别?通俗地讲,前端干的工作是用户可以直接看得见的,而后端开发的工作主要在服务端,用户不太能直接看到。虽然前端开发和后端开发的工作有...【详细内容】
2024-02-21  CarryData    Tags:前端   点击:(32)  评论:(0)  加入收藏
网站程序开发中的前后端分离技术
随着互联网的快速发展和技术的不断创新,传统的网站开发模式已经难以满足日益增长的业务需求。为了提高开发效率、增强系统的可维护性和可扩展性,前后端分离技术逐渐成为了网站...【详细内容】
2024-01-31  网站建设派迪星航    Tags:前后端分离   点击:(23)  评论:(0)  加入收藏
如何优雅的实现前端国际化?
JavaScript 中每个常见问题都有许多成熟的解决方案。当然,国际化 (i18n) 也不例外,有很多成熟的 JavaScript i18n 库可供选择,下面就来分享一些热门的前端国际化库!i18nexti18ne...【详细内容】
2024-01-17  前端充电宝  微信公众号  Tags:前端   点击:(69)  评论:(0)  加入收藏
Vue中Scope是怎么做样式隔离的?
scope样式隔离在 Vue 中,样式隔离是通过 scoped 特性实现的。当在一个组件的 <style> 标签上添加 scoped 特性时,Vue 会自动为这个样式块中的所有选择器添加一个唯一的属性,以...【详细内容】
2024-01-04  海燕技术栈  微信公众号  Tags:Vue   点击:(80)  评论:(0)  加入收藏
vue3中 ref和 reactive的区别 ?
最近有朋友在面试过程中经常被问到这么一个问题,vue3 中的ref 和 reactive的区别在哪里,为什么 要定义两个API 一个 api不能实现 响应式更新吗??带着这个疑问 ,我们 接下来进行逐...【详细内容】
2024-01-03  互联网高级架构师  今日头条  Tags:vue3   点击:(38)  评论:(0)  加入收藏
React18 与 Vue3 全方面对比
1. 编程风格 & 视图风格1.1 编程风格 React 语法少、难度大;Vue 语法多,难度小例如指令:Vue<input v-model="username"/><ul> <li v-for="(item,index) in list" :key="inde...【详细内容】
2024-01-03  爱做梦的程序员  今日头条  Tags:Vue3   点击:(72)  评论:(0)  加入收藏
站内最新
站内热门
站内头条