@@ -50,9 +53,9 @@ import Home from '@theme/components/Home.vue'
import Navbar from '@theme/components/Navbar.vue'
import Page from '@theme/components/Page.vue'
import Sidebar from '@theme/components/Sidebar.vue'
+import VueMasteryBanner from '@theme/components/sponsors/VueMasteryBanner.vue'
import BuySellAds from '@theme/components/BuySellAds.vue'
import CarbonAds from '@theme/components/CarbonAds.vue'
-import BannerTop from '@theme/components/BannerTop.vue'
import { resolveSidebarItems } from '../util'
export default {
@@ -63,15 +66,18 @@ export default {
Page,
Sidebar,
Navbar,
- BannerTop,
+ VueMasteryBanner,
BuySellAds,
CarbonAds
},
data() {
return {
- showTopBanner: false,
- isSidebarOpen: false
+ isSidebarOpen: false,
+ isBannerOpen: false,
+ isMenuFixed: false,
+ nameStorage: 'vuemastery-banner--free-weekend-december-2021',
+ menuPosition: 0
}
},
@@ -116,7 +122,8 @@ export default {
'no-navbar': !this.shouldShowNavbar,
'sidebar-open': this.isSidebarOpen,
'no-sidebar': !this.shouldShowSidebar,
- 'has-top-banner': this.showTopBanner
+ 'vuemastery-menu-fixed': this.isMenuFixed,
+ 'vuemastery-promo': this.isBannerOpen
},
userPageClass
]
@@ -132,7 +139,12 @@ export default {
this.isSidebarOpen = false
})
- this.showTopBanner = false
+ this.isBannerOpen = !localStorage.getItem(this.nameStorage)
+
+ // Load component according to user preferences
+ if (this.isBannerOpen) {
+ this.$nextTick(this.initBanner)
+ }
},
methods: {
@@ -159,6 +171,52 @@ export default {
this.toggleSidebar(false)
}
}
+ },
+
+ // Vue Mastery Banner
+ initBanner() {
+ // Add event listeners
+ this.toggleBannerEvents(true)
+ // Get the menu position
+ this.getMenuPosition()
+ // Check current page offset position
+ this.isMenuFixed = this.isUnderBanner()
+ },
+
+ closeBanner(e) {
+ // Remove events
+ this.toggleBannerEvents(false)
+ // Hide the banner
+ this.isBannerOpen = false
+ // Save action in the local storage
+ localStorage.setItem(this.nameStorage, true)
+ },
+
+ getMenuPosition() {
+ this.menuPosition = this.$refs.vueMasteryBanner.$el.clientHeight
+ },
+
+ isUnderBanner() {
+ return window.pageYOffset > this.menuPosition
+ },
+
+ fixMenuAfterBanner() {
+ if (this.isUnderBanner()) {
+ if (!this.isMenuFixed) {
+ // The menu will be fixed
+ this.isMenuFixed = true
+ }
+ } else if (this.isMenuFixed) {
+ // The menu stay under the banner
+ this.isMenuFixed = false
+ }
+ },
+
+ toggleBannerEvents(on) {
+ // Add or remove event listerners attached to the DOM
+ let method = on ? 'addEventListener' : 'removeEventListener'
+ window[method]('resize', this.getMenuPosition)
+ window[method]('scroll', this.fixMenuAfterBanner)
}
}
}
diff --git a/src/.vuepress/theme/styles/index.styl b/src/.vuepress/theme/styles/index.styl
index f23c9de..d8e1bad 100644
--- a/src/.vuepress/theme/styles/index.styl
+++ b/src/.vuepress/theme/styles/index.styl
@@ -4,6 +4,7 @@
@require './arrow'
@require './wrapper'
@require './toc'
+@require './vuemastery-banner'
html, body
padding 0
diff --git a/src/.vuepress/theme/styles/vuemastery-banner.styl b/src/.vuepress/theme/styles/vuemastery-banner.styl
new file mode 100644
index 0000000..e71506d
--- /dev/null
+++ b/src/.vuepress/theme/styles/vuemastery-banner.styl
@@ -0,0 +1,243 @@
+.vuemastery-banner
+ background: url(/images/vuemastery/background-vuemastery.svg) center center no-repeat
+ background-size 100% auto
+ overflow hidden
+ position relative
+
+ &:before
+ content ''
+ background: url(/images/vuemastery/background-bubbles-vuemastery.svg) left center no-repeat
+ background-size cover
+ position absolute
+ top 0
+ bottom 0
+ left 0
+ right 0
+ transition all .3s ease-out .1s
+ transform: scale(1.1)
+
+ &:after
+ content: ''
+ background: url(/images/vuemastery/lock-vuemastery.svg) right center no-repeat
+ background-size: auto 100%
+ position: absolute
+ width: 100%
+ height: 100%
+ top: 0
+ left: 0
+ pointer-events: none
+
+ &:hover
+ background-size 150% auto
+
+ &:before
+ transform: scale(1)
+
+ &:after
+ background-image url(/images/vuemastery/unlock-vuemastery.svg)
+
+ a
+ display flex
+ height 80px
+ justify-content center
+
+.vuemastery-banner--wrapper
+ display flex
+ height 100%
+ align-items center
+ width: 100%
+ justify-content: center
+ position relative
+
+ &:before
+ content ''
+ pointer-events none
+ position absolute
+ top 0
+ bottom 0
+ left 0
+ width 0
+ transition width .3s ease-out
+
+ &:hover
+ + .vuemastery-banner--close
+ &:before,
+ &:after
+ transform-origin 100%
+
+ p
+ margin -3px 50px 0 20px
+ font-size 1rem
+ line-height 1.4rem
+ color #fff
+ position relative
+ transition-delay .15s
+
+ span
+ font-size 1.17rem
+ font-weight 600
+ color #BEFF74
+ background -webkit-linear-gradient(#41E281, #BEFF74)
+ -webkit-background-clip text
+ -webkit-text-fill-color transparent
+
+@media screen and (min-width: 700px)
+ .vuemastery-banner--wrapper span
+ display block
+
+.vuemastery-banner--logo
+ height 102%
+ margin-top: -1px
+ margin-left -200px
+ position relative
+ z-index 2
+
+.vuemastery-banner--close
+ position absolute
+ top 20px
+ right 25px
+ height 40px
+ width 40px
+ -webkit-tap-highlight-color transparent
+ border-radius 50%
+ cursor pointer
+
+ &:before,
+ &:after
+ content ''
+ position absolute
+ top 19px
+ left 14px
+ width 25px
+ height 2px
+ background-color #fff
+ transform-origin 50%
+ transform rotate(-45deg)
+ transition all .2s ease-out
+
+ &:after
+ transform rotate(45deg)
+
+.vuemastery-button
+ display: inline-flex;
+ background: linear-gradient(to top right,#3d2c61,#835ec2);
+ height: 38px;
+ margin: .5em 0;
+ line-height: 38px;
+ padding: 0 30px;
+ color: #fff;
+ text-decoration: none;
+ align-items: center;
+ justify-content: center;
+ outline: 0;
+ text-transform: uppercase;
+ border: none;
+ border-radius: 36px;
+ font-weight: bold;
+ font-size: 12px;
+ cursor: pointer;
+ position: relative
+ overflow hidden
+
+ &:before,
+ &:after
+ background: linear-gradient(to top right,transparent,#fff);
+ content: "";
+ height: 150px;
+ left: -175px;
+ opacity: .1;
+ position: absolute;
+ top: -50px;
+ transform: rotate(35deg);
+ width: 100px;
+
+@media screen and (max-width: 1200px)
+ .vuemastery-banner
+ &,
+ &:hover
+ background-size cover
+
+ &:before
+ transform: scale(1)
+
+ &:hover:before
+ transform: scale(1)
+
+@media screen and (max-width: 1100px)
+ .vuemastery-button
+ display none
+
+@media screen and (max-width: 700px)
+ .vuemastery-banner
+ &:after
+ background-position right -2rem center
+ a
+ height 40px
+ overflow hidden
+
+ .vuemastery-banner--logo
+ margin-left 0
+ justify-content flex-start
+
+ p, span
+ font-size .8rem
+ color #fff
+ line-height .9rem
+
+ .vuemastery-banner--close
+ top 0px
+ right 0px
+
+ &:before,
+ &:after
+ top 19px
+ left 14px
+ width 15px
+ height 2px
+
+@media screen and (max-width: 465px)
+ .vuemastery-banner
+ &:after
+ display: none
+ p
+ margin-right 40px
+ margin-left 5px
+
+ &:after
+ background-position right -3rem center
+@media screen and (max-width 330px)
+ .vuemastery-banner p
+ font-size 0.6rem
+ margin-right 20px
+ margin-left 0
+
+@media print
+ .vuemastery-banner
+ display none
+
+
+.vuemastery-promo
+ .navbar
+ position relative
+
+ .sidebar
+ position absolute
+ top 8.6rem
+ bottom -5rem
+
+ @media screen and (max-width: 700px)
+ top: 98px;
+ bottom: -20px;
+
+ &.vuemastery-menu-fixed
+ .vuemastery-banner
+ margin-bottom 56px
+
+ .sidebar,
+ .navbar
+ position fixed
+ top -1px
+
+ .sidebar
+ top 3.5rem
+ bottom 0
\ No newline at end of file
diff --git a/src/api/application-api.md b/src/api/application-api.md
index 2dd0d7b..f18b560 100644
--- a/src/api/application-api.md
+++ b/src/api/application-api.md
@@ -96,7 +96,8 @@ app.directive('my-directive', {
mounted() {},
// called before the containing component's VNode is updated
beforeUpdate() {},
- // called after the containing component's VNode and the VNodes of its children // have updated
+ // called after the containing component's VNode and the VNodes of its
+ // children have updated
updated() {},
// called before the bound element's parent component is unmounted
beforeUnmount() {},
diff --git a/src/api/built-in-components.md b/src/api/built-in-components.md
index 31b7c03..0f1e4bb 100644
--- a/src/api/built-in-components.md
+++ b/src/api/built-in-components.md
@@ -20,7 +20,7 @@ import { KeepAlive, Teleport, Transition, TransitionGroup } from 'vue'
- **Props:**
- - `is` - `string | Component`
+ - `is` - `string | Component | VNode`
- **Usage:**
@@ -41,6 +41,8 @@ import { KeepAlive, Teleport, Transition, TransitionGroup } from 'vue'
```
+- **Usage with built-in components:**
+
The built-in components `KeepAlive`, `Transition`, `TransitionGroup`, and `Teleport` can all be passed to `is`, but you must register them if you want to pass them by name. For example:
```js
@@ -62,15 +64,15 @@ import { KeepAlive, Teleport, Transition, TransitionGroup } from 'vue'
Registration is not required if you pass the component itself to `is` rather than its name.
-- **key:**
+- **Usage with VNodes:**
-When using and passing vnode of the same type, you need to provide keys:
-
-```html
-
-```
+ In advanced use cases, it can sometimes be useful to render an existing VNode via a template. Using a `` makes this possible, but it should be seen as an escape hatch, used to avoid rewriting the entire template as a `render` function.
+
+ ```html
+
+ ```
-Otherwise, you are passing two compiled vnodes of the same type to the renderer. Because they are compiled as completely static, they will not be updated at all.
+ A caveat of mixing VNodes and templates in this way is that you need to provide a suitable `key` attribute. The VNode will be considered static, so any updates will be ignored unless the `key` changes. The `key` can be on the VNode or the `` tag, but either way it must change every time you want the VNode to re-render. This caveat doesn't apply if the nodes have different types, e.g. changing a `span` to a `div`.
- **See also:** [Dynamic Components](../guide/component-dynamic-async.html)
diff --git a/src/api/directives.md b/src/api/directives.md
index b58ee87..02cc8a0 100644
--- a/src/api/directives.md
+++ b/src/api/directives.md
@@ -35,7 +35,7 @@
- **Example:**
```html
-
+
```
- **See also:** [Data Binding Syntax - Interpolations](../guide/template-syntax.html#raw-html)
diff --git a/src/api/sfc-script-setup.md b/src/api/sfc-script-setup.md
index cfb7b2b..cf73d93 100644
--- a/src/api/sfc-script-setup.md
+++ b/src/api/sfc-script-setup.md
@@ -131,6 +131,31 @@ import * as Form from './form-components'
```
+## Using Custom Directives
+
+Globally registered custom directives just work as expected, and local ones can be used directly in the template, much like we explained above for components.
+
+But there's one restriction to be aware of: You must name local custom directives according to the following schema: `vNameOfDirective` in order for them to be directly usable in the template.
+
+```html
+
+
+
This is a Heading
+
+```
+```html
+
+```
+
## `defineProps` and `defineEmits`
To declare `props` and `emits` in `
```
+:::warning
+`render` function is not supported in this scenario. Please use one normal `
```
### `entry-client.js`
-The client entry creates the application using the root component factory and mounts it to the DOM:
+The client entry creates the application using the `App.vue` component and mounts it to the DOM:
```js
-import createApp from './app'
+import { createSSRApp } from 'vue'
+import App from './App.vue'
// client-specific bootstrapping logic...
-const { app } = createApp({
- // here we can pass additional arguments to app factory
-})
+const app = createSSRApp(App)
// this assumes App.vue template root element has `id="app"`
app.mount('#app')
@@ -122,12 +143,11 @@ app.mount('#app')
The server entry uses a default export which is a function that can be called repeatedly for each render. At this moment, it doesn't do much other than returning the app instance - but later we will perform server-side route matching and data pre-fetching logic here.
```js
-import createApp from './app'
+import { createSSRApp } from 'vue'
+import App from './App.vue'
-export default function() {
- const { app } = createApp({
- /*...*/
- })
+export default function () {
+ const app = createSSRApp(App)
return {
app
diff --git a/src/guide/transitions-overview.md b/src/guide/transitions-overview.md
index eb98a33..ee20b1c 100644
--- a/src/guide/transitions-overview.md
+++ b/src/guide/transitions-overview.md
@@ -176,7 +176,7 @@ Easing can also convey the quality of material being animated. Take this pen for
-You can get a lot of unique effects and make your animation very stylish by adjusting your easing. CSS allows you to modify this by adjusting a cubic bezier property, [this playground](https://cubic-bezier.com/#.17,.67,.83,.67) by Lea Verou is very helpful for exploring this.
+You can get a lot of unique effects and make your animation very stylish by adjusting your easing. CSS allows you to modify this by adjusting the cubic-bezier function's parameters, [this playground](https://cubic-bezier.com/#.17,.67,.83,.67) by Lea Verou is very helpful for exploring this.
Though you can achieve great effects for simple animation with the two handles the cubic-bezier ease offers, JavaScript allows multiple handles, and therefore, allows for much more variance.
diff --git a/src/style-guide/README.md b/src/style-guide/README.md
index f0ed015..e337e82 100644
--- a/src/style-guide/README.md
+++ b/src/style-guide/README.md
@@ -1485,7 +1485,7 @@ Prefer class selectors over element selectors in `scoped` styles, because large
::: details Detailed Explanation
To scope styles, Vue adds a unique attribute to component elements, such as `data-v-f3f3eg9`. Then selectors are modified so that only matching elements with this attribute are selected (e.g. `button[data-v-f3f3eg9]`).
-The problem is that large numbers of [element-attribute selectors](http://stevesouders.com/efws/css-selectors/csscreate.php?n=1000&sel=a%5Bhref%5D&body=background%3A+%23CFD&ne=1000) (e.g. `button[data-v-f3f3eg9]`) will be considerably slower than [class-attribute selectors](http://stevesouders.com/efws/css-selectors/csscreate.php?n=1000&sel=.class%5Bhref%5D&body=background%3A+%23CFD&ne=1000) (e.g. `.btn-close[data-v-f3f3eg9]`), so class selectors should be preferred whenever possible.
+The problem is that large numbers of element-attribute selectors (e.g. `button[data-v-f3f3eg9]`) will be considerably slower than class-attribute selectors (e.g. `.btn-close[data-v-f3f3eg9]`), so class selectors should be preferred whenever possible.
:::