Vue.extend
Он относится к глобальному API Vue, который мы редко используем в реальной разработке бизнеса, потому что по сравнению с обычно используемымVue.component
использование письмаextend
Шаги более сложные. Но в некоторых сценариях разработки независимых компонентов (например, в библиотеке ElementUI) поэтомуVue.extend
+ $mount
Это очень нужно для комбинации, и мы должны это понимать.
Vue.component
Использование официального сайта:
Зарегистрируйтесь или получите глобальные компоненты. Регистрация также автоматически использует данныйid
Задайте имя компонента
// 注册组件,传入一个扩展过的构造器
Vue.component('my-component', Vue.extend({ /* ... */ }))
// 注册组件,传入一个选项对象 (自动调用 Vue.extend)
Vue.component('my-component', { /* ... */ })
// 获取注册的组件 (始终返回构造器)
var MyComponent = Vue.component('my-component')
let ElInput = Vue.component('ElInput');
console.log(new ElInput); // 就是Inout的实例
Использование также очень простое: компоненты, которые вы пишете, могут быть импортированы непосредственно в main.js, а затем использованы.Vue.component('xx-xxx',xxx)
Его можно использовать глобально.
-
выгода
- Такой
好处
То есть все страницы в основном управляются роутером и могут быть зарегистрированы напрямую, нам не нужно обращать внимание на создание компонентов.extend
быть более непринужденным
- Такой
-
недостаток
- Имена компонентов все пользовательские, что, если я хочу динамически отображать из интерфейса. [extend не обязательно выполнять во время инициализации, ниже приведены примеры]
- есть контент
#app
Рендеринг вниз, зарегистрированные компоненты визуализируются в текущей позиции. Если я захочу реализовать компонент подсказки для модального окна, это будет довольно безвкусно.
В этот момент,Vue.extend + vm.$mount
Комбинация пригодится.
Vue.extend
Использование официального сайта:
<div id="mount-point"></div>
// 创建构造器
var Profile = Vue.extend({
template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>',
data: function () {
return {
firstName: 'Walter',
lastName: 'White',
alias: 'Heisenberg'
}
}
})
// 创建 Profile 实例,并挂载到一个元素上。
new Profile().$mount('#mount-point')
Результат выглядит следующим образом:
<p>Walter White aka Heisenberg</p>
Его можно найтиId
дляmount-point
div, заменяется непосредственно, не заполняется внутри, в нашемmain.js
То же самое верно и при использовании волос при инициализации:
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app'); // 此处都是替换,不是填充
Следующий простой анализ$mount
исходный код
// src/platforms/web/entry-runtime-with-compiler.js
import config from 'core/config'
import {warn, cached} from 'core/util/index'
import {mark, measure} from 'core/util/perf'
import Vue from './runtime/index'
import {query} from './util/index'
import {compileToFunctions} from './compiler/index'
import {shouldDecodeNewlines, shouldDecodeNewlinesForHref} from './util/compat'
const idToTemplate = cached(id => {
const el = query(id)
return el && el.innerHTML
})
const mount = Vue.prototype.$mount; // 缓存了原型上的 $mount 方法
Vue.prototype.$mount = function (el, hydrating) {
el = el && query(el) // 通过 query函数 就是获取真实的DOM元素
// 判断获取的真实 dom元素是否为 body 或 documentElement 报警告
if (el === document.body || el === document.documentElement) {
process.env.NODE_ENV !== 'production' && warn(
`Do not mount Vue to <html> or <body> - mount to normal elements instead.`
)
return this
}
const options = this.$options
// 判断有么有render , 咱们一般都是用 template 写的vue,需要编译
if (!options.render) {
let template = options.template
if (template) {
if (typeof template === 'string') {
if (template.charAt(0) === '#') {
template = idToTemplate(template)
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && !template) {
warn(
`Template element not found or is empty: ${options.template}`,
this
)
}
}
} else if (template.nodeType) {
template = template.innerHTML
} else {
if (process.env.NODE_ENV !== 'production') {
warn('invalid template option:' + template, this)
}
return this
}
} else if (el) {
template = getOuterHTML(el) // 即获取 el 的 outerHTML
}
if (template) {
// 然后通过compileToFunctions将 template 转化为 render 函数,options.render = render
// 所有 Vue 的组件的渲染最终都需要 render 方法,无论是用单页面 .vue 方式开发,还是写了 el 或者 template 属性,
// 最终都要被转成 render 方法,那么这个过程是 Vue 的一个 “在线编译” 的过程, 它是调用 compileToFunctions 方法实现的,最后调用原型上的 $mount 方法挂载。
const {render, staticRenderFns} = compileToFunctions(template, {
outputSourceRange: process.env.NODE_ENV !== 'production',
shouldDecodeNewlines,
shouldDecodeNewlinesForHref,
delimiters: options.delimiters,
comments: options.comments
}, this)
options.render = render
options.staticRenderFns = staticRenderFns
}
}
// 如果没有传el的话,会直接执行这步,会把组件在内存中渲染完毕
return mount.call(this, el, hydrating)
}
// 及时获取HTML 兼容IE
function getOuterHTML(el): string {
if (el.outerHTML) {
return el.outerHTML
} else {
const container = document.createElement('div')
container.appendChild(el.cloneNode(true))
return container.innerHTML
}
}
Vue.compile = compileToFunctions
export default Vue
-
$mount
Метод поддерживает передачу двух параметров, первый — el, который представляет смонтированный элемент, который может быть строкой или объектом DOM.Если это строка, будет вызван метод запроса для преобразования его в объект DOM в среда браузера. Второй параметр связан с рендерингом на стороне сервера, и нет необходимости передавать второй параметр в среде браузера. -
$mount
метод действительно вызоветmountComponent
метод, метод определен вsrc/core/instance/lifecycle.js
середина
Реализовать всплывающий компонент
// message/src/index.vue
<template>
<div class="wrap">
<div class="message" :class="item.type" v-for="item in notices" :key="item._name">
<div class="content">{{item.content}}</div>
</div>
</div>
</template>
<script>
// 默认选项
const defaultOptions = {
duration: 1500,
type: 'info',
content: '这是一条提示信息!',
}
let mid = 0
export default {
name:'MyMessage', // 建议添加方便外面直接取值
data() {
return {
notices: []
}
},
methods: {
addMessage(notice = {}) {
// name标识 用于移除弹窗
let _name = this.getName()
// 合并选项
notice = Object.assign({
_name
}, defaultOptions, notice)
this.notices.push(notice)
setTimeout(() => {
this.removeNotice(_name)
}, notice.duration)
},
getName() {
return 'msg_' + (mid++) //创建一个唯一的值
},
removeNotice(_name) {
let index = this.notices.findIndex(item => item._name === _name)
this.notices.splice(index, 1) // 删除当前超时的dom
}
}
}
</script>
<style scoped>
.wrap {
position: fixed;
top: 50px;
left: 50%;
display: flex;
flex-direction: column;
align-items: center;
transform: translateX(-50%);
}
.message {
--borderWidth: 3px;
min-width: 240px;
max-width: 500px;
margin-bottom: 10px;
border-radius: 3px;
box-shadow: 0 0 8px #ddd;
overflow: hidden;
}
.content {
padding: 8px;
line-height: 1.3;
}
// 对应的集中状态
.message.info {
border-left: var(--borderWidth) solid #909399;
background: #F4F4F5;
}
.message.success {
border-left: var(--borderWidth) solid #67C23A;
background: #F0F9EB;
}
.message.error {
border-left: var(--borderWidth) solid #F56C6C;
background: #FEF0F0;
}
.message.warning {
border-left: var(--borderWidth) solid #E6A23C;
background: #FDF6EC;
}
</style>
// message/index.js
import Vue from 'vue'
import Message from './src/index.vue'
let messageInstance = null
let TempMessage = ''
// 模拟异步请求
setTimeout(() => {
TempMessage = Message
}, 2000)
let init = () => {
let MessageConstructor = TempMessage && Vue.extend(TempMessage)
messageInstance = new MessageConstructor({})// 构造函数可以接传值,data、methods.....
// console.log(messageInstance);
// $mount()不带参数,会把组件在内存中渲染完毕
messageInstance.$mount()
// messageInstance.$el 拿到的就是组件对应的dom元素,可以直接操作dom
document.body.appendChild(messageInstance.$el)
messageInstance.$el.style.zIndex = 9999
}
let caller = (options) => {
if (!messageInstance) {
// 进页面初始化
init(options)
}
// addMessage 是组件内部声明的方法,也可以通过构造函数传对应的方法
messageInstance.addMessage(options)
}
export default {
install(vue) {
vue.prototype.$mymessage = caller
}
}
// main.js
import Message from '@/components/Message/index.js'
Vue.use(Message)
использовать
this.$mymessage({
type: 'warning',
content: '你好坏啊,我好喜欢',
duration: 6000
})