混入(mixins)好处
什么是组件,为什么要有组件&组件的好处(!!!)
组件语法,创建父子组件
组件传值/通信(!!!
组件通信的语法(!!!
生命周期&钩子函数概念&作用(!!!
说明:后期是多个页面,每个页面都new Vue
因此:就会出现举例普通方法冗余 同一段代码写了多次
解决:通过混入(mixin)从而提高代码复用性,减少冗余
###局部
const 变量 = {
data() {// 1通过data来存放公共数据,2留心之前data是对象,现在data是函数返回对象
return {
// 模型数据
}
},
methods:{} // 留心:方法中使用模型数据,先用newVue模型中的,再用混入模型中的
//...
}
// 大家熟悉的语法
new Vue({
mixins: [变量名,...,变量名] // 作用:将公共代码混入进来,留心:变量名不能加引号 加引号就是字符串
el,
data: {},
methods,
computed,
watch
})
###全局(不需要去new Vue整合 直接所有都可以
Vue.mixin({
data,
methods
...
})
步骤1:创建两个Vue对象分别监控app1和app2
步骤2:app1显示uname=小明1和age=1模型数据 & 点击方法弹出模型中的姓名
步骤3:app2显示uname=小明2和age=2模型数据 & 点击方法弹出模型中的姓名
代码:
DOCTYPE html>
<html lang="en">
<head>
<title>vuetitle>
<meta charset="UTF-8">
head>
<body>
<div id="app1">
<button @click="fn">点击弹框button>
div>
<div id="app2">
<button @click="fn">点击弹框button>
div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script>
// 步骤1:创建两个Vue对象分别监控app1和app2
// 步骤2:app1显示uname=小明1和age=1模型数据 & 点击方法弹出模型中的姓名
// 步骤3:app2显示uname=小明2和age=2模型数据 & 点击方法弹出模型中的姓名
const vm1 = new Vue({
el: '#app1',
data: {
uname: "小明1",
age: 1
},
methods: {
fn() {
alert(this.uname)
}
}
})
const vm2 = new Vue({
el: '#app2',
data: {
uname: "小明2",
age: 2
},
methods: {
fn() {
alert(this.uname)
}
}
})
script>
body>
html>
发现:模型中的数据uname是不同的,但是methods中的方法代码一样,冗余
解决:通过mixin混入技术
代码1:
<!DOCTYPE html>
<html lang="en">
<head>
<title>vue</title>
<meta charset="UTF-8">
</head>
<body>
<div id="app1">
<button @click="fn">点击弹框</button>
</div>
<div id="app2">
<button @click="fn">点击弹框</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
// 步骤1:创建两个Vue对象分别监控app1和app2
// 步骤2:app1显示uname=小明1和age=1模型数据 & 点击方法弹出模型中的姓名
// 步骤3:app2显示uname=小明2和age=2模型数据 & 点击方法弹出模型中的姓名
const mixinOne = {
// data() { return {} }
// methods: {}
// computed: {}
data() {
return {
uname: "张三"
}
},
methods: {
fn() {
alert(this.uname) // 先有自己的,自己的没有再用公共的
}
}
}
const vm1 = new Vue({
// 融合公共代码,减少代码冗余 留心切记别加引号
mixins: [mixinOne],
el: '#app1',
data: {
// uname: "小明1",
age: 1
},
})
const vm2 = new Vue({
// 融合公共代码,减少代码冗余
mixins: [mixinOne],
el: '#app2',
data: {
uname: "小明2",
age: 2
},
})
</script>
</body>
</html>
代码2:
<!DOCTYPE html>
<html lang="en">
<head>
<title>vue</title>
<meta charset="UTF-8">
</head>
<body>
<div id="app1">
<button @click="fn">点击弹框</button>
</div>
<div id="app2">
<button @click="fn">点击弹框</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
// 步骤1:创建两个Vue对象分别监控app1和app2
// 步骤2:app1显示uname=小明1和age=1模型数据 & 点击方法弹出模型中的姓名
// 步骤3:app2显示uname=小明2和age=2模型数据 & 点击方法弹出模型中的姓名
Vue.mixin({
methods: {
fn() {
alert(this.uname)
}
}
})
const vm1 = new Vue({
el: '#app1',
data: {
uname: "小明1",
age: 1
},
})
const vm2 = new Vue({
el: '#app2',
data: {
uname: "小明2",
age: 2
},
})
</script>
</body>
</html>
组件(Component)是vue最强大的功能之一
将一个大型网站划分成一个个更小的可控单元(一个个组件 里面放html、css、js)
什么是组件?
就是一个文件(其实就是以前的html只不过语法不同了)里面存放html、js、css
这样有什么好处?
减少代码冗余,方便后期维护,因为它提出了一个概念,封装公共代码相互引用
说明:组件很重要,但写项目语法会比这个简单很多 因为框架封装了
定义
###局部的 也就是说你要在new Vue中写
const vm = new Vue({
el:
//...
components: {
标签名: {
template: `写HTML代码`,
data() {return {}},
methods
//...
}
}
})
###全局的
Vue.component(标签名, {
template: `放HTML代码`, // template 模板 也就是html
data() {return {}},
methods: {}
//...
})
调用
在【监控范围】内,直接写<标签名>标签名>
留心:如果标签名大写,需要将大写改成-小写(因为HTML不识别大小写
自定义组件mytag1输出:我叫MT1:T1
自定义组件mytag2输出:我叫MT2:T2
DOCTYPE html>
<html lang="en">
<head>
<title>vuetitle>
<meta charset="UTF-8">
head>
<body>
<div id="app">
<mytag1>mytag1>
<mytag2>mytag2>
<my-tag3>my-tag3>
div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script>
// 自定义组件mytag1输出:我叫MT1:T1
// 自定义组件mytag2输出:我叫MT2:T2
Vue.component('mytag1', {
template: `我叫MT1:T1
`
})
Vue.component('mytag2', {
template: `我叫MT2:T2
` //ES6模板字符串语法
})
Vue.component('myTag3', {
template: `webopen
`
})
const vm = new Vue({
el: '#app',
data: {
}
})
script>
body>
html>
自定义组件mytag1输出:你好,MT,听说你年薪1w
变量:name-MT,money-1
事件:p-click弹出hello,word
DOCTYPE html>
<html lang="en">
<head>
<title>vuetitle>
<meta charset="UTF-8">
head>
<body>
<div id="app">
<mytag1 />
div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script>
// 自定义组件mytag1输出:你好,MT,听说你年薪1w
// 变量:name-MT,money-1
// 事件:p-click弹出hello,word
Vue.component('mytag1', { // 组件名随意但是留意大小写
template: `
你好,{{name}},听说你年薪{{money}}w
`,
data(){
return {
name: 'MT',
money: 1
}
},
methods: {
say() {
alert('hello,word')
}
}
})
const vm = new Vue({
el: '#app',
data: {
}
})
script>
body>
html>
如何在组件中显示数据: 通过模板语法{{data中的键}}
如何在组件中使用事件: 通过事件语法@事件类型="函数名"
自定义组件mytag1输出:你好,MT(退出),听说你很M
变量:name-MT,age-100
事件:p-click弹出hello
注意:退出位置用a标签创建子组件
DOCTYPE html>
<html lang="en">
<head>
<title>vuetitle>
<meta charset="UTF-8">
head>
<body>
<div id="app">
<mytag1 />
div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script>
// 自定义组件mytag1输出:你好,MT(退出),听说你很M
// 变量:name-MT,age-100
// 事件:p-click弹出hello
// 注意:退出位置用a标签创建子组件
Vue.component('mytag1', {
template: `你好,{{name}}( ),听说你很M,{{age}}岁了
`,
data() {
return {
name: "MT",
age: 100
}
},
methods: {
say() {
alert('hello')
alert(this.age)
}
},
// 通过components来声明子组件 调用同之前的
components: {
// 键就是标签名 值是对象 内容一样
logout: {
template: `退出`
}
}
})
const vm = new Vue({
el: '#app',
data: {
}
})
script>
body>
html>
步骤1:定义组件/页面,语法创建(注:也有简化语法
步骤2:在页面调用显示即可
DOCTYPE html>
<html lang="en">
<head>
<title>vuetitle>
<meta charset="UTF-8">
head>
<body>
<div id="app">
<ul>
<li @click="chooseCompontent = 'index'">首页li>
<li @click="chooseCompontent = 'jiadian'">家电li>
<li @click="chooseCompontent = 'baojian'">保健li>
<li @click="chooseCompontent = 'meirong'">美容li>
ul>
<component v-bind:is="chooseCompontent">component>
div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script>
// 造组件
Vue.component('index', {
template: `这是首页页面`
})
Vue.component('jiadian', {
template: `这是家电页面`
})
Vue.component('baojian', {
template: `这是保健页面`
})
Vue.component('meirong', {
template: `这是美容页面`
})
const vm = new Vue({
el: '#app',
data: {
chooseCompontent: 'jiadian'
}
})
script>
body>
html>
如何实现?
通过组件通信技术
父组件->子组件:通过props接受父传递数据
步骤1:子通过props键来接受父传递的数据 props:['变量名',...,'变量名']
#注:这么写就相当于在子组件data中声明数据了
步骤2:父传递给子 父在调用子的组件上通过语法 v-bind:子组件props中的变量名="父组件中的data数据"
子组件->父组件:通过$emit创建自定义事件发送数据
步骤1:子创建自定义事件 通过语法 this.$emit(事件名称,数据1,...,数据n)
步骤2:父调用自定义事件获取数据 父必须在调用的子组件上触发事件,语法@自定义事件="函数名"
留心1:函数在父定义
留心2:底层会将自定义事件中的数据 传递给函数的形参
兄弟组件:通过EventBus(事件总线)
const eventBus = new Vue() // 相当于创建一个组件数据共享中心
// 发送数据:eventBus.$emit(自定义事件名称,数据1,.....,数据n)
// 接受数据(监控传递):eventBus.$on(自定义事件名称,处理函数)
自定义组件fathertag输出:
我是父组件,我儿子叫:赵冠希
【我是子组件,我爸爸给我取名:赵冠希
】
其中子组件sontag部分:【】
变量:sonName-赵冠希
为了更明显看出父子关系推荐:https://www.w3school.com.cn/tags/tag_fieldset.asp
DOCTYPE html>
<html lang="en">
<head>
<title>vuetitle>
<meta charset="UTF-8">
head>
<body>
<div id="app">
<fathertag>fathertag>
div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script>
Vue.component("fathertag", {
// 声明父组件中的数据
data() {
return {
sonName: '赵冠希' // 调用的时候注意大小写
}
},
// 声音父组件内容
template: `
`,
// 声明普通方法
methods: {},
// 声明子组件
components: {
// 键 - 子组件标签名,值 - 是对象里面有template、data、methods等
sontag: {
// 声明props属性来接受父传递的数据
props: ["myName"], // 留心:这么写就相当于在子的data中声明了myName模型数据
// 声明子组件的内容
template: `
`
}
}
})
const vm = new Vue({
el: '#app',
data: {
}
})
script>
body>
html>
上述代码基础上,在父组件fn1方法中能够获取子的myName2数据
子创建getSonData事件
父通过showSonData方法获取
<!DOCTYPE html>
<html lang="en">
<head>
<title>vue</title>
<meta charset="UTF-8">
</head>
<body>
<div id="app">
<fathertag></fathertag>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
Vue.component('fathertag', {
// 声明父组件的内容
template: `
`,
// 声明父的模型数据
data() {
return {
mySonData: ''
}
},
// 声明父的普通方法
methods: {
showSonDataFn(data) { // 这边有形参,几个呢 看自定义事件中传递了几个
// console.log(data)
this.mySonData = data
}
},
// 声明子组件
components: {
// 键-子组件名称,值-对象 里面有template、methods、data等
sontag: {
// 声明子组件的内容
template: `
`,
// 声明子组件模型数据
data() {
return {
myName2: '小明'
}
},
// 需求:子的数据传递给父用,因为父不能直接获取
// 思考:子声明时候创建自定义事件
// 回答:1 用户和网页交互后创建, 2 网页加载完毕后创建自定义事件 (目前的方案)
// 之前:js中window.onload jq $(function() {})
// 现在:使用mounted()
mounted() {
// 目前简单理解为
// 网页加载完毕后创建自定义事件
// 创建自定义事件语法:this.$emit('事件名称', 数据1,...,数据n)
// this.$emit("getSonData", 1111, 2222)
this.$emit("getSonData", this.myName2)
}
}
}
})
const vm = new Vue({
el: '#app',
data: {
}
})
</script>
</body>
</html>
步骤1:分别定义mytag1和mytag2组件,先写fieldset然后写button
步骤2:点击mytag1组件中的按钮,将mytag1组件中的msg变量传递给mytag2使用
DOCTYPE html>
<html lang="en">
<head>
<title>vuetitle>
<meta charset="UTF-8">
head>
<body>
<div id="app">
<mytag1>mytag1>
<mytag2>mytag2>
div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script>
// 定义数据共享中心
const eventBus = new Vue()
Vue.component('mytag1', {
data() {
return {
msg: 'data中的数据'
}
},
template: `
`,
methods: {
sendDataFn() {
// 发送数据:eventBus.$emit('事件名称', 数据1,...,数据n)
eventBus.$emit('mytag1MsgData', this.msg)
}
}
})
Vue.component('mytag2', {
template: `
`,
data() {
return {
broData: ''
}
},
// 之前:js window.onload jq $(function(){})
// 现在:vue中
mounted() {
// 接受数据(监控传递数据):eventBus.$on('事件名称', 处理函数)
eventBus.$on('mytag1MsgData', (msg) => {
// console.log(msg)
this.broData = msg
})
}
})
const vm = new Vue({
el: '#app',
data: {
}
})
script>
body>
html>
首先:发现还是挺麻烦的,那别管那么多只要把握下述语法理解怎么用 然后复制实现即可
其次:主要搞明白父子、子父工作场景还是较为多,因为后面会有一个vuex库来代替
原理:上述语法是我总结的,官方参考手册
https://cn.vuejs.org/v2/guide/components-props.html
https://cn.vuejs.org/v2/guide/components-custom-events.html
父->子(!
步骤1:子通过props接受数据
步骤2:父在调用子组件的标签上通过v-bind传递数据即可
子->父(!
步骤1:子创建自定义事件,通过this.$emit语法
步骤2:父在调用子组件的标签上通过@自定义事件名称="函数名"获取数据
兄弟(!
步骤1:创建数据共享中心 const eventBus = new Vue()
步骤2:通过eventBus.$emit发送数据
步骤3:通过eventBus.$on监控接受数据
说明:前面做过一个todolist案例数据是固定不变的
需求:数据动态,也就是请求接口。
思考:什么时候发送异步请求? 换句话说在哪写代码(以前:onload和$(function(){})
现在: mounted
生命周期:指代码可用和不可用时间(举例:局部变量声明周期,函数调用产生,函数调动完毕销毁)
钩子函数:在指定场景下触发的普通函数
https://cn.vuejs.org/v2/guide/instance.html#生命周期图示
DOCTYPE html>
<html lang="en">
<head>
<title>vuetitle>
<meta charset="UTF-8">
head>
<body>
<div id="app">
{{msg}}
div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script>
const vm = new Vue({
el: '#app',
data: {
msg: "神龙之母"
},
beforeCreate() {
console.group("beforeCreate:HTML没有剪切,模型没有初始化")
console.log(this.$el) // 打印剪切到内存中的数据
console.log(this.$data) // 打印已经初始化后的模型数据
console.log(this.msg) // 打印模型中的数据
console.groupEnd()
},
created() {
console.group("created:HTML没有剪切,模型已经初始化")
console.log(this.$el) // 打印剪切到内存中的数据
console.log(this.$data) // 打印已经初始化后的模型数据
console.log(this.msg) // 打印模型中的数据
console.groupEnd()
},
beforeMount() {
console.group("beforeMount:HTML已经剪切,HTML数据还没替换,模型已经初始化")
console.log(this.$el) // 打印剪切到内存中的数据
console.log(this.$data) // 打印已经初始化后的模型数据
console.log(this.msg) // 打印模型中的数据
console.groupEnd()
},
mounted() { // 挂载完毕,监控范围里面有vue语法 已经全部替换成最终数据
console.group("mounted:模型已经初始化、HTML数据已经替换完毕,并且放到了监控范围中")
console.log(this.$el) // 打印剪切到内存中的数据
console.log(this.$data) // 打印已经初始化后的模型数据
console.log(this.msg) // 打印模型中的数据
console.groupEnd()
},
beforeUpdate() {
console.group("beforeUpdate")
console.log('模型数据修改前触发')
console.groupEnd()
},
updated() {
console.group("updated")
console.log('模型数据修改后触发')
console.groupEnd()
},
beforeDestroy() {
console.group("beforeDestroy:组件销毁前")
console.groupEnd()
},
destroyed() {
console.group("destroyed:组件销毁后")
console.groupEnd()
}
})
script>
body>
html>
mounted
beforeCreate 监控范围中的HTML未剪切到内存、模型未初始化
mounted HTML已剪切到内存、HTML挂载/监控范围里面的vue模板语法替换成最终的数据 放到页面中、模型已初始化
脚下留心:mounted目前说已经挂载了(但:有特殊情况 它并不能保证 后面说 nextTick