Vue
Официальный сайт описывает его как прогрессивный фреймворк для создания пользовательских интерфейсов;
Прогрессивная структура: при наименьшем количестве предложений каждая структура неизбежно имеет свои особенности и, следовательно, предъявляет определенные требования к пользователям.Эти требования являются предложениями.Предложение сильное или слабое, и его сила повлияет на развитие бизнеса.Путь к используйте его; и хотя у Vue есть семейный пакет Bucket, вы можете использовать только его часть, вместо того, чтобы использовать его основную библиотеку, вы должны использовать его целиком.
Декларативный рендеринг
Vue.js предоставляет краткий синтаксис шаблона для декларативного рендеринга данных в DOM.
<div id="app">
{{ message }}
</div>
const vm = new Vue({
el: '#app',
data: {
message: 'hello vue'
}
})
-
el: точка монтирования элемента; вступает в силу, только когда new создает экземпляр; его можно использовать после монтирования экземпляраvm.$elдоступ -
data: объект данных экземпляра Vue, Vue будет рекурсивно преобразовывать свойство данных в геттер и сеттер, чтобы свойство данных могло реагировать на изменения данных; объект должен быть чистым объектом (содержащим 0 или более пар ключ-значение). ) Браузер Для объектов, созданных с помощью API, свойство прототипа будет игнорироваться.Вообще говоря, данные могут существовать только как данные, и не рекомендуется наблюдать за объектами с поведением в состоянии; -
{{}}: интерполяционное выражение; официальный сайт также известен какMustacheграмматика
Почему данные являются методом в компоненте
Когда компонент определен (не корневой компонент)dataДолжна быть объявлена как функция, возвращающая объект, поскольку компонент может использоваться для создания нескольких экземпляров, если данные все еще являются объектом, чтобы все экземпляры совместно использовали ссылку на один и тот же объект данных, каждый раз предоставляя функцию данных. экземпляр создан, мы можем вызвать функцию данных, которая возвращает совершенно новый объект данных с исходными данными
// 错误 示例
let options = {
data: {
uname: 'zs'
}
}
function Component(options) {
this.data = options.data
}
let user1 = new Component(options)
let user2 = new Component(options)
user1.data.uname = 'ls' // 修改 user1 触发了所有
console.log(user2.data.uname) // ls
// 正确示例
let options = {
data() {
return {
uname: 'zs'
}
}
}
function Component(options) {
this.data = options.data()
}
let user1 = new Component(options)
let user2 = new Component(options)
user1.data.uname = 'ls'
console.log(user2.data.uname) // zs
console.log(user1.data.uname) // ls
Поскольку компоненты можно многократно использовать повторно, если вы не используетеfunction returnДанные каждого компонента указывают на один и тот же адрес в памяти.Из-за особенностей сложных типов данных JavaScript изменяются одни данные и другие, но если вы используетеfunction returnПо сути, это эквивалентно объявлению новых переменных, которые не зависят друг от друга, и, естественно, в приведенном выше примере нет проблем; JavaScript присваиваетObjectКогда , это один и тот же адрес памяти, поэтому для независимости каждого компонента используется этот метод, но поскольку есть только один корневой компонент, нет загрязнения данных, поэтому он может быть объектом;
Использованная литература :
- https://segmentfault.com/a/1190000021680253
- https://axiu.me/coding/why-vue-component-data-must-be-function/
- https://blog.csdn.net/shaleilei/article/details/78084171
инструкция
v-cloak
Эту команду можно комбинировать с
CSSскрыть нескомпилированноеMustacheмаркировать, пока экземпляр не будет готов
Проблемное шоу:
/* css */
[v-cloak] { display: none; }
<div v-cloak>{{ root }}</div>
v-text
Обновите значение под узлом элемента; Примечание: все содержимое будет обновлено. Если вы хотите обновить локально, вы можете использовать
Mustacheграмматика
<div v-text="root"></div>
v-html
обновить элемент
innerHTMLПримечание: обычный HTML-контентИспользование HTML на веб-сайте очень опасно и может легко привести к XSS-инструментам. Не используйте его, когда пользователи отправляют контент.
<div v-html="html"></div>
new Vue({
el: '#app',
data: {
html: '<p>hello vue</p>'
}
})
v-pre
Исходный вывод не будет участвовать в компиляции, и будет отображаться то содержимое, которое будет отображаться.
<div v-pre>{{ will not compile }}</div>
v-once
определено
v-onceЭлемент или компонент инструкции (включая узлы-потомки в элементе или компоненте) могут быть отображены только один раз, первый рендеринг, даже если данные изменяются, он не будет повторно отображаться, как правило, используется для отображения статического содержимого;
<div v-once>{{ content }}</div>
const vm = new Vue({
el: '#app',
data: {
content: 'this is init data'
}
})
vm.content = 'update data'
v-showа такжеv-if
здесь
v-ifНе только эта одна инструкция, она содержитv-else-ifv-elseФункции почти одинаковые, вот единое объяснение
v-show: В соответствии с истинным или ложным значением выражения определить, скрыт ли элемент (переключить отображение элемента: блок/нет)
v-if: Условно отображать данные на основе значения выражения, при переключении элемент и его привязки/компоненты данных уничтожаются и создаются заново.
Разница :
<div v-if="isShow"> v-if </div>
<div v-show="isShow"> v-show </div>
Демонстрация кода решения филиала
<!-- 最终一会展示一个 p 标签中的内容 -->
<div>
<p v-if="score > 90">
<span>成绩优异 : {{ score }}</span>
</p>
<p v-else-if="score > 70">
<span>成绩及格 : {{ score }}</span>
</p>
<p v-else>
<span>不及格 : {{ score }}</span>
</p>
</div>
v-for
существует
v-forЗацикленный объект должен быть итерируемым объектом.iterable( Array | Number | Object | String ... )Синтаксис
alias in expressionгде in также можно заменить на ofВы можете добавлять значения индекса в массивы или объекты
<!-- 数组循环 -->
<div v-for="(item, index) in items">
{{ item.text }}
</div>
<!-- 对象循环 -->
<div v-for="(val, key, index) in object">
{{ val }} {{ key }} {{ index }}
</div>
Зачемv-forдолжен добавить уникальныйkey
Когда Vue обновляет список данных, отображаемых с помощью v-for, по умолчанию используется стратегия обновления на месте. Если порядок элементов данных изменен, Vue не будет перемещать DOM в соответствии с данными элементов данных, а будет обновлять каждый элемент на месте элементов, обеспечивающий их корректную отрисовку в каждой позиции индекса;
зачем добавлятьkey
- Чтобы дать Vue подсказку, чтобы он отслеживал идентичность каждого узла и, таким образом, повторно использовал и переупорядочивал существующие элементы, каждому элементу должен быть присвоен уникальный ключ.
- ключ в основном используется в алгоритме виртуального DOM Vue для идентификации виртуального DOM при сравнении старых и новых узлов, если он не используется
keyбудет использовать алгоритм, который сводит к минимуму динамические элементы и пытается изменить/повторно использовать элементы одного и того же типа на месте, насколько это возможно, и, если возможно,keyон будет основан наkeyизменения, чтобы изменить порядок элементов и удалитьkeyнесуществующий элемент
почему бы не использоватьindexДелатьkey
// 组件数据定义
const vm = new Vue({
el: '#app',
data: {
users: [
{ id: 1, uname: 'zs', age: 23 },
{ id: 2, uname: 'ls', age: 24 },
{ id: 3, uname: 'we', age: 25 },
{ id: 4, uname: 'mz', age: 26 },
]
}
})
indexПример ошибки
Дело в том, что то, что мы сказали выше, изменит порядок элементов на основе изменения ключа.Можно видеть, что если мы используем индекс в качестве массива ключей для переворачивания, порядок ключей не изменился, но входящее значение полностью изменилось.Данные, которые изначально были разными в то время, ошибочно считались одинаковыми, поэтому были вызваны следующие проблемы;
<!-- 具体语法稍后介绍; 意思为点击翻转数组 -->
<button @click="users.reverse()">年龄排序</button>
<ul>
<!-- 循环这个 users 生成一个数据列表 并且里面带有 多选框 以供我们测试 -->
<li v-for="(user, index) of users" :key="index">
<input type="checkbox" />
<span>{{ user.uname }}</span>
</li>
</ul>
Пример правильного уникального идентификатора
В это время ключ и данные связаны.Когда вы переворачиваете массив, привязка на самом деле является этой частью данных, а не индексом, поэтому вышеуказанные проблемы не возникнут.
<li v-for="(user, index) of users" :key="user.id">
......
</li>
использованная литература :
https://juejin.cn/post/6844904113587634184
v-bind
связывание свойств; может быть сокращено как
:
// 绑定 attrbute
<div v-bind:content="message"></div>
// 绑定 class
<div :class="{box: isBox}"></div>
<div :class="['box', 'box1']"></div>
<div :class="['box', {box1: isBox}]"></div>
// 绑定 style
<div :style="{fontSize: '20px', color: 'white'}"></div>
<div :style="[{fontSize: '20px'}, {color: 'white'}]"></div>
v-on
привязка события; сокращенно
@Слушайте события DOM и запускайте некоторый код js при срабатывании
<button v-on:click="count += 1"></button>
{{ count }}
может получить имя метода;
Примечание. Когда это просто имя метода, первым параметром по умолчанию является объект события e
Когда параметры должны быть переданы, то объект события необходимо передать вручную, последний и принудительно записать как
$event
<button @click="handle">点击1</button>
<button @click="handle1('content', $event)">点击2</button>
methods: {
handle(e) {
console.log(e.target)
},
handle1(ct, e) {
console.log(ct)
console.log(e.target)
}
}
модификатор события
-
.prevent: блокировать событие по умолчанию -
.stop: перестань булькать -
.self: только текущий элемент запускает событие -
.once: вызвать событие только один раз -
.native: прослушивание собственных событий корневого элемента компонента.
// 定义子组件
Vue.component('my-component', {
template: `
<button @mousedown="handle" :style="{color: 'white', lineHeight: '20px', backgroundColor: 'black'}">组件</button>
`,
methods: {
handle() {
console.log('///')
}
}
})
ДобавленnativeЭто эквивалентно обработке пользовательского компонента как html, и вы можете прослушивать собственное событие непосредственно на нем, в противном случае пользовательское событие привязано к пользовательскому компоненту, и вы не определяете это событие в пользовательском событии, поэтому не добавляйтеnativeне будет выполняться
// 父组件中引用
<my-component @click.native="handle('父组件')"></my-component>
использованная литература :
https://segmentfault.com/q/1010000011186651
-
.capture: при добавлении прослушивателей событий используйте режим захвата.
// 此时会优先捕获 box1
<div class="box" style="background: skyblue; width: 180px;" @click.capture="handle('box1')">
<div class="box1 box" style="background: slateblue; width: 140px;" @click="handle('box2')">
<div class="box2 box" style="background: red;" @click="handle('box3')"></div>
</div>
</div>
// 允许只有修饰符 prevent 阻止默认事件
<a href="http://www.baidu.com" @click.prevent >百度</a>
// 多个事件修饰符可以连用触发时机也是相同的
<a href="http://www.baidu.com" @click.prevent.stop="handle('a')">baidu</a>
ключевой модификатор
Разрешено в Vue как
v-onДобавить модификаторы клавиатуры при прослушивании событий клавиатуры<input v-on:keyup.enter="submit">Конечно, большинство псевдонимов клавиш предоставляютсяключевой код
также через глобальные
Vue.config.keyCodesПользовательские псевдонимы модификаторовVue.config.keyCodes.f1 = 112
v-model
Создайте двустороннюю привязку данных к элементу формы, которая автоматически выберет правильное значение для обновления элемента в зависимости от типа элемента управления.
// 文本
<input type="text" v-model="message">
<p>{{ message }}</p>
// 多行文本
<textarea cols="30" rows="10" v-model="message"></textarea>
<p>{{ message }}</p>
// 单选框
<input type="radio" value="男" v-model="sex">男
<input type="radio" value="女" v-model="sex">女
<p>{{ sex }}</p>
// 单个复选框
<input type="checkbox" v-model="checked">
<p>{{ checked }}</p>
// 多个复选框
<input type="checkbox" value="打篮球" v-model="hobby"/>打篮球
<input type="checkbox" value="打皮球" v-model="hobby"/>打皮球
<input type="checkbox" value="打气球" v-model="hobby"/>打气球
<input type="checkbox" value="打棒球" v-model="hobby"/>打棒球
<p>{{ hobby }}</p>
// 选择框 -> 单选
<select v-model="selected">
<option>javascript</option>
<option>html</option>
<option>css</option>
</select>
<p>{{ selected }}</p>
// 选择框 -> 多选
<select v-model="selectList" multiple>
<option>javascript</option>
<option>html</option>
<option>css</option>
</select>
<p>{{ selectList }}</p>
// 实例对象
new Vue({
el: '#app',
data: {
message: '', // 多行, 单行文本
sex: '', // 单选框
checked: false, // 复选框单个
hobby: [], // 复选框多个
selected: '', // 选择框 -> 单个
selectList: [] // 选择框 -> 多个
}
})
модификатор
-
.lazy: по умолчаниюv-modelСинхронизируйте содержимое поля ввода после срабатывания каждого события ввода, добавьтеlazyПосле модификатора он станет данными синхронизации после события изменения
<input v-model.lazy="message">
-
.number: преобразование значения, введенного пользователем, в числовой тип.
<input v-model.number="age">
-
.trim: Фильтровать левые и правые пробелы в поле ввода.
<input v-model.trim="message">
Vue.set
Если вы добавите новое свойство в экземпляр после создания экземпляра, это не вызовет обновление представления, как понять?
data() {
return {
info: {
uname: 'zs'
}
}
}
mounted() {
// 此时是不会生效的 , 如果再模块化的开发中还会报错
this.info.age = 23
}
Ограниченный ES5, Vue не может обнаружить добавление или удаление свойств объекта, потому что Vue преобразует свойства вgetter setterТаким образом, атрибут должен быть в объекте данных, чтобы Vue мог конвертировать, и только в объекте данных он реагирует.
mounted() {
// 正确写法
this.$set(this.info, 'age', 23)
}
Vue.set(): а такжеthis.$setРазницы нет никакой, говорится на глобальном и локальном официальном сайтеthis.$setдаVue.setпсевдоним
methods
методы будут смешаны с экземпляром Vue, и доступ к этим методам можно получить непосредственно через экземпляр vm или использовать в директивных выражениях в методе
thisАвтоматически связывать экземпляры VueПримечание: методы в методах не используют стрелочные функции, стрелочные функции в
thisКонтекст, указывающий на родительскую область, поэтомуthisне будет указывать на экземпляр Vue
new Vue({
methods: {
handle() {
console.log(this)
}
}
})
вычисляемое свойствоcomputed
Очень удобно писать выражения в шаблонах, но вы должны понимать, что первоначальное назначение выражений - вычисление, например обработка каких-то строк, форматов времени и т.д., если мы пишем методы!Каждый раз нам приходится вызывать, Это слишком много проблем, потому что Vue предоставляет вычисляемые свойства, вычисляемые
Видно, что каждый раз, когда мы вызываем этот параметр, это очень неудобно.
<input type="text" v-model.number="input1"/> +
<input type="text" v-model.number="input2"/> =
<span>{{ getSum() }}</span>
data() {
return {
sum: '',
input1: '',
input2: ''
}
},
methods: {
getSum() {
return this.sum = this.input1 + this.input2
}
}
Далее мы используем вычисляемое свойство для ее решения; видно, что мы убрали свойство суммы в данных и добавили функцию getSum в вычисляемом
<input type="text" v-model.number="input1"/> +
<input type="text" v-model.number="input2"/> =
<span>{{ getSum }}</span>
data() {
return {
input1: '',
input2: ''
}
},
computed: {
getSum() {
return this.input1 + this.input2
}
},
Так вот вопрос, почему функция определена, а выполняется как свойство? На самом деле это просто сокращение. Это синтаксический сахар. Каждое вычисляемое свойство содержит get и set. Когда есть только get, его можно сокращенно формат функции.
export default {
computed: {
getSum: {
get() {
// 获取数据
},
set(val) {
// val 是这个计算属性被修改之后的数据 设置数据
}
}
}
}
Пример: прочитав этот пример, вы поймете, почему оно называется вычисляемым свойством.
<input type="text" v-model.number="input1"/> +
<input type="text" v-model.number="input2"/> =
<span>{{ getSum }}</span>
<!-- set 函数可以接收这里传递过来的值 -->
<button @click="getSum = '未知数'">修改 getSum</button>
computed: {
getSum: {
get() {
return this.input1 + this.input2
},
// 接收 getSum 这个属性改变后的值
set(val) {
console.log(val)
this.input1 = 20
this.input2 = 30
}
}
},
слушать свойствоwatch
Хотя вычисляемые свойства подходят в большинстве случаев, иногда требуется собственный прослушиватель, и в этом случае требуется свойство прослушивателя.watch
Он все еще вычисляет сумму двух чисел, когда часы прослушивают срабатывание атрибута input1 input1, находят сумму, если вы внимательно посмотрите, возникла проблема, и когда вы измените input2, он больше не сработает;
Резюме: он прослушивает изменения в определенном атрибуте данных и не создает новые атрибуты.
<input type="text" v-model.number="input1"/> +
<input type="text" v-model.number="input2"/> =
<span>{{ getSum }}</span>
data() {
return {
input1: '',
input2: '',
getSum: ''
}
},
watch: {
// 这样写看着是一个函数, 和属性理解不一致, 当然还可以写成这样
input1(newVal, oldVal) {
console.log(newVal, oldVal)
this.getSum = this.input1 + this.input2
}
input2: {
// 回调函数监听 input2 的变化 函数名必须是 handler
handler(newVal, oldVal) {
console.log(newVal, oldVal)
this.getSum = this.input1 + this.input2
}
}
}
Если нам нужно прослушивать свойства объекта, мы можем использовать его в параметре optionsdeep: trueОбратите внимание, что вам не нужно делать это для отслеживания изменений данных.
watch: {
obj: {
handler() {
// ....
},
deep: true
}
}
Особенностью watch является то, что при первой привязке значения функция мониторинга не будет выполняться, только при изменении значения.Если нам нужно выполнить функцию, когда значение изначально привязано, нам нужно использовать прибытиеimmediate: true
watch: {
apiData: {
handler(newVal, oldVal) { },
deep: true,
immediate: true
}
}
методы вычисляют разницу в часах
-
watchОн просто отслеживает изменение определенных данных, поддерживает глубокий мониторинг, получает два параметра, одно последнее значение, одно старое значение до изменения, результат не будет кэшироваться, и часы могут обрабатывать асинхронные задачи. -
computedЭто вычисляемое свойство, в зависимости от одного или нескольких значений свойства вычисленный результат будет кэшироваться, и он изменится только при изменении зависимости данных, и будет создано новое свойство -
methodsЭто вызов функции, кэша нет, он в основном имеет дело с некоторой бизнес-логикой, а не с прослушиванием или вычислением некоторых свойств.
фильтрfilter
Может использоваться для некоторого общего форматирования текста, что позволяет применять его в двух местах.
{{}}v-bindсередина
{{ msg | formatMsg }}
<div v-bind:msg="msg | formatMsg"></div>
- Вы можете определить частные фильтры внутри компонента в параметрах компонента.
Vue.component('son-component', {
template: `
<div>{{ msg | formatMsg }}</div>
`,
data() {
return {
msg: 'this is message'
}
},
filters: {
formatMsg(msg) {
return msg.toString().toUpperCase()
}
}
})
- Глобальные фильтры могут быть определены до создания экземпляра Vue.
Vue.filter('formatMsg', function(msg) {
return msg.toString().toUpperCase()
})
- По умолчанию фильтр
|Предыдущее содержимое используется в качестве первого параметра фильтра, а также может быть повторно передано для передачи.
<div>{{ msg | formatMsg('lower') }}</div>
Vue.filter('formatMsg', function(msg, args) {
console.log(msg) // lower
if (args === 'lower') {
return msg.toString().toLowerCase()
}
})
пользовательская директиваdirective
В соответствии с инструкциями, упомянутыми выше, если эти инструкции не соответствуют требованиям использования, вы можете настроить их самостоятельно.
<input type="text" v-focus/>
// 全局指令 定义时不需要 v- 调用时要加上 v- 前缀
Vue.directive('focus', {
inserted(el) {
el.focus()
}
})
// 或者可以定义为局部
directives: {
'focus': {
inserted(el) {
el.focus()
}
}
}
bindinsertedupdatecomponentUpdatedunbind
el-
binding-
modifiersv-drag.limit name-
valuev-drag="true"
-
<div v-drag>
// 拖拽方块案例
Vue.directive('drag', {
// 初始化样式
bind(el) {
el.style.position = 'absolute'
el.style.top = 0
el.style.left = 0
el.style.width = '100px'
el.style.height = '100px'
el.style.background = 'skyblue'
el.style.cursor = 'pointer'
},
// 元素对象存在后, 开始写拖动逻辑
inserted(el, binding) {
let draging = false
let elLeft = 0
let elRight = 0
document.addEventListener('mousedown', function (e) {
draging = true
let move = el.getBoundingClientRect()
elLeft = e.clientX - move.left
elRight = e.clientY - move.top
})
document.addEventListener('mousemove', function (e) {
let moveX = e.clientX - elLeft
let moveY = e.clientY - elRight
if (draging) {
el.style.left = moveX + 'px'
el.style.top = moveY + 'px'
}
})
document.addEventListener('mouseup', function () {
draging = false
})
}
})
// 我们先传入修饰符 limit 为自己定义的修饰符
<div v-drag.limit>
// 既然不想让他拖拽出视口, 那么就应该在鼠标移动的时候加入一些逻辑
document.addEventListener('mousemove', function (e) {
let moveX = e.clientX - elLeft
let moveY = e.clientY - elRight
// 是否传入了修饰符 limit 为什么这样可以获取 下面就上截图
if (binding.modifiers.limit) {
moveX = moveX <= 0 ? moveX = 0 : moveX
moveY = moveY <= 0 ? moveY = 0 : moveY
}
if (draging) {
el.style.left = moveX + 'px'
el.style.top = moveY + 'px'
}
console.log(binding) // binding 对象
})
<div v-drag.limit="{isDrag: false}">
document.addEventListener('mousemove', function (e) {
let moveX = e.clientX - elLeft
let moveY = e.clientY - elRight
// 是否传入了修饰符 limit
if (binding.modifiers.limit) {
moveX = moveX <= 0 ? moveX = 0 : moveX
moveY = moveY <= 0 ? moveY = 0 : moveY
}
// 是否传入 isDrag 判断是否可滑动
if (!binding.value.isDrag) return
if (draging) {
el.style.left = moveX + 'px'
el.style.top = moveY + 'px'
}
})
Vue.component('GlobalComponent', {
template: `<div> hello component </div>`
})
// 命名时推荐驼峰 , 调用时推荐 - 链接, html 不识别大小写
<global-component></global-component>
new Vue({
el: '#app',
components: {
SonComponent: {
template: `<div>hello private component</div>`
}
}
})
// 组件可以被复用多次
<private-component></private-component>
<private-component></private-component>
<private-component></private-component>
import SonComponent from '@/components/SonComponent.vue'
export default {
components: {
SonComponent
}
}
<son-component></son-component>
props
// 父组件
<div>
<son-component content="传递给子组件的数据, 如果动态传值可以加 v-bind"></son-component>
</div>
// 子组件
Vue.component('SonComponent', {
// 多个单词可以是驼峰式, 但是父组件传递时多个单词必须是 - 连接
// props 中的值, 可以像 data 中的数据一样访问 this.content / {{ content }}
// props 是只读的 切记不要修改 会报错
props: ['content'],
template: `<div> {{ content }} </div>`
})
-
typeNumberStringBooleanArrayObjectDateFunction defaultrequiredvalidator
props: {
content: {
type: String,
// default: 0, 普通值可直接默认返还
default: () => [1, 2, 3],
required: true,
// 如果传进来的 content 长度大于 20 就会报错
validator: (value) => value.length >= 20
}
}
$emit
$emit
// 子组件
<template>
<div class="son">
// $emit 第一个参数自定义事件, 第二个及以后是传递的数据
<button @click="$emit(son-com, [1, 2, 3])"></button>
</div>
</template>
// 父组件
// 监听子组件定义的自定义事件 , 通过 $event 访问第一个传递的参数
<son-component @son-com="msg = $event"></son-component>
// 子组件
<template>
<div class="son">
<button @click="sonHandle"></button>
</div>
</template>
<script>
export default {
methods: {
sonHandle() {
this.$emit('son-com', '需要传递的值')
}
}
}
</script>
// 父组件
<template>
<div class="parent">
<son-component @son-com="parentHandle"></son-component>
// 显示传入其他参数的话 必须使用 $event 接收子组件传递过来的值
<son-component @son-com="parent('显示传入参数', $event)"></son-component>
</div>
</template>
<script>
export default {
methods: {
// 默认第一个值就是传递过来的参数
parentHandle(arg) {
console.log(arg) // 需要传递的值
},
// 对应传入参数的位置
parent(params, arg) {
console.log(params) // 显示传入参数
console.log(arg) // 需要传递的值
}
}
}
</script>
// 子组件
<template>
<div class="son">
<button @click="sonHandle"></button>
</div>
</template>
<script>
export default {
methods: {
sonHandle(event) {
// 事件对象可以在任意位置 , 放到前面相对比较好接收
this.$emit('son-com', event, '需要传递的值', '需要传递的第二个值')
}
}
}
</script>
// 父组件
<template>
<div class="son">
<button @son-com="parent"></button>
</div>
</template>
<script>
export default {
methods: {
parent(event, ...args) {
console.log(event)
// 如果不想使用剩余参数, 也可以多传递参数逐个使用
console.log(args)
}
}
}
</script>
v-model
v-model
<input type="text" v-model="msg"/>
<input :value="msg" @input="msg = $event.target.value"/>
// 父组件
<model-input
:test-value="searchText"
@test-input="searchText = $event"
>
</model-input>
$emit
// 子组件
<input
type="text"
v-bind:value="testValue"
@input="$emit('test-input', $event.target.value)"
>
// script
props: ['testValue'] // 自定义属性传递过来的值
v-model
// 父组件
<model-input v-model="searchText"></model-input>
// 子组件
<input
type="text"
v-bind:value="value"
@input="$emit('input', $event.target.value)"
>
// script
props: ['value']
model
// 父组件
<model-input v-model="isChecked"></model-input>
// script
data() {
return {
isChecked: false
}
},
// 子组件
<input
type="checkbox"
v-bind:checked="checked"
@change="$emit('change', $event.target.checked)"
>
// script
export default {
name: 'ModelInput',
// v-model 拆分
model: {
prop: 'checked', // 将传进来的 isChecked 变成 checked 供后面的 props 使用
event: 'change' // 定义 emit 自定义的事件名字
},
props: {
checked: {
type: Boolean
}
}
}
v-slotslotslot-scope
slot
// 子组件
<template>
<div>
<p>这是组件的头部</p>
<slot></slot>
<p>这是组件的尾部</p>
</div>
</template>
// 父组件
<<template>
<div>
<!-- 插槽内可以是任何内容 组件,文本,标签-->
<slot-test>
<p>这是插槽的内容</p>
</slot-test>
</div>
</template>
<slot>
// 子组件
<template>
<div>
<p>这是组件的头部</p>
<slot>我是默认内容</slot>
<p>这是组件的尾部</p>
</div>
</template>
<slot>name
// 子组件
<template>
<div>
<header>
<slot name="header"></slot>
</header>
<main>
<!-- 如果没有指定 name 默认的 name 为default -->
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
templatev-slot
// 父组件
<template>
<div>
<slot-test>
<template v-slot:header> 我是 header 内容 </template>
我是 没有指定 name 的内容 <!-- 或者也可以写成下面的内容 -->
<template v-slot:default> 没有指定 name 的内容 </template>
<template v-slot:footer> 我是 footer 内容 </template>
</slot-test>
</div>
</template>
<template>v-slot<template>name<slot>
v-slot<template>
v-slot:#
// 子组件
<div>
<slot></slot>
</div>
/* 父组件 */
// 错误示例
<slot-test>
<template #>
<!-- 内容。。。。-->
</template>
</slot-test>
// 正确示例
<slot-test>
<template #default>
<!-- 内容。。。。-->
</template>
</slot-test>
v-bind<slot>v-slot
// 子组件
<template>
<div>
<slot name="userInfo" :user="userInfo"></slot>
</div>
</template>
<script>
export default {
data() {
return {
userInfo: {
firstName: 'firstName',
lastName: 'lastName'
}
}
}
}
</script>
// 父组件
<template>
<div>
<slot-test>
<!-- 如果只有一个插槽可以吧 v-slot 写到 组件上面 具体看下面-->
<template v-slot:userInfo="slotProps">
{{ slotProps.user.firstName }}
</template>
</slot-test>
</div>
</template>
v-slot
// 子组件
<div>
<slot :user="userInfo"></slot>
</div>
// 组件数据
data(){
return {
userInfo: {
firstName: 'firstName',
lastName: 'lastName'
}
}
}
// 父组件
<div>
<slot-test v-slot="slotProps">
{{ slotProps.user.firstName }}
</slot-test>
</div>
Prop
<div>
<slot-test v-slot="{ user }">
{{ user.firstName }}
</slot-test>
</div>
<div>
<slot-test v-slot="{ user: preson }">
{{ preson.firstName }}
</slot-test>
</div>
<todo-list>
// 子组件
<template>
<ul>
<li v-for="item in list" :key="item.id">
<!-- 这里把控制逻辑交出去,由父组件去控制一定的逻辑 -->
<slot name="todo" :item="item">
{{ item.uname }}
</slot>
</li>
</ul>
</template>
// 数据
[
{id: 1, uname: 'zs'},
{id: 2, uname: 'ls'},
{id: 3, uname: 'we'},
{id: 4, uname: 'mz'},
]
// 父组件
<test v-slot:todo="slotProps">
<!-- 本来是显示名字的改成了显示id -->
{{ slotProps.item.id }}
</test>
component
// 模板
<div>
<button @click="handle('post')" :style="{background: !isShow ? 'red' : ''}">post</button>
<button @click="handle('list')" :style="{background: isShow ? 'red' : ''}">list</button>
<item-post v-show="!isShow"></item-post>
<item-list v-show="isShow"></item-list>
</div>
// script
import ItemPost from '@/components/ItemPost.vue'
import ItemList from '@/components/ItemList.vue'
export default {
name: 'Home',
components: {
ItemPost,
ItemList
},
data() {
return {
isShow: true
}
},
methods: {
handle(title) {
title === 'list' ? this.isShow = true : this.isShow = false
}
}
}
<!-- 每次点击 button 的时候触发 handle事件函数时 is绑定的值会重新渲染组件 -->
<component :is="showWhat"></component>
data() {
return {
showWhat: 'ItemPost',
isShow: true
}
},
methods: {
handle(title) {
// 这里同时控制了切换之后 active 的样式,所以就不删了
title === 'list' ? this.isShow = true : this.isShow = false
// 加一层判断切换逻辑
title === 'list' ? this.showWhat = 'ItemList' : this.showWhat = 'ItemPost'
}
}
showWhat<keep-alive>
<!-- 失活的 tab 将会被缓存 -->
<keep-alive>
<component :is="showWhat"></component>
</keep-alive>
<template>
<div>这是一个简单的组件</div>
</template>
<template>
<div>
<dynamic></dynamic>
</div>
</template>
<script>
import Dynamic from '@/component/Dynamic.vue'
export default {
name: 'Home',
components: {
Dynamic
}
}
</script>
export default {
components: {
// script 头部的导入, 直接在组件内导入
Dynamic: () => import Dynamic from '@/component/Dynamic.vue'
}
}
0.js
<template>
<div>
// 就是增加一个按钮,点击控制,这里就给大家简化了
<dynamic v-if="isShow"></dynamic>
</div>
</template>
ref
ref
// 模板
<template>
<div>
<item-list ref="itemRef"></item-list>
<input type="text" ref="inputRef"/>
</div>
</template>
// script
export default {
mounted() {
// 子组件的实例对象
console.log(this.$refs.itemRef)
// 元素的实例对象, 可以操作 dom
console.log(this.$refs.inputRef)
}
}
this.refs
<ul>
<li v-for="user of userList" :key="user.id" :style="{listStyle: 'none'}" ref="forRef">
<input type="checkbox" />
{{ user.id }} --- {{ user.uname }} --- {{ user.age }}
</li>
</ul>
mounted() {
console.log(this.$refs.forRef)
}
$refs$refs
-
beforeCreate:datacomputedwatchmethods -
created:datacomputedwatchmethodsbeforeRouterEnter -
beforeMount:beforeMount -
mounted:$ref -
beforeUpdate: -
updated: -
activated: -
deacticated:
// 子组件
// 要在子组件的声命周期内 , 才会触发这两个钩子函数
activated() {
console.log('itemList 被激活')
},
deactivated() {
console.log('itemList 被停用 / 失活')
},
// 父组件
// toggle 切换时触发子组件中的这两个钩子函数
<button @click="com = 'ItemPost'">post</button>
<button @click="com = 'ItemList'">list</button>
<keep-alive>
<component :is="com"></component>
</keep-alive>
-
beforeDestroy: -
destroyed:
<template>
<div>
<p>this is $el</p>
<button @click="info = '修改后的值'">{{ info }}</button>
<button @click="handle">卸载</button>
</div>
</template>
<script>
export default {
name: 'HomePage',
data() {
return {
info: 'data options',
flag: true
}
},
methods: {
handle() {
this.$destroy()
}
},
beforeCreate() {
console.group('##### 组件创建前 beforeCreate #####')
console.log('Vue', this)
console.log(this.info)
console.log(this.$el)
},
created() {
console.group('##### 组件创建后 created #####')
console.log(this.info)
console.log(this.$el)
},
beforeMount() {
console.group('##### 组件挂载前 beforeMount #####')
console.log(this.info)
console.log(this.$el)
},
mounted() {
console.group('##### 组件挂载后 mounted #####')
console.log(this.$el)
},
beforeUpdate() {
console.group('##### 组件更新前 beforeUpdate #####')
console.log(`这里的数据已经修改了只是没有渲染 ----- `+ this.info)
this.info = '又修改了一次'
},
updated() {
console.group('##### 组件更新后 updated #####')
console.log('更新后的新值: ', this.info)
},
beforeDestroy() {
console.group('##### 组件卸载前 updated #####')
console.log(this.info)
console.log(this.$el)
},
destroyed() {
console.group('##### 组件卸载后 updated #####')
console.log(this.info)
console.log(this.$el)
}
}
</script>
-
beforeMountMounted
v-if v-showcomponent)
v-enterv-enter-activev-enter-tov-leavev-leave-activev-leave-to
<transition>
<dynamic v-if="isShow"></dynamic>
</transition>
<transition>v-
<transition name="my-trans"> my-trans-enter
<style lang="css">
.v-enter, .v-leave-to{
opacity: 0;
transition: all .5s ;
}
.v-enter-to, .v-leave{
opacity: 1;
transition: all .5s ;
}
</style>
<transition>
<keep-alive>
<component :is="showWhat"></component>
</keep-alive>
</transition>
<style lang="css">
.v-enter, .v-leave-to{
opacity: 0;
}
.v-enter-active, .v-leave-active{
transition: opacity .3s ease;
}
</style>
<transition>
in-outout-in
out-in
<transition mode="out-in">
<keep-alive>
<component :is="showWhat"></component>
</keep-alive>
</transition>
<transition appear>
<div v-if="toggle">post</div>
<div v-else>list</div>
</transition>
<transition-group>
<transition-group tag="ul" appear>
<li v-for="user of users" :key="user.id">
<p>{{ user.uname }}</p>
</li>
</transition-group>
nextTick
nextTick()
nextTick
created() {
// created 钩子中可以操作 DOM 元素
this.$nextTick(() => {
this.$refs.divRef.innerHTML = 'hello vue'
})
}
<!-- path: Mixin/MyButton/MyButton.vue -->
<template>
<button :class="['my-btn', type]">
<!-- 我们希望用户输入按钮的名字所以使用插槽 -->
<slot></slot>
</button>
</template>
<script>
// 我们希望用户传递进来一个 type 来定制 btn 样式
export default {
props: {
type: {
type: String,
default: 'my-primay'
}
}
}
</script>
<style scoped>
/* 基类样式 */
.my-btn {
border: none;
outline: none;
line-height: 30px;
width: 50px;
}
/* 用户可拓展样式 */
.btn-primary {
background: skyblue;
}
.btn-danger {
background: orange;
}
.btn-success {
background: palegreen;
}
</style>
// path: Mixin/MyButton/index.js
import MyButton from './MyButton.vue'
export default {
// 这里我们使用了 组件中的 components 对象
components: {
MyButton
}
}
<!-- views/page.vue -->
<template>
<!-- 此时我们只需要传入指定不同的类名即可变换 button 的样式 -->
<my-button type="btn-danger">按钮</my-button>
</template>
<script>
import MyButton from './mixin/MyButton'
export default {
// 组件内使用 mixins 将这个对象混入,
mixins: [MyButton]
}
</script>
// mixin/index.js
export default {
data() {
return {
m_name: 'lisi',
m_list: [1, 2, 3]
}
},
created() {
// 混入之后会被调用 同时我们也可以在混入之前调用组件内的数据
console.log(this.m_name, this.m_list, 'mixin')
console.log(this.c_name, this.c_list, 'component')
// 执行 handle
this.handle() // 这个handle 实际就是调用了 组件中的handle 而不是 mixin 中的handle
this.handle1()
},
methods: {
// 由于此处的 handle 与 组件内存在同名 按照上面说明, 这个handle被覆盖以下面组件中为主
handle() {
console.log('mixin handle')
},
handle1() {
console.log('mixin handle1')
}
}
}
<template>
<div></div>
</template>
<script>
import mixin from '@/mixin'
export default {
mixins: [mixin],
data() {
return {
c_name: 'zhangsan',
c_list: [1, 2, 3]
}
},
created() {
// 同理这里也可以直接访问 mixin 中的数据,这里就不演示了
console.log('this is component')
// 调用handle
this.handle()
},
methods: {
handle() {
console.log('component handle')
}
}
}
</script>
// main.js
Vue.mixin({
data() {
return {}
},
created() {},
// ......
})
provideinject
// App.vue
<template>
<div>
<router-view></router-view>
</div>
</template>
<script>
export default {
data() {
return {
info: { name: 'zs', age: 23 }
}
},
// 使用 provide 把值传递出去
// 这里碰到一点小问题,官网说可以是 Objct | function 返回一个对象,这里试了 Object 就是不能成功不知道为啥😭
provide() {
return {
info: this.info,
reload: this.reload
}
},
methods: {
reload() {
console.log('reload')
}
}
}
</script>
// Home.vue
<template>
<div>
Home
<provide-test></provide-test>
</div>
</template>
<script>
// 这里我们只是把需要用到 provide 数据的组件引入,可以看出我们并没有使用
import ProvideTest from '@/components/ProvideTest.vue'
export default {
components: {
ProvideTest
}
}
</script>
// components/ProvideTest.vue
<template>
<div></div>
</template>
<script>
export default {
// 这里我们使用 indect 来接收 父组件传递过来的数据,可以看出这种方式类似于 props 接收
inject: ['info', 'reload'],
mounted() {
// 然后就可以通过实例访问这些数据了
console.log(this.info)
this.reload()
}
}
</script>
provideinjectinject
emit
$on
$on$emit
// About.vue
<template>
<div>
<button @click="handle">点击传递</button>
</div>
</template>
<script>
export default {
methods: {
handle() {
// 这里使用 emit 触发一个自定义事件 如果是监听原生事件 同样可以传递 event
this.$emit('on-click', '单文件内被监听了')
}
},
mounted() {
// 在 mounted 中 用 on 去监听触发的事件, 并且接收传递过来的参数
this.$on('on-click', msg => {
console.log(msg)
})
}
}
</script>
// Bus/index.js
import Vue from 'vue'
// 创建一个空的 Vue 实例 用来做 桥梁
export const Bus = new Vue()
// main.js
import { Bus } from './Bus'
// 将这个空的实例绑定到 vue 的原型中
Vue.prototype.$bus = Bus
// About.vue
<template>
<div>
<button @click="handle">点击传递</button>
</div>
</template>
<script>
export default {
data() {
return {
message: ''
}
},
methods: {
handle() {
// 通过 $bus.$emit 触发事件 可以是自定义事件也可以是原生事件
this.$bus.$emit('click', '其他文件内被监听了', event)
}
}
}
</script>
// Home.vue
<template>
<div></div>
</template>
<script>
export default {
mounted() {
// 兄弟组件中可以通过 $bus.$on 监听触发的事件, 并且接收一个回调处理参数
this.$bus.$on('click', (msg, e) => {
console.log(msg)
console.log(e)
})
}
}
</script>
mountedcreatedmounted