目录
Vue框架入门系列(一)
/    

Vue框架入门系列(一)

vue官网https://cn.vuejs.org/v2/guide/installation.html

vue的几种安装方式

  1. 直接去官网引入js
  2. 使用引入cdn
  3. npm安装vue脚手架

vue分生产环境和开发环境,当我们开发的时候使用开发环境的版本,便于我们查阅源代码(有注释),

上线时候使用生产环境。

CDN

对于制作原型或学习,你可以这样使用最新版本:

<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>

hello.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="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提供的事件绑定机制 缩写是 @ -->

总结:

  • 绑定属性 v-bind: 简写:':'。 例如 v-bind:href = :href
  • 监听事件 v-on: 简写:'@'。例如 v-on:click = @click
  • v-text 和 v-html的区别:
    • v-text 不会解析 html标签
    • v-html会解析html标签

if else的使用

例子

<!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>

vue的生命周期

<!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>

总结:

  • 先执行create函数,然后执行其他的 例如methods, 最后执行mounted
  • 当绑定 class属性时, 该属性的值可以为一个对象,键为类名,值为布尔类型,当为true时,说明当前键对应的类名生效,否则无效。

bind的作业

<!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>

默认第一个 被选中,有颜色。

然后点击哪个,哪个就被选中,其他则不被选中。

computed计算属性

<!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中的,不需要加括号。

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循环要记住。

  • for直接遍历用下标,这个非常普遍。
  • for (let i in books) 使用in,这里的i也是下标的意思。books[i]
  • for (let book of books) 使用of,这里的book是books的单个元素。

登录切换案例

<!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中的数据会被清空

高级js函数的使用

<!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>
  • filter函数: 根据需要,过滤数组的元素,返回一个数组
  • map函数: 可以遍历数组中的每个元素,返回一个新的数组
  • reduce函数: 一把对于数组的求和。

v-model双向绑定

<!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>

总结:

  • 组件可分为全局组件和局部组件
    • 全局组件可以在所有vue管理的范围内使用
    • 局部组件只能在对应的vue管理div中使用
  • 首先
    // 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>

组件模板的抽离template

<!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>

watch 的使用

可以用来监听 某个 变量的 变化

<!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('这是父组件的函数,被子组件调用') } }

插槽的使用

最好的封装方式就是将共性抽取到组件中,将不同暴露为插槽
一旦我们预留了插槽,就可以让使用者根据自己的需求,决定插槽中插入什么内容
是搜索框,还是文字,还是菜单。由调用者自己来决定

  1. 插槽的基本使用
    <slot></slot>
  2. 插槽的默认值
    <slot><button>这个是默认值</button></slot>
  3. 如果有多个值,同时放入到组件进行替换时,一起作为替换元素
  • 子组件
    <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>

标题:Vue框架入门系列(一)
作者:gitsilence
地址:https://blog.lacknb.cn/articles/2020/04/25/1587785902124.html

Gitalking ...