props
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>props</title>
<script src="../../vue.js"></script>
</head>
<body>
<div id="root">
<child
:title-content="title"
url="http://www.baidu.com"
class="abc"
></child>
<!-- <child></child> -->
<!-- <div title-abc="msg"></div> -->
</div>
<script type="module">
Vue.config.productionTip = false
import Child from './Child.js'
var vm = new Vue({
el: '#root',
data: {
title: 'hello',
},
components: {
child: Child
},
mounted() {
setTimeout(() => {
this.title = 'world'
}, 1000)
},
})
</script>
</body>
</html>
Child.js文件
const Child = {
// props: ['titleContent'],
props: {
titleContent: {
// type: Number
// type: String
// type: Boolean
// type: Array,
// type: Function,
// type: Symbol,
// type: [Number, String]
type: String,
// required: true
// default: '标题'
// default() {
// // 10000行的复杂逻辑
// return '标题一'
// }
validator(value) {
// 返回值一定是个boolean
return value.length >= 5
}
},
// url: {
// type: String
// }
},
inheritAttrs: false,
template: `
<div class="def">
<h1>{{newTitle}}</h1>
<div>{{title}}</div>
</div>
`,
data() {
return {
// title: this.titleContent
title2: ''
}
},
beforeCreate() {
// this.title = this.titleContent
},
computed: {
newTitle() {
return this.titleContent + 1
},
// title() {
// return this.titleContent + '!!!'
// }
title: {
get() {
return this.titleContent + '!!!'
},
set(value) {
this.title2 = value
}
}
},
mounted() {
this.title = 'world'
},
}
export default Child
custom-event
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>custom events</title>
<script src="../../vue.js"></script>
</head>
<body>
<div id="root">
<child
@click.native="handleEvent"
></child>
<!-- sync修饰符:相当于父组件授权给子组件,去修改父组件的状态 -->
<child2
:custom-event.sync="bar"
></child2>
{{bar}}
</div>
<script>
Vue.config.productionTip = false
const Child = {
template: `
<div>
<div>child</div>
<button @click="handleClick">click</button>
</div>
`,
methods: {
handleClick() {
// this.$emit('custom-event', 'hello')
}
},
mounted() {
// this.$emit('custom-event', 'hello')
},
}
const Child2 = {
template: `
<div>
<h1>header</h1>
<button @click="handleClick">click</button>
</div>
`,
methods: {
handleClick() {
// this.$emit('custom-event', { bar: 'hello' })
this.$emit('update:custom-event', 'hello')
}
},
}
var vm = new Vue({
el: '#root',
data: {
bar: 'aaa'
},
components: {
child: Child,
child2: Child2
},
methods: {
handleEvent(msg) {
console.log(msg)
},
// handleChild2Event(msg) {
// this.bar = msg.bar
// }
},
})
</script>
</body>
</html>
自定义组件
自定义组件只能用kebab-case的命名方法,大驼峰和小驼峰均不行
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>component advanced</title>
<script src="../vue.js"></script>
</head>
<body>
<div id="root">
<my-component></my-component>
<your-component></your-component>
</div>
<script type="module">
import YourComponent from './YourComponent.js'
Vue.config.productionTip = false
// camelCase 小驼峰
// ParscalCase 大驼峰
// kebab-case 肉串
Vue.component('my-component', {
template: `
<div>product</div>
`
})
// 局部定义组件
// const YourComponent = {
// template: `
// <div>cart</div>
// `
// }
var vm = new Vue({
el: '#root',
// template: `
// <my-component></my-component>
// `,
// title: 'hello',
// handleClick() {
// console.log(100)
// console.log(this)
// },
mounted() {
// this.$options.handleClick.call(this)
// console.log(this.$options.title)
},
// 在这个组件上挂载其他的组件
components: {
'your-component': YourComponent
}
})
</script>
</body>
</html>
YouComponent.js文件
// 局部定义组件
const YourComponent = {
template: `
<div>cart</div>
`
}
export default YourComponent
动态组件
主要是keep-alive
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title></title>
<script src="../../../vue.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
#root {
height: 100%;
}
html,body {
height: 100%;
overflow: hidden;
}
html {
font-size: 100px;
}
body {
font-size: 16px;
}
ul, li {
list-style: none;
}
.container {
height: 100%;
display: flex;
flex-direction: column;
}
main {
flex: 1;
overflow: hidden;
}
nav {
height: .44rem;
border-top: #eee solid 1px;
}
nav ul {
height: 100%;
display: flex;
}
nav ul li {
flex: 1;
text-align: center;
line-height: .44rem;
}
li.active {
background-color: #eee;
}
.home-tab {
height: .44rem;
display: flex;
border-bottom: solid 1px #ccc;
}
.home-tab li {
flex: 1;
line-height: .44rem;
text-align: center;
}
.list {
height: 100%;
}
.main-box {
height: 100%;
display: flex;
flex-direction: column;
}
.tab-box {
overflow-y: scroll;
flex: 1;
}
</style>
</head>
<body>
<div id="root">
<div class="container">
<main>
<keep-alive
include="abc"
>
<component :is="currentComp"></component>
</keep-alive>
</main>
<nav>
<ul>
<li
v-for="tab in tabs"
@click="handleClick(tab.component)"
:class="{active: currentComp === tab.component}"
>
{{tab.title}}
</li>
</ul>
</nav>
</div>
</div>
<script type="module">
Vue.config.productionTip = false
const tab1 = {
template: `
<div class="list">
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表<br />
童装列表2<br />
</div>
`
}
const tab2 = {
template: `
<div>女装列表</div>
`
}
Vue.component('m-home', {
data() {
return {
tabs: [
{
id: '001',
title: '童装',
component: 'tab1'
},
{
id: '002',
title: '女装',
component: 'tab2'
}
],
currentComp: 'tab1'
}
},
components: {
tab1,
tab2
},
template: `
<div class="main-box">
<ul class="home-tab">
<li
v-for="tab in tabs"
@click="handleClick(tab.component)"
:class="{active: tab.component === currentComp}"
>
{{tab.title}}
</li>
</ul>
<div class="tab-box">
<component :is="currentComp"></component>
</div>
</div>
`,
destroyed() {
console.log('home')
},
methods: {
handleClick(comp) {
this.currentComp = comp
}
},
})
Vue.component('m-category', {
name: 'abc',
template: `
<div class="main-box">category</div>
`,
destroyed() {
console.log('m-category')
},
// mounted() {
// console.log(100)
// },
activated() {
console.log(200)
},
deactivated() {
console.log(300)
},
})
Vue.component('m-profile', {
template: `
<div class="main-box">profile</div>
`,
destroyed() {
console.log('m-profile')
},
mounted() {
console.log(100)
},
})
var vm = new Vue({
el: '#root',
data: {
currentComp: 'm-home',
tabs: [
{
id: '001',
title: '首页',
component: 'm-home'
},
{
id: '002',
title: '分类',
component: 'm-category'
},
{
id: '003',
title: '我的',
component: 'm-profile'
}
]
},
computed: {
},
methods: {
handleClick(comp) {
this.currentComp = comp
}
},
})
</script>
</body>
</html>
vue2的一些边缘问题
和 r o o t 类 似 , root 类似, root类似,parent property 可以用来从一个子组件访问父组件的实例。它提供了一种机会,可以在后期随时触达父级组件,以替代将数据以 prop 的方式传入子组件的方式
尽管存在 prop 和事件,有的时候你仍可能需要在 JavaScript 里直接访问一个子组件。为了达到这个目的,你可以通过 ref 这个 attribute 为子组件赋予一个 ID 引用
bus总线
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title></title>
<script src="../../vue.js"></script>
</head>
<body>
<script type="text/x-template" id="hello-world-template">
<p>Hello hello hello {{title}}</p>
</script>
<div id="root">
<child ref="child"></child>
<test inline-template>
<div>
{{title}}
</div>
</test>
<test2></test2>
{{xx}}
</div>
<script type="module">
Vue.config.productionTip = false
import bus from './bus.js'
const grandson = {
inject: ['x', 'setX'],
template: `
<div>
<h1>grandson {{x}}</h1>
<h3>{{message}}</h3>
</div>
`,
components: {
},
data() {
return {
bus,
message: 100
}
},
mounted() {
// this.$root.x = 200
// console.log(this.$parent.y)
// this.x = 5000
// this.setX(5000)
// console.log(bus.x)
// bus.$emit('setx', 'world')
// this.$forceUpdate()
bus.$on('changeMessage', (msg) => {
this.message = msg
})
},
}
const child = {
inject: ['x'],
template: `
<div>
<h1>child</h1>
<grandson></grandson>
{{bus.x}}
{{x}}
</div>
`,
components: {
grandson
},
data() {
return {
y: 1000,
bus
}
},
mounted() {
bus.$emit('changeMessage', 999)
},
}
const test = {
data() {
return {
title: 'line'
}
}
}
const test2 = {
template: '#hello-world-template',
data() {
return {
title: 'line 2'
}
}
}
var vm = new Vue({
el: '#root',
components: {
child,
test,
test2
},
data: {
xx: 100
},
mounted() {
console.log(this.$refs['child'].y)
},
provide: {
x: 3000,
setX(x) {
// console.log(this)
// this.x = x
}
}
})
</script>
</body>
</html>
slot
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>slots</title>
<script src="../../vue.js"></script>
</head>
<body>
<div id="root">
<child>
<template
#default="{string, url}"
>
<div slot="div1">{{url}}</div>
</template>
<template
#div2="{url}"
>
<div slot="div2">{{url}}</div>
</template>
<!-- <div slot="div2">hello slot</div>
<div>{{string}}</div>
<div>{{string}}</div>
<div>{{string}}</div> -->
</child>
</div>
<script type="module">
Vue.config.productionTip = false
const Child = {
template: `
<div>
<h1>child slot</h1>
<h2>
<slot name="div1" :string="string"></slot>
</h2>
<h3>
<slot name="div2" url="abc.com"></slot>
</h3>
<h4>
<slot :string="string" url="http://www.baidu.com">
hello vue
</slot>
</h4>
</div>
`,
data() {
return {
string: 'hello child div'
}
}
}
var vm = new Vue({
el: '#root',
components: {
child: Child
},
data: {
string: 'hello div~'
}
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title></title>
<script src="../../vue.js"></script>
</head>
<body>
<div id="root">
<my-header
:msg="msg"
>
<template #default="{title}">
<h1>{{title}}</h1>
</template>
</my-header>
</div>
<script type="module">
Vue.config.productionTip = false
const Header = {
props: {
msg: {
type: Object
}
},
template: `
<div>
<slot :title="msg.title"></slot>
</div>
`
}
var vm = new Vue({
el: '#root',
components: {
'my-header': Header
},
data: {
msg: {
title: 'abc',
content: 'aaabbbcc'
}
}
})
</script>
</body>
</html>
组件递归
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title></title>
<script src="../../vue.js"></script>
</head>
<body>
<div id="root">
<tree-folder :folder="folder"></tree-folder>
</div>
<script type="module">
Vue.config.productionTip = false
Vue.component('tree-folder', {
props: ['folder'],
template: `
<p>
<span>{{ folder.name }}</span>
<tree-folder-contents :children="folder.children"/>
</p>
`
})
Vue.component('tree-folder-contents', {
props: ['children'],
template: `
<ul>
<li v-for="child in children">
<tree-folder v-if="child.children" :folder="child"/>
<span v-else>{{ child.name }}</span>
</li>
</ul>
`
})
var vm = new Vue({
el: '#root',
data: {
folder: {
name: 'folder1',
children: {
folder: {
name: 'folder1-1',
children: {
folder: {
name: 'folder1-1-1'
},
folder2: {
name: 'folder1-1-2'
}
}
},
folder2: {
name: 'folder2-1',
children: {
folder: {
name: 'folder2-1-1'
},
folder2: {
name: 'folder2-1-2'
}
}
}
}
}
}
})
</script>
</body>
</html>
混入(minxin)vue3已经去除
内部的data定义的数据优先级高于minxin的优先级
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>mixin</title>
<script src="../vue.js"></script>
</head>
<body>
<div id="root">
<child></child>
<h2>{{title}}</h2>
<button @click="handleClick('haha')">click</button>
</div>
<script type="module">
Vue.config.productionTip = false
// Vue.mixin({
// data() {
// return {
// title: 'BALABALA.....'
// }
// },
// methods: {
// handleClick(title) {
// this.title = title
// }
// },
// mounted() {
// console.log('100')
// },
// })
// 局部混入
const mixins = {
data() {
return {
title: 'BALABALA.....'
}
},
methods: {
handleClick(title) {
this.title = title
}
},
mounted() {
console.log('100')
},
}
const child = {
mixins: [mixins],
data() {
return {
// title: 'hello'
}
},
template: `
<div>
<h1>{{title}}</h1>
<button @click="handleClick('world')">click</button>
<button @click="handleSubmit">submit</button>
</div>
`,
methods: {
handleSubmit() {
console.log(100)
}
},
mounted() {
console.log('200')
},
}
var vm = new Vue({
mixins: [mixins],
el: '#root',
components: {
child
},
data: {
// title: 'hi'
}
})
</script>
</body>
</html>