PageSourceSearch

https://whyta.cn/post/0dced23f9a71/

html whyta.cn collected 2026-09-28 07:07:09 UTC 94,279 bytes, 354 lines download raw bytes

1<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0,viewport-fit=cover"><title>Vue的不同风格写法,你知道么? | 前端日记</title><meta name="author" content="YangTao"><meta name="copyright" content="YangTao"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="引入打开 Vue3 的官方文档,它首先会告诉你,Vue 的组件可以按两种不同的风格书写:选项式 API 和组合式 API。文档为我们提供一系列两种风格的代码参考,供我们按照偏好进行选择。 实际上,Vue3 组件可不止两种写法,而是多达十几种!然而,不管是什么写法,它们都是基于同一个底层系统实现的,概念之间也是彼此相通的,只是使用的接口不同。在实际开发中,我们也不会同时使用到那么多种写法,但是这并不">
2<meta property="og:type" content="article">
3<meta property="og:title" content="Vue的不同风格写法,你知道么?">
4<meta property="og:url" content="https://whyta.cn/post/0dced23f9a71/index.html">
5<meta property="og:site_name" content="前端日记">
6<meta property="og:description" content="引入打开 Vue3 的官方文档,它首先会告诉你,Vue 的组件可以按两种不同的风格书写:选项式 API 和组合式 API。文档为我们提供一系列两种风格的代码参考,供我们按照偏好进行选择。 实际上,Vue3 组件可不止两种写法,而是多达十几种!然而,不管是什么写法,它们都是基于同一个底层系统实现的,概念之间也是彼此相通的,只是使用的接口不同。在实际开发中,我们也不会同时使用到那么多种写法,但是这并不">
7<meta property="og:locale" content="zh_CN">
8<meta property="og:image" content="https://xiaojinhe-cdn.iyoudui.cn/upload/common/2023/avata.jpg">
9<meta property="article:published_time" content="2024-10-24T10:52:24.000Z">
10<meta property="article:modified_time" content="2024-10-24T02:58:54.465Z">
11<meta property="article:author" content="YangTao">
12<meta property="article:tag" content="Vue">
13<meta name="twitter:card" content="summary">
14<meta name="twitter:image" content="https://xiaojinhe-cdn.iyoudui.cn/upload/common/2023/avata.jpg"><link rel="shortcut icon" href="/img/favicon.png"><link rel="canonical" href="https://whyta.cn/post/0dced23f9a71/index.html"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox/fancybox.min.css" media="print" onload="this.media='all'">
14<script>const GLOBAL_CONFIG = {
15  root: '/',
16  algolia: undefined,
17  localSearch: {"path":"/search.xml","preload":false,"top_n_per_article":1,"unescape":false,"languages":{"hits_empty":"找不到您查询的内容:${query}","hits_stats":"共找到 ${hits} 篇文章"}},
18  translate: {"defaultEncoding":2,"translateDelay":0,"msgToTraditionalChinese":"繁","msgToSimplifiedChinese":"简"},
19  noticeOutdate: undefined,
20  highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false},
21  copy: {
22    success: '复制成功',
23    error: '复制错误',
24    noSupport: '浏览器不支持'
25  },
26  relativeDate: {
27    homepage: false,
28    post: false
29  },
30  runtime: '天',
31  dateSuffix: {
32    just: '刚刚',
33    min: '分钟前',
34    hour: '小时前',
35    day: '天前',
36    month: '个月前'
37  },
38  copyright: {"limitCount":50,"languages":{"author":"作者: YangTao","link":"链接: ","source":"来源: 前端日记","info":"著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。"}},
39  lightbox: 'fancybox',
40  Snackbar: undefined,
41  infinitegrid: {
42    js: 'https://cdn.jsdelivr.net/npm/@egjs/infinitegrid/dist/infinitegrid.min.js',
43    buttonText: '加载更多'
44  },
45  isPhotoFigcaption: false,
46  islazyload: false,
47  isAnchor: false,
48  percent: {
49    toc: true,
50    rightside: false,
51  },
52  autoDarkmode: false
53}</script>
53<script id="config-diff">var GLOBAL_CONFIG_SITE = {
54  title: 'Vue的不同风格写法,你知道么?',
55  isPost: true,
56  isHome: false,
57  isHighlightShrink: false,
58  isToc: true,
59  postUpdate: '2024-10-24 02:58:54'
60}</script>
60<script>(win=>{
61      win.saveToLocal = {
62        set: (key, value, ttl) => {
63          if (ttl === 0) return
64          const now = Date.now()
65          const expiry = now + ttl * 86400000
66          const item = {
67            value,
68            expiry
69          }
70          localStorage.setItem(key, JSON.stringify(item))
71        },
72      
73        get: key => {
74          const itemStr = localStorage.getItem(key)
75      
76          if (!itemStr) {
77            return undefined
78          }
79          const item = JSON.parse(itemStr)
80          const now = Date.now()
81      
82          if (now > item.expiry) {
83            localStorage.removeItem(key)
84            return undefined
85          }
86          return item.value
87        }
88      }
89    
90      win.getScript = (url, attr = {}) => new Promise((resolve, reject) => {
91        const script = document.createElement('script')
92        script.src = url
93        script.async = true
94        script.onerror = reject
95        script.onload = script.onreadystatechange = function() {
96          const loadState = this.readyState
97          if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
98          script.onload = script.onreadystatechange = null
99          resolve()
100        }
101
102        Object.keys(attr).forEach(key => {
103          script.setAttribute(key, attr[key])
104        })
105
106        document.head.appendChild(script)
107      })
108    
109      win.getCSS = (url, id = false) => new Promise((resolve, reject) => {
110        const link = document.createElement('link')
111        link.rel = 'stylesheet'
112        link.href = url
113        if (id) link.id = id
114        link.onerror = reject
115        link.onload = link.onreadystatechange = function() {
116          const loadState = this.readyState
117          if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
118          link.onload = link.onreadystatechange = null
119          resolve()
120        }
121        document.head.appendChild(link)
122      })
123    
124      win.activateDarkMode = () => {
125        document.documentElement.setAttribute('data-theme', 'dark')
126        if (document.querySelector('meta[name="theme-color"]') !== null) {
127          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
128        }
129      }
130      win.activateLightMode = () => {
131        document.documentElement.setAttribute('data-theme', 'light')
132        if (document.querySelector('meta[name="theme-color"]') !== null) {
133          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
134        }
135      }
136      const t = saveToLocal.get('theme')
137    
138        if (t === 'dark') activateDarkMode()
139        else if (t === 'light') activateLightMode()
140      
141      const asideStatus = saveToLocal.get('aside-status')
142      if (asideStatus !== undefined) {
143        if (asideStatus === 'hide') {
144          document.documentElement.classList.add('hide-aside')
145        } else {
146          document.documentElement.classList.remove('hide-aside')
147        }
148      }
149    
150      const detectApple = () => {
151        if(/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){
152          document.documentElement.classList.add('apple')
153        }
154      }
155      detectApple()
156    })(window)</script>
156<meta name="generator" content="Hexo 6.3.0"></head><body><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img is-center"><img src="https://xiaojinhe-cdn.iyoudui.cn/upload/common/2023/avata.jpg" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="sidebar-site-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">296</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">31</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">11</div></a></div><hr class="custom-hr"/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 文章</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fas fa-list"></i><span> 娱乐</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/images/"><i class="fa-fw fas fa-images"></i><span> 图库</span></a></li><li><a class="site-page child" href="/music/"><i class="fa-fw fas fa-music"></i><span> Music</span></a></li><li><a class="site-page child" href="/movies/"><i class="fa-fw fas fa-video"></i><span> Movie</span></a></li><li><a class="site-page child" href="/about/resume.html"><i class="fa-fw fa fa-address-card"></i><span> 简历</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 联系我</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> About</span></a></div></div></div></div><div class="post" id="body-wrap"><header class="post-bg" id="page-header" style="background-image: url('https://xiaojinhe-cdn.iyoudui.cn/upload/common/20230808/6028094.jpg')"><nav id="nav"><span id="blog-info"><a href="/" title="前端日记"><img class="site-icon" src="https://xiaojinhe-cdn.iyoudui.cn/upload/common/2023/avata.jpg"/><span class="site-name">前端日记</span></a></span><div id="menus"><div id="search-button"><a class="site-page social-icon search" href="javascript:void(0);"><i class="fas fa-search fa-fw"></i><span> 搜索</span></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 文章</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fas fa-list"></i><span> 娱乐</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/images/"><i class="fa-fw fas fa-images"></i><span> 图库</span></a></li><li><a class="site-page child" href="/music/"><i class="fa-fw fas fa-music"></i><span> Music</span></a></li><li><a class="site-page child" href="/movies/"><i class="fa-fw fas fa-video"></i><span> Movie</span></a></li><li><a class="site-page child" href="/about/resume.html"><i class="fa-fw fa fa-address-card"></i><span> 简历</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 联系我</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> About</span></a></div></div><div id="toggle-menu"><a class="site-page" href="javascript:void(0);"><i class="fas fa-bars fa-fw"></i></a></div></div></nav><div id="post-info"><h1 class="post-title">Vue的不同风格写法,你知道么?</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2024-10-24T10:52:24.000Z" title="发表于 2024-10-24 10:52:24">2024-10-24</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2024-10-24T02:58:54.465Z" title="更新于 2024-10-24 02:58:54">2024-10-24</time></span><span class="post-meta-categories"><span class="post-meta-separator">|</span><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/Vue/">Vue</a></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-wordcount"><i class="far fa-file-word fa-fw post-meta-icon"></i><span class="post-meta-label">字数总计:</span><span class="word-count">4.8k</span><span class="post-meta-separator">|</span><i class="far fa-clock fa-fw post-meta-icon"></i><span class="post-meta-label">阅读时长:</span><span>18分钟</span></span><span class="post-meta-separator">|</span><span class="post-meta-commentcount"><i class="far fa-comments fa-fw post-meta-icon"></i><span class="post-meta-label">评论数:</span><a href="/post/0dced23f9a71/#post-comment"><span class="gitalk-comment-count"><i class="fa-solid fa-spinner fa-spin"></i></span></a></span></div></div></div></header><main class="layout" id="content-inner"><div id="post"><article class="post-content" id="article-container"><h3 id="引入"><a href="#引入" class="headerlink" title="引入"></a>引入</h3><p>打开 Vue3 的官方文档,它首先会告诉你,Vue 的组件可以按两种不同的风格书写:选项式 API 和组合式 API。文档为我们提供一系列两种风格的代码参考,供我们按照偏好进行选择。</p>
157<p>实际上,Vue3 组件可不止两种写法,而是多达十几种!然而,不管是什么写法,它们都是基于同一个底层系统实现的,概念之间也是彼此相通的,只是使用的接口不同。在实际
157开发中,我们也不会同时使用到那么多种写法,但是这并不意味着我们不需要去了解这些写法!</p>
158<h3 id="setup-语法糖"><a href="#setup-语法糖" class="headerlink" title="setup 语法糖"></a>setup 语法糖</h3><p>setup 语法糖应该是最常用的写法了。在 Vue3 中,我们想封装一个组件,最习惯的做法还是新建一个 Vue 文件,并将组件代码写在文件中。具体是:页面结构写在 template 中,页面逻辑写在 script 中,页面样式写在 style 中。</p>
159<p>总之,我们将与该组件相关的代码都写在一起、放在一个文件中单独维护,在需要该组件的地方引入使用。</p>
160<p>这里我们使用了 setup 语法糖,直接在 script 中书写我们的 setup 内部的逻辑。</p>
161<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span>&#123;&#123; name &#125;&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">script</span> <span class="attr">setup</span> <span class="attr">lang</span>=<span class="string">&quot;ts&quot;</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">import</span> &#123; ref &#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span>;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">const</span> name = <span class="title function_">ref</span>(<span class="string">&quot;天气好&quot;</span>);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">style</span> <span class="attr">scoped</span>&gt;</span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span></span><br></pre></td></tr></table></figure>
162<p>在 App. vue 中引入并使用:</p>
163<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// App.vue</span></span><br><span class="line">&lt;template&gt;</span><br><span class="line">  <span class="language-xml"><span class="tag">&lt;<span class="name">User</span> /&gt;</span></span></span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">script</span> <span class="attr">setup</span> <span class="attr">lang</span>=<span class="string">&quot;ts&quot;</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">import</span> <span class="title class_">User</span> <span class="keyword">from</span> <span class="string">&quot;./User.vue&quot;</span>;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">style</span> <span class="attr">scoped</span>&gt;</span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span></span><br></pre></td></tr></table></figure>
164<p>注:后续写法尽管形式不同,但它们最终的目的都是导出一个组件,所以对于组件使用方来说(这里是 App. vue),怎么使用这个组件的代码都是不变的,所以将不再重复此代码。</p>
165<h3 id="Vue2-选项式写法"><a href="#Vue2-选项式写法" class="headerlink" title="Vue2 选项式写法"></a>Vue2 选项式写法</h3><h4 id="Vue2-经典写法"><a href="#Vue2-经典写法" class="headerlink" title="Vue2 经典写法"></a>Vue2 经典写法</h4><p>这种写法也是比较经典的。和 setup 语法糖写法类似。我们需要新建一个 vue 文件来存储我们的组件代码,然后在需要使用该组件的地方对其进行引入。
165区别在于,我们需要在 script 中导出一个 Vue 实例。</p>
166<p>这里我们导出的其实是一个普通对象,该对象包含 data、methods 等属性。这个对象的属性都是可选的,即 option,翻译回来即“选项”。</p>
167<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span>&#123;&#123; name &#125;&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">script</span> <span class="attr">lang</span>=<span class="string">&quot;ts&quot;</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="attr">data</span>: <span class="function">() =&gt;</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">return</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      <span class="attr">name</span>: <span class="string">&quot;天气好&quot;</span>,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    &#125;;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  &#125;,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">&#125;;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">style</span>&gt;</span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span></span><br></pre></td></tr></table></figure>
168<h4 id="defineComponent-辅助函数"><a href="#defineComponent-辅助函数" class="headerlink" title="defineComponent 辅助函数"></a>defineComponent 辅助函数</h4><p>尽管我们在 script 语言块中导出的默认对象会被 vue 编译器当成 vue 实例,但不管怎么看,它依旧只是一个 plain object。在定义组件实例方面,vue 提供了一个名为 defineComponent 辅助接口。</p>
169<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span>&#123;&#123; name &#125;&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">script</span> <span class="attr">lang</span>=<span class="string">&quot;ts&quot;</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">
169import</span> &#123; defineComponent &#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span>;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title function_">defineComponent</span>(&#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="attr">data</span>: <span class="function">() =&gt;</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">return</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      <span class="attr">name</span>: <span class="string">&quot;天气好&quot;</span>,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    &#125;;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  &#125;,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">&#125;);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">style</span>&gt;</span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span></span><br></pre></td></tr></table></figure>
170<p>尽管这个接口也不能改变我们导出的是一个普通对象的事实,但是它可以为我们的实例提供强大的类型推导。我们可以把它看成是一个返回 vue 实例的工厂函数,让我们的代码看起来更加规范。</p>
171<h3 id="Vue3-选项式写法"><a href="#Vue3-选项式写法" class="headerlink" title="Vue3 选项式写法"></a>Vue3 选项式写法</h3><p>在 Vue3 中,官方引入了新的选项 setup,这是 Vue3 选项式写法和 Vue2 写法的主要区别。setup 选项的意义在于它允许我们在选项式的写法中引用和使用组合式的 api,比如 onMounted、ref、reactive 等。但对于我们来说,它对于我们有益的地方还是基于它封装起来的 setup 语法糖用起来很方便。</p>
172<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span>&#123;&#123; name &#125;&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">script</span> <span class="attr">lang</span>=<span class="string">&quot;ts&quot;</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="title function_">setup</span>(<span class="params"></span>) &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">return</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">
172      <span class="attr">name</span>: <span class="string">&quot;天气好&quot;</span>,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    &#125;;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  &#125;,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">&#125;;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">style</span>&gt;</span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span></span><br></pre></td></tr></table></figure>
173<p>使用 defineComponent 时,它能够提示我们 setup 将会接收到什么参数:</p>
174<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span>&#123;&#123; name &#125;&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">script</span> <span class="attr">lang</span>=<span class="string">&quot;ts&quot;</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">import</span> &#123; defineComponent &#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span>;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title function_">defineComponent</span>(&#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="title function_">setup</span>(<span class="params">prop,context</span>) &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">return</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      <span class="attr">name</span>: <span class="string">&quot;天气好&quot;</span>,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    &#125;;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  &#125;,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">&#125;);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">style</span>&gt;</span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span></span><br></pre></td></tr></table></figure>
175<p>以上写法我们都是在 template 上书写我们的页面结构,这也是最常见的几种写法,下面我们来介绍几种了解 vue 底层必不可少的写法,渲染函数。</p>
176<h3 id="手写渲染函数"><a href="#手写渲染函数" class="headerlink" title="手写渲染函数"></a>手写渲染函数</h3><p>template 模板语法本质上也可以算是一种语法糖。在 vue 编译器上,template 中的内容最终会被翻译为渲染函数,挂载到 vue 实例的 render 属性上。当需要渲染组件时,vue 就执è
176¡Œä¸€æ¬¡ render,得到对应的虚拟节点树,最后再转变为真实 dom。</p>
177<p>Vue 允许我们脱离 template,直接自己书写渲染函数。位置就在导出实例的 render 选项上:</p>
178<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">&lt;script lang=<span class="string">&quot;ts&quot;</span>&gt;</span><br><span class="line"><span class="keyword">import</span> &#123; defineComponent &#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span>;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title function_">defineComponent</span>(&#123;</span><br><span class="line">  <span class="attr">data</span>: <span class="function">() =&gt;</span> (&#123; <span class="attr">name</span>: <span class="string">&quot;天气好&quot;</span> &#125;),</span><br><span class="line">  <span class="title function_">render</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">name</span>;</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;);</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">style</span>&gt;</span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span></span><br></pre></td></tr></table></figure>
179<p>在 template 中,我们使用类似 html 的模板语法来描述我们的视图,在 render 函数中又如何描述呢?vue 提供了两个 api:createVnode 和 h。二者没有区别,h 函数只是 createVnode 的缩写。有了 render 函数,我们就不需要写 template 了。</p>
180<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">&lt;script lang=<span class="string">&quot;ts&quot;</span>&gt;</span><br><span class="line"><span class="keyword">import</span> &#123; defineComponent, h &#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span>;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title function_">defineComponent</span>(&#123;</span><br><span class="line">  <span class="attr">data</span>: <span class="function">() =&gt;</span> (&#123; <span class="attr">name</span>: <span class="string">&quot;天气好&quot;</span> &#125;),</span><br><span class="line">  <span class="title function_">render</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="title function_">h</span>(<span class="string">&quot;div&quot;</span>, <span class="variable language_">this</span>.<span class="property">name</span>);</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;);</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">style</span>&gt;</span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span></span><br></pre></td></tr></table></figure>
181<p>在上面的示例中,我们使用 h 函数生成了一个 vNode,并 return 出去,作为本组件最终在被使用时渲染出来的效果。</p>
182<p>在 template 中我们可以使用 v-if、v-for、slot 等模板语法,在 h 函数中这些概念也是支持的,只是形式不同,这方面官方文档有具体的示例。总之,template 模板和 render 选项是可以相互替代的。</p>
183<h3 id="setup-返回渲染函数"><a href="#setup-返回渲染函数" class="headerlink" title="setup 返回渲染函数"></a>setup 返回渲染函数</h3><h4 id="setup-返回-render-方法"><a href="#setup-返回-render-方法" class="headerlink" title="setup 返回 render 方法"></a>setup 返回 render 方法</h4><p>一般来说,在选项式语法中,setup 方法返回一个对象,该对象暴露给 templateï¼
183Œä¾› template 使用,具体参考第三个例子(vue3 选项式写法)。如果我们不使用 template,也就没有返回对象的必要了。</p>
184<p>在 Vue3 中,还有另外一种不使用 template 的写法,就是在 setup 方法中返回一个 render 方法。</p>
185<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">&lt;script lang=<span class="string">&quot;ts&quot;</span>&gt;</span><br><span class="line"><span class="keyword">import</span> &#123; defineComponent, h, ref &#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span>;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title function_">defineComponent</span>(&#123;</span><br><span class="line">  <span class="title function_">setup</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> name = <span class="title function_">ref</span>(<span class="string">&quot;天气好&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="function">() =&gt;</span> <span class="title function_">h</span>(<span class="string">&quot;div&quot;</span>, name.<span class="property">value</span>);</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;);</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">style</span>&gt;</span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span></span><br></pre></td></tr></table></figure>
186<p>注意:</p>
187<ol>
188<li>在选项式中使用 setup 之后,一般不应该再使用 data、生命周期等在选项式写法中常用的选项,而应该把主要逻辑都写在 setup 中,并适当引入组合式的 api。比如,使用 ref,而不是 data 选项。</li>
189<li>ref 自动解包是 template 特有的功能,h 函数是没有这个功能的。在 h 函数中引入 ref,记得理所当然地带上 <code>.value</code>。</li>
190</ol>
191<h4 id="defineComponent-传入setup"><a href="#defineComponent-传入setup" class="headerlink" title="defineComponent 传入setup"></a>defineComponent 传入setup</h4><p>就注意中的第一点,我们可以采用下面这种写法:直接在 defineComponent 中书写 setup 函数(如果再省一点就是 setup 语法糖的写法了)。</p>
192<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">&lt;script lang=<span class="string">&quot;ts&quot;</span>&gt;</span><br><span class="line"><span class="keyword">import</span> &#123; defineComponent, h, ref &#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span>;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title function_">defineComponent</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">const</span> name = <span class="title function_">ref</span>(<span class="string">&quot;天气好&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> <span class="function">() =&gt;</span> <span class="title function_">h</span>(<span class="string">&quot;div&quot;</span>, name.<span class="property">value</span>);
192</span><br><span class="line">&#125;);</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">style</span>&gt;</span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span></span><br></pre></td></tr></table></figure>
193<p>以上就是渲染函数的写法,是不是有点感觉了呢,一下子就学会了两个 api!后面会提到的 Jsx 写法其实也应该归为渲染函数写法的一种(只要不是 template,而是用 JavaScript 表达页面结构的,都是渲染函数),但是相对于 h 函数,jsx 并不是纯粹的 js,所以我将它们分成了两类。</p>
194<h3 id="Vue-Jsx"><a href="#Vue-Jsx" class="headerlink" title="Vue &amp; Jsx"></a>Vue &amp; Jsx</h3><h4 id="在render-中使用-jsx"><a href="#在render-中使用-jsx" class="headerlink" title="在render 中使用 jsx"></a>在render 中使用 jsx</h4><p>有了前面两类写法介绍的铺垫,接下来引入 jsx 语法就没有什么难理解的点了。</p>
195<p>jsx 在 vue 文件中是这样写的。在 render 渲染函数返回值处书写 jsx 替代 h 函数。书写纯 JavaScript 的 h 函数描述结构还是比较繁冗的,jsx 就是简化了的h 函数写法。</p>
196<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">&lt;script lang=<span class="string">&quot;tsx&quot;</span>&gt;</span><br><span class="line"><span class="keyword">import</span> &#123; defineComponent &#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span>;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title function_">defineComponent</span>(&#123;</span><br><span class="line">  <span class="title function_">data</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123; <span class="attr">name</span>: <span class="string">&quot;天气好&quot;</span> &#125;;</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="title function_">render</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> (</span><br><span class="line">      <span class="language-xml"><span class="tag">&lt;&gt;</span></span></span><br><span class="line"><span class="language-xml">        <span class="tag">&lt;<span class="name">div</span>&gt;</span>&#123;this.name&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;/&gt;</span></span></span><br><span class="line">    );</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;);</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">style</span>&gt;</span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span></span><br></pre></td></tr></table></figure>
197<h4 id="在-setup-中使用jsx"><a href="#在-setup-中使用jsx" class="headerlink" title="在 setup 中使用jsx"></a>在 setup 中使用jsx</h4><p>jsx 和 setup 配合食用更加。在选项式风格中使用 setup,在 setup 中使用组合式 api,并且返回 jsx 书写的渲染函数。</p>
198<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">&lt;script lang=<span class="string">&quot;tsx&quot;</span>&gt;</span><br><span class="line"><span class="keyword">
198import</span> &#123; defineComponent, ref &#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span>;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title function_">defineComponent</span>(&#123;</span><br><span class="line">  <span class="title function_">setup</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> name = <span class="title function_">ref</span>(<span class="string">&quot;天气好&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="function">() =&gt;</span> <span class="language-xml"><span class="tag">&lt;&gt;</span>&#123;name.value&#125;<span class="tag">&lt;/&gt;</span></span>;</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;);</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">style</span>&gt;</span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span></span><br></pre></td></tr></table></figure>
199<h4 id="defineComponent-简写"><a href="#defineComponent-简写" class="headerlink" title="defineComponent 简写"></a>defineComponent 简写</h4><p>这个其实就是前面介绍过的 「defineComponent 传入 setup」 函数写法:这里的区别只是使用 jsx 替代了 h 函数。</p>
200<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">&lt;script lang=<span class="string">&quot;tsx&quot;</span>&gt;</span><br><span class="line"><span class="keyword">import</span> &#123; defineComponent, ref &#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span>;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title function_">defineComponent</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">const</span> name = <span class="title function_">ref</span>(<span class="string">&quot;天气好&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> <span class="function">() =&gt;</span> (</span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">div</span>&gt;</span>&#123;name.value&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;/&gt;</span></span></span><br><span class="line">  );</span><br><span class="line">&#125;);</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">style</span>&gt;</span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span></span><br></pre></td></tr></table></figure>
201<h4 id="自行导出-vNode-对象"><a href="#自行导出-vNode-对象" class="headerlink" title="自行导出 vNode 对象"></a>自行导出 vNode 对象</h4><p>我们也可以自己将 render 函数执行一遍,然后将得到的 jsx Element 导出,和上一个示例「defineComponent 简写」是十分相似。但是这段代码的缺点非常致命,它不支持接收外部传递来的属性参数。</p>
202<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">&lt;script lang=<span class="string">&quot;tsx&quot;</span>&gt;</span><br><span class="line"><span class="keyword">
202import</span> &#123; ref &#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span>;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> (<span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">const</span> name = <span class="title function_">ref</span>(<span class="string">&quot;天气好&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> <span class="function">() =&gt;</span> (</span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">div</span>&gt;</span>&#123;name.value&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;/&gt;</span></span></span><br><span class="line">  );</span><br><span class="line">&#125;)();</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">style</span>&gt;</span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span></span><br></pre></td></tr></table></figure>
203<p>不要使用这种写法。这里会提到这样写,只是因为和后面的「函数式组件(其二)」 写法有关联。本写法与其它写法都不同,其它写法导出的都是 JavaScript 对象或者 jsx 对象,而这里我们则是自己执行了一遍渲染函数并得到了虚拟节点,直接将虚拟节点导出去。既然都已经把虚拟节点创建出来了,那自然无法接收 props。</p>
204<h4 id="defineComponent-的第二个参数"><a href="#defineComponent-的第二个参数" class="headerlink" title="defineComponent 的第二个参数"></a>defineComponent 的第二个参数</h4><p>如果 defineComponent 的第一个参数是 setup 函数,那么它的第二个参数则可以为组件的定义添加需要的选项,但一般除了补充 props 选项,不会再需要其它选项了(组合式 api 和 setup 的入参可以完全替代其它选项)。</p>
205<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">&lt;script lang=<span class="string">&quot;tsx&quot;</span>&gt;</span><br><span class="line"><span class="keyword">import</span> &#123; defineComponent &#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span>;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title function_">defineComponent</span>(</span><br><span class="line">  <span class="function">(<span class="params">props</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="function">() =&gt;</span> (</span><br><span class="line">      <span class="language-xml"><span class="tag">&lt;&gt;</span></span></span><br><span class="line"><span class="language-xml">        <span class="tag">&lt;<span class="name">div</span>&gt;</span>&#123;props.userName&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;/&gt;</span></span></span><br><span class="line">    );</span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">props</span>: &#123; <span class="attr">userName</span>: <span class="title class_">String</span> &#125;,</span><br><span class="line">  &#125;</span><br><span class="line">);</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">style</span>&gt;</span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span></span><br></pre></td></tr></table></figure>
206<h3 id="直接在-vue-中使用-jsx"><a href="#直接在-vue-中使用-jsx" class="headerlink" title="直接在 vue 中使用 jsx"></a>直接在 vue 中使用 jsx</h3><p>这里 jsx 不再只作为返回值,而是直接被某处使用。它可以是被直接导出,或者用在 template 上。</p>
207<h4 id="直接导出-jsx-对象"><a href="#直接导出-jsx-对象" class="headerlink" title="直接导出 jsx 对象"></a>直接导出 jsx 对象</h4><p>直接将 jsx 对象导出使用。比前面的写法更简洁,做法就是把 setup 里面的内容提到外面。这里需要注意的是我们导出的是一段直接的 jsx 对象(jsx Element),而不是渲染函数。</p>
208<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">&lt;script lang=<span class="string">&quot;tsx&quot;</span>&gt;</span><br><span class="line"><span class="keyword">
208import</span> &#123; ref &#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span>;</span><br><span class="line"><span class="keyword">const</span> name = <span class="title function_">ref</span>(<span class="string">&quot;天气好&quot;</span>);</span><br><span class="line"><span class="keyword">const</span> <span class="title class_">User</span> = <span class="language-xml"><span class="tag">&lt;&gt;</span>&#123;name.value&#125;<span class="tag">&lt;/&gt;</span></span>;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title class_">User</span>;</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">style</span> <span class="attr">scoped</span>&gt;</span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span></span><br></pre></td></tr></table></figure>
209<h4 id="直接用在-template-上"><a href="#直接用在-template-上" class="headerlink" title="直接用在 template 上"></a>直接用在 template 上</h4><p>这种写法可以帮助你在自身的组件内复用一些颗粒度更小的组件,它和 setup 语法糖的写法非常接近,只是 User 变量可以作为标签直接使用。</p>
210<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  <span class="language-xml"><span class="tag">&lt;<span class="name">User</span> /&gt;</span></span></span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">script</span> <span class="attr">setup</span> <span class="attr">lang</span>=<span class="string">&quot;tsx&quot;</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">import</span> &#123; ref &#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span>;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">const</span> name = <span class="title function_">ref</span>(<span class="string">&quot;天气好&quot;</span>);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">const</span> <span class="title class_">User</span> = <span class="language-xml"><span class="tag">&lt;&gt;</span>&#123;name.value&#125;<span class="tag">&lt;/&gt;</span></span></span></span>;</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line"><span class="language-xml"><span class="language-handlebars"><span class="language-xml"><span class="tag">&lt;<span class="name">style</span>&gt;</span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span></span></span></span><br></pre></td></tr></table></figure>
211<h4 id="函数式组件(其一)"><a href="#函数式组件(其一)" class="headerlink" title="函数式组件(其一)"></a>函数式组件(其一)</h4><p>你还可以将 User 写成函数式组件,在本页面内使用。但它不会将连字符属性转换为小驼峰写法。这和「直接用在 template 上」的内容都是一样的,它们都是为了方便在组件本身复用一些常用的组件。</p>
212<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  <span class="language-xml"><span class="tag">&lt;<span class="name">User</span> <span class="attr">:user-name</span>=<span class="string">&quot;name&quot;</span> /&gt;</span></span></span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">script</span> <span class="attr">setup</span> <span class="attr">lang</span>=<span class="string">&quot;tsx&quot;</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">
212import</span> &#123; ref &#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span>;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">const</span> name = <span class="title function_">ref</span>(<span class="string">&quot;天气好&quot;</span>);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">const</span> <span class="title function_">User</span> = (<span class="params">props: &#123; <span class="string">&quot;user-name&quot;</span>: string &#125;</span>) =&gt; &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="keyword">return</span> <span class="language-xml"><span class="tag">&lt;&gt;</span>&#123;props[&quot;user-name&quot;]&#125;<span class="tag">&lt;/&gt;</span></span></span></span>;</span><br><span class="line">&#125;;</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line"><span class="language-xml"><span class="language-handlebars"><span class="language-xml"><span class="tag">&lt;<span class="name">style</span>&gt;</span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span></span></span></span><br></pre></td></tr></table></figure>
213<p>如果你经常使用 tailwind,你可能就会知道什么情况下会出现小颗粒度的可复用标签,比如,一个加了一大堆类名的 div 标签。</p>
214<h3 id="独立的-Jsx-文件"><a href="#独立的-Jsx-文件" class="headerlink" title="独立的 Jsx 文件"></a>独立的 Jsx 文件</h3><p>以上介绍的所有写法,都是在 .vue 文件中书写的,而且也离不开 
214<script lang="tsx">。接下来的写法可以让我们脱离 Vue 的语法块框架,书写更像 jsx 的 jsx。</p>
215<h4 id="jsx-定义组件"><a href="#jsx-定义组件" class="headerlink" title="jsx 定义组件"></a>jsx 定义组件</h4><p>我们需要新建一个 jsx/tsx 文件,然后只要保证导出的仍然是一个组件就可以了。有了前面的铺垫,我们不难发现,这不就是去掉 script 标签的选项式写法吗?确实!这是因为我故意在前面安排了选项式写法的例子,所以过渡到这里完全没有压力!</p>
216<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// User.tsx</span></span><br><span class="line"><span class="keyword">import</span> &#123; ref &#125; <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="title function_">setup</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> name = <span class="title function_">ref</span>(<span class="string">&#x27;天气好&#x27;</span>)</span><br><span class="line">    <span class="keyword">return</span> <span class="function">() =&gt;</span> <span class="language-xml"><span class="tag">&lt;&gt;</span><span class="tag">&lt;<span class="name">div</span>&gt;</span>&#123;name.value&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span><span class="tag">&lt;/&gt;</span></span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
217<p>我还是推荐套上 defineComponent:</p>
218<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// User.tsx</span></span><br><span class="line"><span class="keyword">import</span> &#123; ref, defineComponent &#125; <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title function_">defineComponent</span>(&#123;</span><br><span class="line">  <span class="title function_">setup</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> name = <span class="title function_">ref</span>(<span class="string">&#x27;天气好&#x27;</span>)</span><br><span class="line">    <span class="keyword">return</span> <span class="function">() =&gt;</span> (<span class="language-xml"><span class="tag">&lt;&gt;</span><span class="tag">&lt;<span class="name">div</span>&gt;</span>&#123;name.value&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span><span class="tag">&lt;/&gt;</span></span>)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>
219<p>同样地,前面对于 defineComponent 不同方式的使用这里也都可以的。比如导出普通对象并在 render 或者 setup 中使用 jsx 等等。从 vue 到 jsx,区别只是省下了 script 语法块。</p>
220<p>vue2 选项式写法+jsx。</p>
221<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// User.tsx</span></span><br><span class="line"><span class="keyword">
221import</span> &#123; defineComponent &#125; <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title function_">defineComponent</span>(&#123;</span><br><span class="line">  <span class="attr">data</span>: <span class="function">() =&gt;</span> (&#123; <span class="attr">name</span>: <span class="string">&#x27;天气好&#x27;</span> &#125;),</span><br><span class="line">  <span class="title function_">render</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="language-xml"><span class="tag">&lt;&gt;</span><span class="tag">&lt;<span class="name">div</span>&gt;</span>&#123;this.name&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span><span class="tag">&lt;/&gt;</span></span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>
222<p>导出普通对象:</p>
223<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// User.tsx</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="attr">data</span>: <span class="function">() =&gt;</span> (&#123; <span class="attr">name</span>: <span class="string">&#x27;天气好&#x27;</span> &#125;),</span><br><span class="line">  <span class="title function_">render</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="language-xml"><span class="tag">&lt;&gt;</span><span class="tag">&lt;<span class="name">div</span>&gt;</span>&#123;this.name&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span><span class="tag">&lt;/&gt;</span></span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>
224<h4 id="函数式组件(其二)"><a href="#函数式组件(其二)" class="headerlink" title="函数式组件(其二)"></a>函数式组件(其二)</h4><p>Vue 中支持的最像函数式组件的写法。</p>
225<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// User.tsx</span></span><br><span class="line"><span class="keyword">import</span> &#123; ref &#125; <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">function</span> <span class="title function_">User</span>(<span class="params">props</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> name = <span class="title function_">ref</span>(<span class="string">&#x27;天气好&#x27;</span>)</span><br><span class="line">  <span class="keyword">return</span> <span class="language-xml"><span class="tag">&lt;&gt;</span><span class="tag">&lt;<span class="name">div</span>&gt;</span>&#123;name.value&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span><span class="tag">&lt;/&gt;</span></span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
226<p>该例和前面的「自行导出 vNode 对象」非常接近,这也是为什么即使后者存在不能接收参数的缺陷我也会提出来,因为二者都是使用接近函数式组件的写法来描述组件的,但是在 vue 文件中并没有办法直接导出这个函数组件,而是需要自行执行得到vNode。而在 jsx 文件中却可以将其导出,并且支持接收参数。</p>
227<p>如果你需要为其定义 props,也不需要使用 「defineComponent 的第二个参数」为你提供什么 props 选项,而是直接在函数式组件的 props 、emits 属性上挂载对应的配置。</p>
228<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">
228import</span> &#123; ref &#125; <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="title class_">User</span>.<span class="property">props</span> = &#123;</span><br><span class="line">  <span class="attr">userName</span>: <span class="title class_">String</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">User</span>(<span class="params">props</span>) &#123;</span><br><span class="line">  <span class="comment">// const name = ref(&#x27;天气好&#x27;)</span></span><br><span class="line">  <span class="keyword">return</span> <span class="language-xml"><span class="tag">&lt;&gt;</span><span class="tag">&lt;<span class="name">div</span>&gt;</span>&#123;props.userName&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span><span class="tag">&lt;/&gt;</span></span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title class_">User</span>;</span><br></pre></td></tr></table></figure>
229<p>相信习惯了 React 的 fc 的小伙伴,看到这里一定感觉倍感亲切。然而 Vue 的 Jsx 终究只是 Vue 的 Jsx,它并没有像 React 一样存在那么多强大的 Hooks 和内置组件,而是仅仅只是 h 函数的便捷写法。在语法上也和 React Jsx 存在诸多区别。和 React Jsx 相比,Vue Jsx 其实和自家的 template 更接近。不过 Vue Jsx 写法的灵活性还是要比 template 模板高,但官方更推荐使用 template。template 更容易上手且提供了更好的性能优化,除非你想完完全全掌控组件的每一个细节,才需要jsx。</p>
230<h3 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h3><p>尽管本文提到了很多种写法,但大多数写法在大多数时候都是不会派上用场的,也应该不被派上用场。之所以列举那么多写法,主要的目的还是为了循序渐进引入 jsx 文件写法和函数式组件写法。</p>
231<p>可以看出,Vue 的写法本质上是选项式的。Vue3 在 Vue2 的基础上引入了 setup 选项和 setup 语法糖,结合组合式 api 后,开发者可以将组件的大部分逻辑都维护在 setup 中,而不是 vue2 中割裂了逻辑的 data+created+methods 选项。</p>
232<p>在此基础上,setup 语法糖支持自动导出组件功能,为我们日常开发带来了很大的便利。</p>
233<p>但是除了使用 template 来表达我们的结构,我们也可以自己使用 render 选项并借助 h 函数或者 jsx 的力量来手写渲染函数。这些都是在 vue 文件中完成的。</p>
234<p>既然都不需要 template 了,那么 vue 文件里就只剩下一个 script 了(我们先忽略 style)。在 jsx 文件中,就允许我们直接书写导出对象(仍是选项式的写法),忽略script。</p>
235<p>最后是 Vue 的 jsx 文件独有的特性。它允许我们导出一个函数作为组件,我们称之为函数式组件(fc,function component),这是 vue 文件和以前所有写法所不具备的,外形与 React 相近。</p>
236<p>总的来说就一句话,「Vue 本身仍然是选项式的,但是它现在还额外支持了在 jsx 文件中书写 fc。」</p>
237<h3 id="个人看法"><a href="#个人看法" class="headerlink" title="个人看法"></a>个人看法</h3><p>使用哪一种写法,主要看个人偏好。每种写法在特定场景下都有它的好处和坏处。选择哪一种并不重要。但是我还是提几点个人建议:</p>
238<ol>
239<li>优先选择 setup 语法糖。</li>
240<li>使用选项式时,推荐套上 defineComponent。</li>
241<li>当需要使用 jsx 时,推荐在 vue 文件中使用选项式 setup+返回 jsx 渲染函数的写法。</li>
242</ol>
243<p>为什么不推荐函数式组件的写法,因为它需要写在 jsx 文件里。如果你只是想通过 jsx 为你的组件增强某些功能,直接改造 vue 文件更加方便,并且不需要修改你引入文件的后缀<code>(.vue -&gt; .jsx/.tsx)</code>。最重要的是,如果真的想写函数式组件,为何不试试 Reactï¼
243Ÿ</p>
244</article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta"><i class="fas fa-circle-user fa-fw"></i>文章作者: </span><span class="post-copyright-info"><a href="https://whyta.cn">YangTao</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta"><i class="fas fa-square-arrow-up-right fa-fw"></i>文章链接: </span><span class="post-copyright-info"><a href="https://whyta.cn/post/0dced23f9a71/">https://whyta.cn/post/0dced23f9a71/</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta"><i class="fas fa-circle-exclamation fa-fw"></i>版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外,均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="https://whyta.cn" target="_blank">前端日记</a>!</span></div></div><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/Vue/">Vue</a></div><div class="post_share"><div class="social-share" data-image="https://xiaojinhe-cdn.iyoudui.cn/upload/common/2023/avata.jpg" data-sites="facebook,twitter,wechat,weibo,qq"></div><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/butterfly-extsrc/sharejs/dist/css/share.min.css" media="print" onload="this.media='all'">
244<script src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/sharejs/dist/js/social-share.min.js" defer></script>
244</div></div><nav class="pagination-post" id="pagination"><div class="next-post pull-full"><a href="/post/421b80af7984/" title="GitHub"><div class="cover" style="background: var(--default-bg-color)"></div><div class="pagination-info"><div class="label">下一篇</div><div class="next_info">GitHub</div></div></a></div></nav><div class="relatedPosts"><div class="headline"><i class="fas fa-thumbs-up fa-fw"></i><span>相关推荐</span></div><div class="relatedPosts-list"><div><a href="/post/d6ec52dcc745/" title="Vue 动态添加路由及生成菜单"><div class="cover" style="background: var(--default-bg-color)"></div><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2023-11-29</div><div class="title">Vue 动态添加路由及生成菜单</div></div></a></div><div><a href="/post/cb1902f58a3e/" title="Vue 改变数据,页面不刷新的问题"><div class="cover" style="background: var(--default-bg-color)"></div><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2023-12-01</div><div class="title">Vue 改变数据,页面不刷新的问题</div></div></a></div><div><a href="/post/69044459c6ec/" title="Vue 页面权限控制和登陆验证"><div class="cover" style="background: var(--default-bg-color)"></div><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2023-12-01</div><div class="title">Vue 页面权限控制和登陆验证</div></div></a></div></div></div><hr class="custom-hr"/><div id="post-comment"><div class="comment-head"><div class="comment-headline"><i class="fas fa-comments fa-fw"></i><span> 评论</span></div><div class="comment-switch"><span class="first-comment">Gitalk</span><span id="switch-btn"></span><span class="second-comment">Valine</span></div></div><div class="comment-wrap"><div><div id="gitalk-container"></div></div><div><div class="vcomment" id="vcomment"></div></div></div></div></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="is-center"><div class="avatar-img"><img src="https://xiaojinhe-cdn.iyoudui.cn/upload/common/2023/avata.jpg" onerror="this.onerror=null;this.src='/img/friend_404.gif'" alt="avatar"/></div><div class="author-info__name">YangTao</div><div class="author-info__description">share & study</div></div><div class="card-info-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">296</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">31</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">11</div></a></div><a id="card-info-btn" target="_blank" rel="noopener" href="https://github.com/ytanck"><i class="fab fa-github"></i><span>Follow Me</span></a><div class="card-info-social-icons is-center"><a class="social-icon" href="https://github.com/ytanck" target="_blank" title="Github"><i class="fab fa-github" style="color: #24292e;"></i></a><a class="social-icon" href="mailto:[email protected]" target="_blank" title="Email"><i class="fas fa-envelope" style="color: #4a7dbe;"></i></a></div></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn fa-shake"></i><span>公告</span></div><div class="announcement_content">=>我的个人网站,分享前端技术及踩坑记录。如果喜欢,欢迎Star!</div></div><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span><span class="toc-percentage"></span></div><div class="toc-content"><ol class="toc"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%BC%95%E5%85%A5"><span class="toc-number">1.</span> <span class="toc-text">引入</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#setup-%E8%AF%AD%E6%B3%95%E7%B3%96"><span class="toc-number">2.</span> <span class="toc-text">setup 语法糖</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Vue2-%E9%80%89%E9%A1%B9%E5%BC%8F%E5%86%99%E6%B3%95"><span class="toc-number">3.</span> <span class="toc-text">Vue2 选项式写法</span></a><ol class="toc-child"><li class="toc-item toc-level-4">
244<a class="toc-link" href="#Vue2-%E7%BB%8F%E5%85%B8%E5%86%99%E6%B3%95"><span class="toc-number">3.1.</span> <span class="toc-text">Vue2 经典写法</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#defineComponent-%E8%BE%85%E5%8A%A9%E5%87%BD%E6%95%B0"><span class="toc-number">3.2.</span> <span class="toc-text">defineComponent 辅助函数</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Vue3-%E9%80%89%E9%A1%B9%E5%BC%8F%E5%86%99%E6%B3%95"><span class="toc-number">4.</span> <span class="toc-text">Vue3 选项式写法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%89%8B%E5%86%99%E6%B8%B2%E6%9F%93%E5%87%BD%E6%95%B0"><span class="toc-number">5.</span> <span class="toc-text">手写渲染函数</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#setup-%E8%BF%94%E5%9B%9E%E6%B8%B2%E6%9F%93%E5%87%BD%E6%95%B0"><span class="toc-number">6.</span> <span class="toc-text">setup 返回渲染函数</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#setup-%E8%BF%94%E5%9B%9E-render-%E6%96%B9%E6%B3%95"><span class="toc-number">6.1.</span> <span class="toc-text">setup 返回 render 方法</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#defineComponent-%E4%BC%A0%E5%85%A5setup"><span class="toc-number">6.2.</span> <span class="toc-text">defineComponent 传入setup</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Vue-Jsx"><span class="toc-number">7.</span> <span class="toc-text">Vue &amp; Jsx</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%9C%A8render-%E4%B8%AD%E4%BD%BF%E7%94%A8-jsx"><span class="toc-number">7.1.</span> <span class="toc-text">在render 中使用 jsx</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%9C%A8-setup-%E4%B8%AD%E4%BD%BF%E7%94%A8jsx"><span class="toc-number">7.2.</span> <span class="toc-text">在 setup 中使用jsx</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#defineComponent-%E7%AE%80%E5%86%99"><span class="toc-number">7.3.</span> <span class="toc-text">defineComponent 简写</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E8%87%AA%E8%A1%8C%E5%AF%BC%E5%87%BA-vNo
244de-%E5%AF%B9%E8%B1%A1"><span class="toc-number">7.4.</span> <span class="toc-text">自行导出 vNode 对象</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#defineComponent-%E7%9A%84%E7%AC%AC%E4%BA%8C%E4%B8%AA%E5%8F%82%E6%95%B0"><span class="toc-number">7.5.</span> <span class="toc-text">defineComponent 的第二个参数</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%9B%B4%E6%8E%A5%E5%9C%A8-vue-%E4%B8%AD%E4%BD%BF%E7%94%A8-jsx"><span class="toc-number">8.</span> <span class="toc-text">直接在 vue 中使用 jsx</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E7%9B%B4%E6%8E%A5%E5%AF%BC%E5%87%BA-jsx-%E5%AF%B9%E8%B1%A1"><span class="toc-number">8.1.</span> <span class="toc-text">直接导出 jsx 对象</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E7%9B%B4%E6%8E%A5%E7%94%A8%E5%9C%A8-template-%E4%B8%8A"><span class="toc-number">8.2.</span> <span class="toc-text">直接用在 template 上</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%87%BD%E6%95%B0%E5%BC%8F%E7%BB%84%E4%BB%B6%EF%BC%88%E5%85%B6%E4%B8%80%EF%BC%89"><span class="toc-number">8.3.</span> <span class="toc-text">函数式组件(其一)</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%8B%AC%E7%AB%8B%E7%9A%84-Jsx-%E6%96%87%E4%BB%B6"><span class="toc-number">9.</span> <span class="toc-text">独立的 Jsx 文件</span></a></li></ol></div></div><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最新文章</span></div><div class="aside-list"><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/post/0dced23f9a71/" title="Vue的不同风格写法,你知道么?">Vue的不同风格写法,你知道么?</a><time datetime="2024-10-24T10:52:24.000Z" title="发表于 2024-10-24 10:52:24">2024-10-24</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/post/421b80af7984/" title="GitHub">GitHub</a><time datetime="2024-10-24T02:58:54.469Z" title="发表于 2024-10-24 02:58:54">2024-10-24</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/post/d9b2231487d1/" title="一文解读react-hook(useState、useReducer、useEffect、useCallback、useMemo、useRef、useContext...)">一文解读react-hook(useState、useReducer、useEffect、useCallback、useMemo、useRef、useContext...)</a><time datetime="2024-09-06T10:02:42.000Z" title="发表于 2024-09-06 10:02:42">2024-09-06</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/post/dc707376a421/" title="GPT4升级指南(2024年5月最新)">GPT4升级指南(2024年5月最新)</a><time datetime="2024-05-15T10:21:23.000Z" title="发表于 2024-05-15 10:21:23">2024-05-15</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/post/a4dd5826810e/" title="CSS @符号规则的使用(@font-face、@keyframes、@media、@scope等)">CSS @符号规则的使用(@font-face、@keyframes、@media、@scope等)</a><time datetime="2024-02-20T11:23:26.000Z" title="发表于 2024-02-20 11:23:26">2024-02-20</time></div></div></div></div></div></div></main><footer id="footer"><div id="footer-wrap"><div class="copyright">&copy;2023 - 2024 By YangTao</div><div class="footer_custom_text"><a target="_blank" rel="noopener" href="https://beian.miit.gov.cn/"><span>鄂ICP备2021000562号</span></a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="translateLink" type="button" title="简繁转换">简</button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside-config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><button id="chat-btn" type="button" title="聊天"><i class="fas fa-sms"></i></button><a id="to_comment" href="#post-comment" title="直达评论"><i class="fas fa-comments"></i></a><button id="go-up" type="button" title="回到顶部"><span class="scroll-percent"></span><i class="fas fa-arrow-up"></i></button></div></div><div>
244<script src="/js/utils.js"></script>
244<script src="/js/main.js"></script>
244<script src="/js/tw_cn.js"></script>
244<script src="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox/fancybox.umd.min.js"></script>
244<div class="js-pjax">
244<script>(() => {
245  const initGitalk = () => {
246    const gitalk = new Gitalk(Object.assign({
247      clientID: '82c5496065cfe6d3d6d6',
248      clientSecret: '798e420c011e4d4eb32f94b0e6261830a24c3c96',
249      repo: 'ytanck.github.io',
250      owner: 'ytanck',
251      admin: ['ytanck'],
252      id: '9a94d3f53b6acc5de2c064cc85b61876',
253      updateCountCallback: commentCount
254    },null))
255
256    gitalk.render('gitalk-container')
257  }
258
259  const loadGitalk = async() => {
260    if (typeof Gitalk === 'function') initGitalk()
261    else {
262      await getCSS('https://cdn.jsdelivr.net/npm/gitalk/dist/gitalk.min.css')
263      await getScript('https://cdn.jsdelivr.net/npm/gitalk/dist/gitalk.min.js')
264      initGitalk()
265    }
266  }
267  
268  const commentCount = n => {
269    const isCommentCount = document.querySelector('#post-meta .gitalk-comment-count')
270    if (isCommentCount) {
271      isCommentCount.textContent= n
272    }
273  }
274
275  if ('Gitalk' === 'Gitalk' || !false) {
276    if (false) btf.loadComment(document.getElementById('gitalk-container'), loadGitalk)
277    else loadGitalk()
278  } else {
279    window.loadOtherComment = loadGitalk
280  }
281})()</script>
281<script>(() => {
282  const initValine = () => {
283    const valine = new Valine(Object.assign({
284      el: '#vcomment',
285      appId: 'epBB1Z21rnGhwEtsu57MeE1d-gzGzoHsz',
286      appKey: 'jzsxVdOEZgUj76hevYcbr4pV',
287      avatar: '',
288      serverURLs: 'https://epbb1z21.lc-cn-n1-shared.com',
289      emojiMaps: "",
290      path: window.location.pathname,
291      visitor: false
292    }, null))
293  }
294
295  const loadValine = async () => {
296    if (typeof Valine === 'function') initValine()
297    else {
298      await getScript('https://cdn.jsdelivr.net/npm/valine/dist/Valine.min.js')
299      initValine()
300    }
301  }
302
303  if ('Gitalk' === 'Valine' || !false) {
304    if (false) btf.loadComment(document.getElementById('vcomment'),loadValine)
305    else setTimeout(loadValine, 0)
306  } else {
307    window.loadOtherComment = loadValine
308  }
309})()</script>
309</div>
309<script id="canvas_nest" defer="defer" color="0,0,255" opacity="0.7" zIndex="-1" count="99" mobile="false" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/dist/canvas-nest.min.js"></script>
309<script id="click-heart" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/dist/click-heart.min.js" async="async" mobile="false"></script>
309<script>(() => {
310  const isChatBtn = true
311  const isChatHideShow = false
312
313  if (isChatBtn) {
314    const close = () => {
315      Chatra('minimizeWidget')
316      Chatra('hide')
317    }
318
319    const open = () => {
320      Chatra('openChat', true)
321      Chatra('show')
322    }
323
324    window.ChatraSetup = {
325      startHidden: true
326    }
327  
328    window.chatBtnFn = () => {
329      const isShow = document.getElementById('chatra').classList.contains('chatra--expanded')
330      isShow ? close() : open()
331    }
332  } else if (isChatHideShow) {
333    window.chatBtn = {
334      hide: () => {
335        Chatra('hide')
336      },
337      show: () => {
338        Chatra('show')
339      }
340    }
341  }
342
343  (function(d, w, c) {
344    w.ChatraID = 'PhLXQufxgCL6iLDEc'
345    var s = d.createElement('script')
346    w[c] = w[c] || function() {
347        (w[c].q = w[c].q || []).push(arguments)
348    }
349    s.async = true
350    s.src = 'https://call.chatra.io/chatra.js'
351    if (d.head) d.head.appendChild(s)
352  })(document, window, 'Chatra')
353
354})()</script>
354<div id="local-search"><div class="search-dialog"><nav class="search-nav"><span class="search-dialog-title">搜索</span><span id="loading-status"></span><button class="search-close-button"><i class="fas fa-times"></i></button></nav><div class="is-center" id="loading-database"><i class="fas fa-spinner fa-pulse"></i><span>  数据库加载中</span></div><div class="search-wrap"><div id="local-search-input"><div class="local-search-box"><input class="local-search-box--input" placeholder="搜索文章" type="text"/></div></div><hr/><div id="local-search-results"></div><div id="local-search-stats-wrap"></div></div></div><div id="search-mask"></div>
354<script src="/js/search/local-search.js"></script>
354</div></div></body></html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.