vue官网https://cn.vuejs.org/v2/guide/installation.html
vue分生产环境和开发环境,当我们开发的时候使用开发环境的版本,便于我们查阅源代码(有注释),
上线时候使用生产环境。
对于制作原型或学习,你可以这样使用最新版本:
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
对于生产环境,我们推荐链接到一个明确的版本号和构建文件,以避免新版本造成的不可预期的破坏:
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
如果你使用原生 ES Modules,这里也有一个兼容 ES Module 的构建文件:
<script type="module">
import Vue from 'https://cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.esm.browser.js'
</script>
import Vue from 'https://cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.esm.browser.js'
</script></script>
基本骨架
<div id="app">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
}
})
</script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<!-- <script src="https://cdn.jsdelivr.net/npm/vue@2.6.0"></script> -->
<style>
[v-cloak]{
display: none;
}
</style>
</head>
<body>
<!-- 将来new的vue实例, 会控制这个元素中的所有内容 -->
<div id="app">
<!-- 使用v-cloak能够解决插值表达式闪烁的问题 -->
<p v-cloak>---{{ msg }}+++</p>
<h4 v-text="msg">---+++</h4>
<!-- 默认 v-text是没有闪烁问题的 -->
<!-- v-text会覆盖元素中原本的内容, 但是插值表达式只会替换自己的
占位符, 不会把整个内容清空-->
<div>{{ msg2 }}</div>
<div v-text="msg2"></div>
<div v-html="msg2"></div>
<input type="button" value="按钮" v-bind:title="mytitle + '新增加的字符串'" @mouseover="mouse">
<!-- v-bind: 是vue中, 提供的用于绑定属性的指令 -->
<input type="button" value="按钮2" v-bind:title="'v-bind:可以简写成:' + mytitle">
<!-- v-bind中, 可以写合法的js表达式 -->
<!-- vue中提供了v-on: 事件绑定机制 -->
<br><br>
<!-- 浏览器常用的事件都可以绑定 mouseover, mouseout, blur-->
<input type="button" value="点击事件弹窗" v-on:click="show">
</div>
<script src="lib/vue.js"></script>
<script>
// 创建一个vue实例
// 当我们导入包之后 在浏览器的内存中, 就多了一个vue构造函数
var vm = new Vue({
el: '#app', // 表示 当前我们new的这个vue实例, 要控制页面上的哪个区域
data: {
msg: '欢迎学习vue', // 通过vue提供的命令. 很方便的就能把数据渲染到页面上
// 前端的vue之类的框架, 不提倡我们去手动操作dom元素
msg2: "<h1>嘿嘿嘿嘿, 一级标题</h1>",
mytitle: "这是一个自己定义的title"
},
methods: { // 这个methods属性中定义了当前实例所有可用的方法
show: function(){
alert('hello !')
},
mouse: function(){
alert('v-on的缩写形式为@')
}
}
})
</script>
</body>
</html>
<!-- 1. 如何定义一个基本的Vue代码结构 -->
<!-- 2. 插值表达式 和 v-text -->
<!-- 3. v-cloak -->
<!-- 4. v-html -->
<!-- 5. v-bind Vue提供的属性绑定机制 缩写是 : -->
<!-- 6. v-on Vue提供的事件绑定机制 缩写是 @ -->
总结:
例子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="lib/vue.js"></script>
</head>
<body>
<div id="app">
{{message}} <br>
{{msg}} <br>
<span v-bind:title="time">
鼠标停留在这几秒看看......
</span>
<br>
<h1 v-if="str === 'A'">v-if的使用</h1>
<h1 v-else-if="str === 'B'">v-else-if的使用</h1>
<h1 v-else="str === 'C'">v-else的使用</h1>
<h2 v-show="str === 'B' || str === 'C'">v-show的使用,它只是简单操作css的display样式</h2>
<hr>
<ul>
<li v-for="todo in todos">
{{todo.text}}
</li>
</ul>
</div>
<script>
var strs = ['A', 'B', 'C']
var str = strs[Math.round(Math.random() * 3)]
let app = new Vue({
el: '#app',
data: {
message : "Hello Vue !!!",
msg : '你好, Vue。',
time : '页面加载于....' + new Date().toLocaleString(),
str : str,
todos : [
// 控制台输入app.todos.push({text : "哈哈哈哈哈"}),可以动态添加内容
{text : '学习JavaScript'},
{text : '学习Java'},
{text : '学习Vue'},
{text : '啥都不想学'}
]
}
});
var t = setInterval(function(){
str = strs[Math.round(Math.random() * 2)];
console.log(str)
app.str = str;
}, 1000);
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="/lib/vue.js"></script>
</head>
<body>
<div id="app">
<input type="button" value="浪一波" @click="lang">
<input type="button" value="低调" @click="stop">
<p>{{ msg }}</p>
</div>
<script>
/*
在vm实例, 会监听自己身上的 data中所有数据的改变, 只要数据一发生变化, ,
就会自动把最新的数据, 从data上同步到页面上去;
*/
var vm = new Vue({
el: "#app",
data: {
msg: "猥琐发育, 别浪~~~",
timer: null // 在data上定义定时器的id
},
methods: {
lang(){
// var _this = this 这种方式不建议使用, 可以使用箭头函数
/*
箭头函数没有this, 会绑定当前作用域的this
而function的this会在调用时动态绑定this
*/
if (this.timer != null) return;
this.timer = setInterval(() => {
console.log(this.msg)
var start = this.msg.substring(0, 1)
var end = this.msg.substring(1)
this.msg = end + start
}, 200)
},
stop(){
console.log("停止")
clearInterval(this.timer)
// 每当清除了定时器之后, 需要把timer设置为null
this.timer = null
}
}
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="lib/vue.js"></script>
<style>
*{
padding: 0;
margin: 0;
}
#app{
margin: 20px auto;
height: 500px;
width: 500px;
background-color: rgb(61, 0, 230);
}
</style>
</head>
<body>
<!-- 冒泡机制 -->
<!-- 使用.stop 阻止冒泡 -->
<div id="app" @click="div">
<input type="button" value="点击按钮" @click.stop="btn">
</div>
<a href="http://www.baidu.com" @click.prevent="linkClick">有问题去百度</a>
<script>
var vm = new Vue({
el: "#app",
data: {
},
methods: {
btn(){
console.log("按钮被点击了......")
},
div(){
console.log("div被点击了......")
},
linkClick(){
console.log("触发了链接的点击事件")
}
}
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.active {
color: red;
}
</style>
</head>
<body>
<div id="app">
<button v-on:click="changeColor">变色</button>
<!--这里class中是一个对象,键 为类名,值为 布尔型,为true则插入到类中,反之移除-->
<h2 class="title" v-bind:class="{active: true, line: true}">{{message}}</h2>
<h2 class="title" v-bind:class="getClasses()">{{message}}</h2>
<img v-bind:src="imgURL" alt=""> <br>
<a v-bind:href="href">{{word}}</a>
<!--绑定的缩写形式-->
<img :src="imgURL" alt=""> <br>
<a :href="href">{{word}}</a>
</div>
<script src="lib/vue.js"></script>
<script>
/*
* var 定义的变量 全局的
* let 定义的变量 有作用域
* const 定义的是常量,不可修改
* */
const app = new Vue({
el: '#app',
data: {
message: '你好,Vue',
imgURL: 'https://tx-live-cover.msstatic.com/huyalive/94525224-2460685313-10568562945082523648-2789274524-10057-A-0-1/20200327105831.jpg?sign=JGU6iHSf0svbUe7Fh+SfYC6qxQ1hPTEyNTM0OTg3MDEmaz1BS0lEeG56NjRXQTU3eGQ4VUVxVXlIT0tuQUxRTEN1UkN6NTUmZT0xNTkzMDUzOTExJnQ9MTU4NTI3NzkxMSZyPTEyMzQ1Njc4JmY9L2h1eWFsaXZlLzk0NTI1MjI0LTI0NjA2ODUzMTMtMTA1Njg1NjI5NDUwODI1MjM2NDgtMjc4OTI3NDUyNC0xMDA1Ny1BLTAtMS8yMDIwMDMyNzEwNTgzMS5qcGcmYj1odXlhLXNjcmVlbnNob3RzLXJldmlldy0xMjUzNDk4NzAx',
href: 'http://www.baidu.com',
word: '百度一下,你就知道',
/*
* class 类名,值为布尔值
* */
classes: {
active: true,
line: false
}
},
methods: {
changeColor: function () {
this.classes.active = !this.classes.active
},
getClasses: function () {
console.log(this.classes);
return this.classes;
}
},
created: function () {
console.log('created');
},
mounted: function () {
console.log('mounted');
}
})
</script>
</body>
</html>
总结:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.active {
color: red;
background-color: yellow;
}
li:hover {
background-color: yellow;
cursor: pointer;
}
</style>
</head>
<body>
<div id="app">
<ul>
<li v-for="(m, index) in movies"
:class="{active: index == currentIndex?true:false}"
v-on:click="getRed(index)">
{{m}}
</li>
</ul>
</div>
<script src="lib/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
movies: ['七龙珠', '火影忍者', '蜡笔小新', '千与千寻', '哈尔移动的城堡', '钢铁侠', 'I\'m a Iron man '],
isActive: false,
currentIndex: 0
},
methods: {
getRed: function (index) {
this.currentIndex = index
}
}
})
</script>
</body>
</html>
默认第一个 被选中,有颜色。
然后点击哪个,哪个就被选中,其他则不被选中。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<h2>{{message}}</h2>
<h3>{{getFullName()}}</h3>
<h4>{{fullName}}</h4>
</div>
<script src="lib/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好,Vue',
lastName: '聂',
firstName: '保华'
},
methods: {
getFullName: function () {
return this.lastName + " " + this.firstName
}
},
computed: {
fullName: function () {
return this.lastName + " " + this.firstName
}
}
})
</script>
</body>
</html>
当我们直接调用函数的时候,需要加括号。
如果使用computed中的,不需要加括号。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
[v-cloak]{
display: none;
}
</style>
</head>
<body>
<div id="app">
<h2>{{message}}</h2>
<h3 v-cloak>总价钱为: {{totalPrice}}</h3>
</div>
<script src="lib/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好,Vue',
bookes: [
{id: 110, name: 'Unix编程艺术', price: 119},
{id: 111, name: '代码大全', price: 107},
{id: 112, name: '微服务实战', price: 199},
{id: 113, name: '深入理解Java虚拟机', price: 188}
]
},
computed: {
totalPrice: function () {
let sum = 0;
for (let i = 0; i < this.bookes.length; i++) {
sum += this.bookes[i].price;
}
// 这里的i是下标
for (let i in this.bookes) {
console.log('i的值为:' + i);
console.log(this.bookes[i].name)
}
console.log("--------------------");
// 这里的book是books中的单个对象
for (let book of this.bookes) {
console.log('i的值为:' + book);
console.log(book.name)
}
return sum;
}
}
})
</script>
</body>
</html>
有几种for循环要记住。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<span v-if="isUser">
<label for="username">用户账号:</label>
<input type="text" id="username" placeholder="用户账号:" key="不复用">
</span>
<span v-else>
<label for="mail">用户邮箱:</label>
<input type="text" id="mail" placeholder="用户邮箱">
</span>
<button @click="isUser = !isUser">切换类型</button>
</div>
<script src="lib/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
isUser: true
}
})
</script>
</body>
</html>
上面的key属性,页面中,我们输入一个账号的时候,再去切换登录框,则原来input中的数据会被清空
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
/*
* filter/map/reduce
* filter中的回调函数有一个要求:必须返回一个boolean值
* 如果返回true时,函数内部会自动将这次回调的n加入到新的数组中
* 如果返回false,函数内部会过滤掉这次n
* 最后全部结束,会返回一个新的数组
*
* 例子:有一组数,取出其中大于50的数
* */
const nums = [23, 45, 67, 88, 112, 124, 43, 23];
let newNums = nums.filter(function (n) {
return n > 50; // 返回值类型:布尔型。 如果为真,留下当前元素,否则删除当前元素。
});
// 最终filter内执行完毕之后,返回一个新的 数组。
// [67, 88, 112, 124]
console.log(newNums);
/*
* map函数的使用
* 所有返回的值会组一个新的数组
* */
let new2Nums = newNums.map(function (n) {
return n * 2; // n为 数组中的元素,逐个遍历。
});
// [134, 176, 224, 248]
// 134 + 176 + 224 + 248 = 782
console.log(new2Nums);
/*
* reduce函数的使用 reduce(回调函数,初始值)
* 作用:对数组中的所有的内容进行汇总
* 回调函数的参数:
* previousSum 之前值的总和
* currentValue 当前的 值
*
* */
let total = new2Nums.reduce(function (previousSum, currentValue) {
return previousSum + currentValue;
}, 0);
// 782
console.log(total);
/* -- 综上可得 高阶函数使用:-- */
let sum = nums.filter(function (n) {
return n > 50;
}).map(function (n) {
return n * 2;
}).reduce(function (preSum, currentValue) {
return preSum + currentValue;
}, 0);
console.log(sum);
/* 更加高级的箭头函数 */
let sum2 = nums.filter(n => n > 50).map(n => n * 2).reduce(((pre, cur) => pre + cur), 0);
console.log(sum2);
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<!--
v-model其实是一个语法糖,它的背后本质上是包含两个操作的:
1. v-bind绑定一个value属性
2. v-on指令给当前元素绑定input事件
-->
第一种
<input type="text" v-model="message">
<h2>{{message}}</h2>
第二种
<!-- @ 或 v-on 表示监听, 这里表示监听input框 -->
<input type="text" :value="message" @input="message = $event.target.value"> <br> <br>
第三种
<input type="text" :value="message" v-on:input="showValue"> <br> <br>
<label for="male">
<input type="radio" value="男" v-model="sex" name="sex" id="male" checked> 男
</label>
<label for="female">
<input type="radio" value="女" v-model="sex" name="sex" id="female"> 女
</label>
<h3>sex的值为:{{sex}}</h3>
<label v-for="item in originalHobbies" :for="item">
<input type="checkbox" name="hobby" v-model="hobbies" :value="item" :id="item"> {{item}}
</label>
<h3>选择的爱好为:{{hobbies}}</h3>
<select name="do" multiple v-model="mySelects">
<option v-for="item in selects">{{item}}</option>
</select>
<h3>你的选择:{{mySelects}}</h3>
<!-- 修饰符lazy 懒加载 -->
<input type="text" v-model.lazy="message">
<h2>{{message}}</h2>
<!--修饰符number v-model-->
<input type="number" v-model="age">
<h3>age的值{{age}}, 类型是{{typeof age}}</h3>
<!--使用number之后的-->
<input type="number" v-model.number="age">
<!--修饰符 trim 去除两边的空格 v-model.trim -->
</div>
<script src="lib/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好,Vue',
sex: '男',
hobbies: [],
originalHobbies: ['篮球', '乒乓球', '羽毛球', '排球', '高尔夫球'],
selects: ['钢琴', '小提琴', '大提琴', '吉他', '唢呐'],
mySelects: [],
age: 18
},
methods: {
showValue: function (event) {
this.message = event.target.value
}
}
})
</script>
</body>
</html>
v-model相当于 v-bind绑定一个value属性,v-on给当前元素绑定input事件
$event 是 window对象
一个函数,参数是用event接收, 调用此函数时,若参数为空,则event是当前window对象,
也可以传参$event
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<my-cpn></my-cpn>
<div>
<my-cpn></my-cpn>
</div>
<my-cpn></my-cpn>
<!-- <mycomp></mycomp>-->
</div>
<hr>
<div id="app2">
<mycomp></mycomp>
<mycomp></mycomp>
<mycomp></mycomp>
<my-cpn></my-cpn>
</div>
<script src="lib/vue.js"></script>
<script>
// ES6语法 ``可以直接换行
// 1. 创建组件构造器对象
const componentConstruct = Vue.extend({
template: `
<div>
<h2>我是标题</h2>
<p>我是内容,哈哈哈哈</p>
<p>我是内容,呵呵呵呵</p>
</div>
`
});
const mycomp = Vue.extend({
template: `
<div>
<p>局部组件----~~~~</p>
<p>我是内容~~~~~~~~</p>
</div>
`
})
// 2. 注册组件 全局组件
Vue.component('my-cpn', componentConstruct);
const app = new Vue({
el: '#app',
data: {
message: '你好,Vue'
}
})
// 局部组件
let app2 = new Vue({
el: '#app2',
components: {
mycomp: mycomp
}
})
</script>
</body>
</html>
总结:
// 1. 创建组件构造器对象
const componentConstruct = Vue.extend({
template: `
<div>
<h2>我是标题</h2>
<p>我是内容,哈哈哈哈</p>
<p>我是内容,呵呵呵呵</p>
</div>
`
});
// 2. 注册组件 全局组件
Vue.component('my-cpn', componentConstruct);
// 局部组件
let app2 = new Vue({
el: '#app2',
components: {
mycomp: mycomp // 这里可以直接省略写成 mycomp
}
})
<div id="app2">
<mycomp></mycomp>
<mycomp></mycomp>
<mycomp></mycomp>
<my-cpn></my-cpn>
</div>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<parent></parent>
<br> <br>
<new></new>
</div>
<script src="lib/vue.js"></script>
<script>
let son = Vue.extend({
template: `
<div>
<h3>子组件-----------首</h3>
<p>啦啦啦啦啦啦</p>
<h3>子组件------------尾</h3>
</div>
`
});
let parent = Vue.extend({
template: `
<div>
<h3>父组件-------首</h3>
<son></son>
<p>嘿嘿嘿嘿嘿嘿嘿或或和或或或或或或或或或或或或或或</p>
<h3>父组件--------尾</h3>
</div>
`,
components: {
son: son
}
});
// 全局组件
Vue.component('parent', parent)
// 使用语法糖的方式 注册全局组件
Vue.component('new', {
template: `
<div>
<h2>另外一种 创建组件的方式</h2>
</div>
`
})
const app = new Vue({
el: '#app',
data: {
message: '你好,Vue'
},
// 局部组件
// components: {
// parent: parent
// }
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn></cpn>
<br> <br>
<comp></comp>
</div>
<script src="lib/vue.js"></script>
<script type="text/x-template" id="cpn01">
<div>
<h3>组件模板分离--第一种方式</h3>
</div>
</script>
<template id="cpn02">
<div>
<h3>组件模块分离------第二种方式</h3>
<h4>{{title}}</h4>
</div>
</template>
<script>
/*
* 组件的数据存放
* 组件对象也有一个data属性,也可以有methods属性,
* 只是这个data属性是一个函数
* 而且这个函数返回一个对象,对象内部保存着数据
* */
Vue.component('cpn', {
template: '#cpn01'
});
Vue.component('comp', {
template: '#cpn02',
data() {
return {
title: '我是标题。。。。。。。'
}
}
})
const app = new Vue({
el: '#app',
data: {
message: '你好,Vue'
}
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<h2>{{message}}</h2>
<br>
<mycpn></mycpn>
<br>
<hr>
<mycpn02></mycpn02>
</div>
<template id="cpn">
<div>
<h3>{{title}}</h3>
<p>{{content}}</p>
</div>
</template>
<script type="text/x-template" id="cpn02">
<div>
<h4>{{title}}</h4>
<p>{{content}}</p>
</div>
</script>
<script src="lib/vue.js"></script>
<script>
/*
* 为什么组件中的data必须是一个函数?
* 因为要保证 每个组件拥有属于它自己的状态,函数每次返回的对象都是一个新的对象。
* 例如 创建组件 计数器, 然后使用多个 该组件
* */
const app = new Vue({
el: '#app',
data: {
message: '你好,Vue'
},
components: {
mycpn: {
template: '#cpn',
data() {
return {
title: '这是标题。。。。',
content: '这是内容。。。。'
}
}
},
mycpn02: {
template: '#cpn02',
data() {
return {
title: '这是第二个组件的标题。。。',
content: '这是第二个组件的内容。。。'
};
}
}
}
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<!--需要绑定一下-->
<cpn v-bind:cmovies="movies" :cmessage="message"></cpn>
</div>
<script src="lib/vue.js"></script>
<template id="cpn">
<div>
<p>{{cmovies}}</p>
<p>{{cmessage}}</p>
<p>{{name}}</p>
<ul>
<li v-for="item in cmovies">
{{item}}
</li>
</ul>
</div>
</template>
<script>
/*
* 如何进行父子组件通信呢 ? Vue官方提到
* - 父 --> 子 通过props(属性) 传递数据
* - 子 --> 父 通过事件发送消息
* */
// 从父 向 子传数据,通过props
const cpn = {
template: '#cpn',
data() {
return {
name: "子组件中的数据"
}
},
methods: {
},
// 1. props: ['cmovies', 'cmessage'] // 对应 进行接收数据
// 2. 第二种 使用对象
props: {
// cmovies: Array, // 定义类型
// cmessage: String
//3. 定义类型,还有可以设置默认值
cmovies: {
type: Array,
// 类型是 一个 对象 或者 数组时, 默认值必须是一个函数,否则会报错。 经测试2.6.11版本没有报错
// default: ['如果没有', '传值过来,', '这个将作', '为默认值渲', '染到界面上']
default() {
return ['如果没有', '传值过来,', '这个将作', '为默认值渲', '染到界面上'];
}
},
cmessage: {
type: String,
default: 'cmessage的默认值设定',
required: true // 必须要传的值
}
}
};
const app = new Vue({
el: '#app',
data: {
message: '你好,Vue',
movies: ['七龙珠', '鬼吹灯', '旋风小子', '钢铁侠']
},
components: {
cpn: cpn
}
})
// // 省略写法
// let name = "124";
// a = {
// name : name
// }
// // 可以简写成
// b = {
// name
// }
</script>
</body>
</html>
总之,子组件 通过props属性获取 父组件的数据。
使用的时候,绑定 props中对应变量,如果是驼峰标识,绑定的时候需要用 ‘ - ‘ 代替。
例如:
根vue实例
new Vue({
el: '#app',
data: {
info: {
name: '张三',
gender: '男',
age: '22'
},
message: '你好,Vue',
isMyMessage: '这是的一条信息'
}
})
props: {
cInfo: {
type: Object,
default () {
return [];
}
},
cIsMyMessage: {
type: String,
default: ''
}
}
组件
<template id="cpn">
<!--当使用多个标签式,最好有一个 根 标签-->
<div>
<p>{{cInfo}}</p>
<p>{{cIsMyMessage}}</p>
</div>
</template>
我们使用的时候
<div id="app">
<!--这里驼峰标识 要 改写成 ' - ' -->
<cpn :c-info="info" :c-is-my-message="isMyMessage"></cpn>
</div>
v-bind:c-info="info"
, 这里的Info,是vue根实例中的变量名。
等于是将 父组件中变量info的值,绑定到 子组件中的 cInfo。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<!--这里驼峰标识 要 改写成 ' - ' -->
<cpn :c-info="info" :c-is-my-message="isMyMessage"></cpn>
</div>
<script src="lib/vue.js"></script>
<template id="cpn">
<!--当使用多个标签式,最好有一个 根 标签-->
<div>
<p>{{cInfo}}</p>
<p>{{cIsMyMessage}}</p>
</div>
</template>
<script>
/*
* props中使用驼峰标识接收, 会有问题
* */
// 全局组件
Vue.component('cpn', {
template: '#cpn',
props: {
cInfo: {
type: Object,
default() {
return [];
}
},
cIsMyMessage: {
type: String,
default: ''
}
}
});
const app = new Vue({
el: '#app',
data: {
info: {
name: '张三',
gender: '男',
age: '22'
},
message: '你好,Vue',
isMyMessage: '这是的一条信息'
}
})
</script>
</body>
</html>
子组件
<template id="son">
<div>
<ul>
<li v-for="item in categories">
<button @click="itemClick(item)">{{item.name}}</button>
</li>
</ul>
</div>
</template>
子组件中的数据
const son = {
template: '#son',
data() {
return {
categories: [{
id: 1,
name: '热门推荐'
}, {
id: 2,
name: '手机数码'
}, {
id: 3,
name: '家用家电'
}, {
id: 4,
name: '电脑办公'
},]
}
},
methods: {
itemClick(item) {
console.log('子组件', item.name);
// emit 发射事件:(自定义事件) 当前 函数名, 不能用驼峰命名, 传参数item
this.$emit('item-click', item)
}
}
};
当子组件中的 点击事件 触发后,进入函数。通过 this.$emit('当前函数名', 变量)
。如果当前函数名为驼峰标识,使用-代替。例如当前可以写成 item-click 。 到这里 自定义 事件已经完成,然后父组件 绑定 该事件即可。
父组件
<div id="app">
<cpn v-on:item-click="cpnClick"></cpn>
</div>
引入子组件,并绑定 item-click事件,触发之后进入函数 cpnClick。
父组件中的函数
const app = new Vue({
el: '#app',
data: {
message: '你好,Vue'
},
components: {
cpn: son
},
methods: {
cpnClick(item) {
console.log('父组件----', item.name)
}
}
})
函数 中的参数,接收 来自 子组件传递来 的数据。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn v-on:item-click="cpnClick"></cpn>
</div>
<template id="son">
<div>
<ul>
<li v-for="item in categories">
<button @click="itemClick(item)">{{item.name}}</button>
</li>
</ul>
</div>
</template>
<script src="lib/vue.js"></script>
<script>
/**
* 当子组件需要向父组件传递数据时,就要用到自定义事件了。
* 之前学习的v-on 或 @ 不仅仅可以用于监听DOM事件,也可以用于组件间的自定义事件
*
* 自定义事件的流程:
* - 在子组件中,通过$emit()来触发事件
* - 在父组件中,通过v-on来监听事件
*
*/
const son = {
template: '#son',
data() {
return {
categories: [{
id: 1,
name: '热门推荐'
}, {
id: 2,
name: '手机数码'
}, {
id: 3,
name: '家用家电'
}, {
id: 4,
name: '电脑办公'
},]
}
},
methods: {
itemClick(item) {
console.log('子组件', item.name);
// emit 发射事件:(自定义事件) 当前 函数名, 不能用驼峰命名, 传参数item
this.$emit('item-click', item)
}
}
};
const app = new Vue({
el: '#app',
data: {
message: '你好,Vue'
},
components: {
cpn: son
},
methods: {
cpnClick(item) {
console.log('父组件----', item.name)
}
}
})
</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>Document</title>
</head>
<body>
<div id="app">
<apn @increase-click="increase" @less-click="less" :total2="total">
</apn>
</div>
a
<template id="son">
<div>
<p>{{total2}}</p>
<p><button @click="increaseClick">增加</button> <button @click="lessClick">减少</button></p>
</div>
</template>
<script src="lib/vue.js"></script>
<script>
const son = {
template: '#son',
methods: {
increaseClick() {
this.$emit('increase-click')
},
lessClick() {
this.$emit('less-click')
}
},
props: {
total2: {
type: Number,
default: 0
}
}
}
const app = new Vue({
el: '#app',
data: {
total: 1
},
methods: {
increase() {
this.total += 1;
},
less() {
this.total -= 1;
}
},
components: {
apn: son
}
})
/**
* 总结:
* 父 传 子 等于是 自定义 属性,
* v-bind:绑定子组件中的props的属性='父组件中data数据的名称'
* 即如代码中的 :total2="total" 或者 v-bind:total2="total"
*
* 子 传 父 等于是 自定义 事件
* v-on:监听子组件方法中this.$emit提交的函数名="父组件方法中的方法名"
* 即如代码中的 @increase-click="increase"
*
*/
</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>Document</title>
</head>
<body>
<div id="app">
<h2>num: {{number1}}</h2>
<cpn :dnumber1="number1" @numchange="numchange"></cpn>
</div>
<template id="cpn">
<div>
<h3>{{dnumber1}}</h3>
<input type="text" v-model="dnumber1">
</div>
</template>
<script src="./lib/vue.js"></script>
<script>
/*
watch函数,监听data中的数据变化,当值发生变化的时候,执行函数,该函数名就是变量名
*/
const app = new Vue({
el: '#app',
data: {
number1: 1,
},
methods: {
numchange(value) {
this.number1 = value;
}
},
watch: {
number1(newValue, oldValue) {
console.log('父组件中:旧数据是', oldValue, '---新数据是', newValue);
}
},
components: {
cpn: {
template: '#cpn',
props: {
number1: {
type: Number
}
},
data() {
return {
dnumber1: this.number1
};
},
watch: {
dnumber1(newValue, oldValue) {
console.log('子组件中:旧数据是', oldValue, '---新数据是', newValue);
this.$emit('numchange', newValue);
},
immediate: false
},
}
}
})
</script>
</body>
</html>
使用 $children、$refs、$parent、$root调用 方法
子组件
<template id="cpn">
<div>
<h3>我是子组件</h3>
<button @click="getParent">调用父组件</button>
</div>
</template>
cpn: {
template: '#cpn',
data() {
return {
name: '我是子组件中name属性'
}
},
methods: {
hello() {
console.log('我是 子组件中的hello函数');
},
getParent() {
// 访问父组件 $parent
console.log(this.$parent.parent())
// 访问根组件 $root
}
},
}
父组件
<div id="app">
<cpn></cpn>
<cpn ref="aaa"></cpn>
<cpn></cpn>
<button @click="hello">调用子组件</button>
</div>
{
el: '#app',
data: {},
methods: {
hello() {
//1. 通过 $children,它 是一个数组
this.$children[0].hello()
for (let child of this.$children) {
console.log(child.name)
}
//2. 通过$refs, 它默认是一个空的对象类型。 这个需要 在cpn中定义属性ref
this.$refs.aaa.hello() // 调用指定的子组件
},
parent() {
console.log('这是父组件的函数,被子组件调用')
}
}
最好的封装方式就是将共性抽取到组件中,将不同暴露为插槽
一旦我们预留了插槽,就可以让使用者根据自己的需求,决定插槽中插入什么内容
是搜索框,还是文字,还是菜单。由调用者自己来决定
<slot></slot>
<slot><button>这个是默认值</button></slot>
<template id="cpn">
<div>
<h3>我是子组件</h3>
<p>内容,子组件</p>
<slot><button>这个是插槽的默认值</button></slot>
</div>
</template>
<div id="app">
<!--
1. 插槽的基本使用 <slot></slot>
2. 插槽的默认值 <slot><button>这个是默认值</button></slot>
3. 如果有多个值,同时放入到组件进行替换时,一起作为替换元素
-->
<cpn><button>插槽按钮</button></cpn>
<cpn><a href="#">插槽超链接</a></cpn>
<cpn>
<p>插槽文字</p>
<strong>我也时插槽中的文字</strong>
</cpn>
<cpn></cpn>
</div>
使用子组件的时候,子组件标签中的值,会替换掉插槽中的值
就是给插槽起个名字,插入值的时候,可以插入指定的插槽。
<template id="cpn">
<div>
<h2>我是子组件,我有很多插槽</h2>
<slot name="left"><span>左边</span></slot>
<slot name="center"><span>中间</span></slot>
<slot name="right"><span>右边</span></slot>
</div>
</template>
<div id="app">
<cpn>
<h2>替换内容</h2>
<!-- 这种只会 替换没有名字的插槽,有名字的插槽不会改变 -->
<strong slot="center">我想替换中间的插槽</strong>
</cpn>
</div>
这样,中间插槽中的数据就被替换了。
父组件 替换 插槽的标签 ,但是内容是由子组件来提供的
子组件 使用 :data绑定数据
<template id="cpn">
<div>
<slot :data="dLanguages">
<ul>
<li v-for="item in dLanguages">{{item}}</li>
</ul>
</slot>
</div>
</template>
const app = new Vue({
el: '#app',
data: {},
methods: {},
components: {
cpn: {
template: '#cpn',
data() {
return {
dLanguages: ['JavaScript', 'Python', 'Java', 'C++', 'C#', 'C', 'Go']
}
}
}
}
});
父组件调用。slot-scope="slot"来取得作用域插槽 :data绑定的数据
<div id="app">
<!-- 默认使用li进行遍历 -->
<cpn></cpn>
<!-- 使用span进行遍历 用 - 连接 -->
<cpn>
<!-- 低版本的只支持 template -->
<template slot-scope="slot">
<div>
<span v-for="item in slot.data">{{item}} - </span>
</div>
</template>
</cpn>
<cpn>
<div slot-scope="slot">
<span v-for="item in slot.data">
{{item}} *
</span>
</div>
</cpn>
<cpn>
<div slot-scope="slot">
{{slot.data.join(' + ')}}
</div>
</cpn>
</div>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="./lib/vue.js"></script>
</head>
<body>
<div id="app">
<cpn></cpn>
<cpn>
<!-- 低版本的只支持 template -->
<template slot-scope="slot">
<div>
<span v-for="item in slot.data">{{item}} - </span>
</div>
</template>
</cpn>
<cpn>
<div slot-scope="slot">
<span v-for="item in slot.data">
{{item}} *
</span>
</div>
</cpn>
<cpn>
<div slot-scope="slot">
{{slot.data.join(' + ')}}
</div>
</cpn>
</div>
<template id="cpn">
<div>
<slot :data="dLanguages">
<ul>
<li v-for="item in dLanguages">{{item}}</li>
</ul>
</slot>
</div>
</template>
<script>
/*
父组件 替换 插槽的标签 ,但是内容是由子组件来提供的
*/
const app = new Vue({
el: '#app',
data: {},
methods: {},
components: {
cpn: {
template: '#cpn',
data() {
return {
dLanguages: ['JavaScript', 'Python', 'Java', 'C++', 'C#', 'C', 'Go']
}
}
}
}
});
</script>
</body>
</html>