赞
踩
视频地址:【尚硅谷Vue2.0+Vue3.0全套教程丨vuejs从入门到精通】 https://www.bilibili.com/video/BV1Zy4y1K7SH/?p=13&share_source=copy_web&vd_source=b1cb921b73fe3808550eaf2224d1c155
目录
Vue基础
Vue-cli 做工程开发
Vue-router 在Vue中实现前端入门
Vuex 保管数据
element-ui ui组件库
后起之秀:创作者参考了react框架做出了Vue框架。
虚拟DOM就是内存里的一组数据。
Diff算法:新的虚拟DOM与旧的虚拟DOM比较,此为Diff比较,如果新的虚拟DOM中有一部分与旧的虚拟DOM相同,那么相同的部分就会复用。只需要处理后来放进来的虚拟DOM。
vue3:简介 | Vue.js
教程和API是重要内容。
API:Vue字典。
风格指南:如何写出优雅的Vue代码
学习Vue的时候,在html页面中,引入vue.js,然后编写vue代码。以后在公司里干活,用高端平台-脚手架Vue-cli.
引入Vue后,多了一个Vue函数
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
- <title>初识Vue</title>
- <!-- 引入vue -->
- <script type="text/javascript" src="../js/vue.js"></script>
- <!-- 多了vue函数 -->
- </head>
- <body></body>
- </html>
谷歌插件。 Vue Devtools。
- <body>
- <script type="text/javascript">
- Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示
- </script>
- </body>
首先要准备好一个容器,为什么,因为使用Vue是用来构建界面的,对于Vue构建出来的界面,要摆在什么位置呢,所以得准备一个容器。
强制刷新:shift + 刷新
小常识。
- <body>
- <!-- 初识Vue
- 1. 想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象(这里的就是el和data
- 2. root容器里的代码依然符合html规范,只不过混入了一些特殊的Vue语法({{name}})
- 3. root容器里的代码被称为【Vue模板】 -->
- <div id="root">
- <h1>hello, {{name}}!</h1>
- </div>
-
- <script type="text/javascript">
- Vue.config.productionTip = false; //阻止 vue 在启动时生成生产提示
-
- // 创建vue实例
- const x = new Vue({
- el: "#root", // el用于指定当前Vue为哪个容器服务,值通常为css选择器字符串
- // 如果是类选择器,那么即为【el:'.root'】
- // 多组key-value之间使用逗号分隔
- data: {
- // data中用于存储数据,数据供el所指定的容器去使用,值我们暂时先写成一个对象
- name: "word",
- },
- });
- </script>
- </body>
总结
注意区分 js表达式 和 js代码(语句)
1、表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方
(1) a
(2) a+b
(3) demo(1)
(4) x===y?'a':'b' 三元表达式
js表达式:拿一个变量const x = 在左侧接,都能接到一个值。
2、js语句(代码)不生成值,只控制代码的走向
(1) if(){}
(2) for(){}
(3)
js表达式是一种特殊的js代码,或者是一种特殊的js语句
继续总结
模板的概念:root容器里的代码被称为【Vue模板】
有了模板也就要有模板语法。
目前只学了{{xxx}} 插值语法
何时使用插值语法,何时使用指令语法
实践
1、首先引入vue
- <title>模板语法</title>
- <!-- 引入Vue -->
- <script type="text/javascript" src="../js/vue.js"></script>
2、其次准备容器
- <body>
- <!-- 准备好一个容器 -->
- <div id="root">
- <h1>插值语法</h1>
- <h3>你好,{{name}}</h3>
- <hr />
- <h1>指令语法</h1>
- <a v-bind:href="url">点我去百度</a>
- <!-- v-bind:bind 绑定,v-bind就是vue里的指令 -->
- <!-- 加上v-bind,那么"url"就会当做js表达式去执行 -->
- <a :href="url2">点我去尚硅谷</a>
- </div>
- </body>
3、写vue部分的代码
- <script type="text/javascript">
- Vue.config.productionTip = false; // 阻止Vue在启动时生成生产提示
-
- new Vue({
- el: "#root",
- data: {
- name: "jack",
- url: "http://www.baidu.com",
- url2: "http://www.atguigu.com",
- },
- });
- </script>
v-bind:单向数据绑定。数据只能从data流向页面。即数据变化,页面上的数据也随之变化。但是页面的数据改变了,vue函数里的对象data中的数据却不随之改变。
v-model:双向数据绑定。数据不仅能从data流向页面,还可以从页面流向data。即数据变化,页面上的数据也随之变化。页面的数据改变,data中的数据也随之改变。
不是所有的数据都适合v-model。
v-model只能应用在表单类元素(输入元素)上,h2等元素是不能用的。
输入类元素:input 单选框 多选框,select,多行输入等表单元素,共同点就是都有value属性。
v-model: value可以简写为v-model,因为v-model默认收集的就是value值。
代码实现:
- 单向数据绑定:<input type="text" v-bind:value="name">
- 双向数据绑定:<input type="text" v-model:value="name">
简写为
- 单向数据绑定:<input type="text" :value="name">
- 双向数据绑定:<input type="text" v-model="name">
- const v = new Vue ({
- el:'#root', //第一种写法
- data:{
- name:'尚硅谷'
- }
- })
- console.log(v)
- v.$mount('#root') //第二种写法
mount挂载
将容器里写的模板交给vue实例进行解析,解析之后将解析完的内容重新放到页面的指定位置,放官方叫挂载。mount就有挂载的意思。
- data:{ // 对象式
- name:'尚硅谷'
- }
- //函数式,函数必须返回一个对象
- data: function () {
- return {
- name:'尚硅谷'
- }
- }
以后使用到组件,就必须使用data的函数式写法。
- data: function () {
- console.log(this) // 此处的this为Vue实例对象
- }
结果
- data: ()=> {
- console.log(this) // 此处的this为Vue实例对象
- return {
- name: '尚硅谷'
- }
- }
另外,在一个对象里写函数,一般就删掉function和冒号,简化为
- data() {
- console.log(this) // 此处的this为Vue实例对象
- return {
- name: '尚硅谷'
- }
- }
总结:
Vue的设计者在最初设计Vue时,就参考了这个模型。
MVVM模型在一堆数据和一堆DOM结构中间做了连接,它起到中间桥梁纽带作用。其实前端主流框架都是这个思想,数据放在要求的位置,然后写出模板代码,具体数据如何插入到模板中,就需要学习框架的语法,什么指令啊插值语法啊。然后框架开始工作,就可以将数据和模板建立起来连接。
ViewModel简称vm,vm是Vue实例对象。
因此以后用vm去接收Vue实例。
- const vm = new Vue({
- el: '#root', //第一种写法
- data:{ // 对象式
- name:'尚硅谷'
- }
- })
Object.defineProperty() 给对象定义属性(ES6)
举例
- <script type="text/javascript">
- let person = {
- name: '张三',
- gender: '男'
- }
- Object.defineProperty(person, 'age', {
- value:18
- })
- console.log(person)
- </script>
与下面的区别在哪呢
- let person = {
- name: '张三',
- gender: '男',
- age:'18'
- }
注意,使用Object.defineProperty()添加的属性,是不可以被枚举(遍历)的。
Object.keys(对象名)以数组的形式返回对象所有属性的属性名,
1.使用创建对象的时候添加属性,其属性为
2.使用Object.defineProperty()添加属性,遍历不到Object.defineProperty()添加的age属性
此即为不可枚举(说白了就是不能遍历)。
当然使用for-in也可以证明Object.defineProperty() 添加的属性不可枚举
// 遍历person对象的所有属性值
for(let key in person) {
console.log(person[key],',')
}
- Object.defineProperty(person, 'age', {
- value:18,
- enumerable:true,
- writable:true,
- configurable:true
- })
- let number = 19
- Object.defineProperty(person, 'age', {
- // 当读取age属性时,get就会被调用,且返回值就是age的值
- get:function () {
- return number
- }
- })
同时还有set函数,当修改age属性时,set函数(setter)就会被调用,且参数是修改的值。
- let number = 19
- Object.defineProperty(person, 'age', {
- // 当读取age属性时,get就会被调用,且返回值就是age的值
- get:function () {
- return number
- }
- set(value) {
- number = value
- }
- })
- let obj = {x:100}
- let obj2 = {y:1000}
- // 通过obj2读写obj的x
- Object.defineProperties(obj2, 'x', {
- //
- get() {
- return obj.x
- },
- set(value) {
- obj.x = value
- }
- })
具体操作
案例
- <div id="root">
- <h2>学校名称: {{name}}</h2>
- <h2>学校地址: {{address}}</h2>
- </div>
-
- <script type="text/javascript">
- Vue.config.productionTip = false
-
- const vm = new Vue({
- el:'#root',
- data:{
- name:"尚硅谷",
- address:"宏福科技园"
- }
- })
- console.log(vm)
- </script>
结果
可以看出,vm有对name和address的一组getter和setter。此即为数据代理。
通过vm读写name和address,就是读写data中的name和address,示意图如下。
数据代理图示
vm数据代理,方便编码。
- <!-- 准备好一个容器 -->
- <div id="root">
- <h2>欢迎来到{{name}}学习</h2>
- <button>点我提示信息</button>
-
- </div>
-
- <script type="text/javascript">
- Vue.config.productionTip = false
-
- new Vue ({
- el:'#root',
- data:{
- name:'尚硅谷'
- }
- })
-
- </script>
- <!-- 当点击button的时候,就去找名为showInfo的函数调用 -->
- <button v-on:click="showInfo">点我提示信息</button>
- showInfo(event) {
- console.log(event.target.innerText) //点我提示信息
- // alert("同学你好")
- }
- showInfo2(number,event) {
- console.log(number) //点我提示信息
- // alert("同学你好")
- }
总结:
案例
<a href="http://www.atguigu.com" @click="showInfo">点我提示信息</a>
showInfo函数
- methods: {
- showInfo(e) {
- e.preventDefault()
- alert("同学你好")
- }
- }
因为点击的是a标签,在弹出弹框点击确定后,会跳转到href网址,因此在showInfo里添加e.preventDefault()可以阻止跳转。
方案2
也可以阻止这个默认事件。
此处@click后面的prevent就是事件修饰符。
p15 后面的没怎么听
案例
一个input框
<input type="text" placeholder="按下回车提示输入" @keyup="showInfo">
showInfo事件
- showInfo(e) {
- // 按下回车才打印输入的值,回车的keyCode是13
- if(e.keyCode !== 13) return
- console.log(e.target.value)
- }
效果
只有按下回车才在控制台打印输入值,if(e.keyCode !== 13) return。
然后只需要在键盘事件后加一个修饰,就代表回车了。
- <!-- 准备一个容器 -->
- <div id="root">
- <span>姓<input type="text" v-model="firstName"></span>
- <br/>
- <br/>
- <span>名<input type="text" v-model="lastName"></span>
- <br/>
- <br/>
- <span>全名:{{firstName.slice(0,3)}}-{{lastName}}</span>
-
- </div>
- <script type="text/javascript">
- Vue.config.productionTip = false
- new Vue({
- el:'#root',
- data: {
- firstName: '张',
- lastName:'三'
- }
- })
- </script>
效果
但是,这里对于firstName的截取,在{{}}内有点复杂了,下面用methods实现。
data中的数据发生改变,那么Vue就会重新解析模板。
接下来就是计算属性,见1.7.2。
计算属性的setter,可以不写,如果计算属性以后会被修改,那么加上setter
- set(value) {
- const arr=value.split('-')
- this.firstName = arr[0]
- this.lastName = arr[1]
- }
计算属性总结:
完整形式
- computed:{
- // 完整形式
- fullName:{
- get(){
- return this.firstName + '-' + this.lastName
- },
- set(value) {
- const arr=value.split('-')
- this.firstName = arr[0]
- this.lastName = arr[1]
- }
- }
- }
简写
如图所示,绿色其实就是getter。红色就是计算属性的名。
代码
- <div id="root">
- <h2>今天天气很{{info}}</h2>
- <button @click="changWeather">切换天气</button>
- </div>
-
- <script type="text/javascript">
- Vue.config.productionTip = false
-
- new Vue({
- el:'#root',
- data: {
- isHot: true
- },
- computed:{
- info(){
- return this.isHot?'炎热':'凉爽'
- }
- },
- methods: {
- changWeather() {
- this.isHot = !this.isHot
- }
- }
- })
- </script>
结果
点击按钮,切换天气。
进一步简化代码,不用methods的函数了,直接在模板里面实现逻辑。因为切换天气,功能很单一,所以可以这样写。
- watch: {
- isHot: {
- immediate: false,
- handler (newValue, oldValue) {
-
- }
- }
- }
- vm.$watch('isHot', {
- handler (newValue, oldValue) {
-
- }
- })
跳过 p23
当watch配置项里只有handler()时才可以简写。
完整形式
- watch: {
- isHot: {
- handler (newValue, oldValue) {
-
- }
- }
- }
或者写法2
- vm.$watch('isHot', {
- handler (newValue, oldValue) {
-
- }
- })
简写形式
- watch: {
- isHot(newValue, oldValue) {
-
- }
- }
或者
- vm.$watch('isHot', function (newValue, oldValue) {
-
- })
p25 跳过。
将前面的姓名案例,用监视属性实现。
监视姓和名。
看了一半,没有记笔记。
- <!-- 准备好一个容器 -->
- <div id="root">
- <!-- 加上冒号,那么a就会被解析,去Vue里找a的值 -->
- <div class="basic" :class="mood" @click="changeMood">
- {{name}}
-
- </div>
-
- </div>
- <script type="text/javascript">
- Vue.config.productionTip = false
-
- new Vue({
- el:'#root',
- data: {
- name:'尚硅谷',
- mood:'normal'
- },
- methods:{
- changeMood() {
- this.mood = 'happy'
- }
- }
- })
- </script>
解读
从上向下就是123
1 代码就是动态地指定class,class的值需要读取mood,mood在Vue里。点击事件触发后,mood的值会变为happy,即class会变为happy。
案例升级——mood随机
- changeMood() {
- // this.mood = 'happy'
- const arr = ['happy', 'sad', 'normal']
- const index = Math.floor(Math.random()) //生成[0,1)的随机数
- this.mood = arr[index]
- }
案例继续升级——添加多个类名
- <div class="basic" :class="classArr" @click="changeMood">
- {{name}}
- </div>
-
-
- new Vue({
- el:'#root',
- data: {
- name:'尚硅谷',
- mood:'normal',
- classArr:['atguigu1', 'atguigu2','atguigu3']
- },
案例继续升级——要添加的类名个数确定
- <div class="basic" :class="classObj" @click="changeMood">
- {{name}}
- </div>
-
-
- new Vue({
- el:'#root',
- data: {
- name:'尚硅谷',
- mood:'normal',
- classObj: {
- atguigu1: false,
- atguigu2: true
- }
- },
样式的绑定除了用class,还可以用style内联样式。
代码
注意:style里的字体大小是font-size,在Vue里要写成fontSize,即驼峰式
- <div class="basic" :style="styleObj">{{name}}</div>
-
-
- new Vue({
- el:'#root',
- data: {
- name:'尚硅谷',
- mood:'normal',
- styleObj: {
- fontSize:'40px'
- },
- }
- }
像color等style,在Vue直接写color,但是像短横线的,就要改成驼峰式的。
- <div class="basic" :style="styleArr">{{name}}</div>
-
-
-
- el:'#root',
- data: {
- name:'尚硅谷',
- mood:'normal',
- styleArr: [
- {
- fontSize:'40px'
- },
- {
- color:'40px'
- }
- ],
数组里面放的就是样式的对象。
顾名思义:符合了某些条件,然后给你渲染某些东西。主要就是几个指令的使用。
要div时而显示时而隐藏。
如果用原生去实现,可以display:none或者透明度为0或者visibility为hidden。
但是Vue中指令v-show,底层实现就是调整display属性。
代码
<h2 v-show="true">欢迎来到{{name}}</h2>
v-show里是个表达式也可以,比如v-show=" 1=== 3".
v-if为false,这个节点本身也就不存在,这是与v-show的不同之处。v-show只是控制节点不显示,本质还是存在的。
<h2 v-if="false">欢迎来到{{name}}</h2>
如果切换频率高,建议使用v-show。v-if涉及到在DOM添加/删除节点,因此不适用于切换频率高的操作。
比三个if效率要高一些。
- <h2 v-if="n === 1">欢迎来到{{name}}</h2>
- <h2 v-else-if="n === 2">欢迎来到{{name}}</h2>
- <h2 v-else-if="n === 3">欢迎来到{{name}}</h2>
v-else就是最后if elseif else里的else作用。
- <h2 v-if="n === 1">欢迎来到{{name}}</h2>
- <h2 v-else-if="n === 2">欢迎来到{{name}}</h2>
- <h2 v-else-if="n === 3">欢迎来到{{name}}</h2>
- <h2 v-else>欢迎来到{{name}}</h2>
v-if v-else-if v-else中间不允许被打断,也就是不允许被插入其他语句。
- <div v-if="true">
- <h2>欢迎来到{{name}}</h2>
- <h2>欢迎来到{{name}}</h2>
- <h2>欢迎来到{{name}}</h2>
- <h2>欢迎来到{{name}}</h2>
- </div>
本来只是四个h2,但是为了将他们包在一起,所以多了个div。
更好的办法,使用template,模板,最大的特点是hi不影响结构。最终渲染的时候,红色框里的东西会消掉。
注意: template只能配合v-if使用,不能与v-show使用。
下面的xxx是表达式
基本的列表渲染
使用v-for指令,完成列表渲染。for-in
- <!-- 准备好一个容器 -->
- <div id="root">
- <ul>
- <li v-for="p in persons">{{p.name}}-{{p.age}}</li>
- </ul>
-
- </div>
-
- <script type="text/javascript">
- Vue.config.productionTip = false
-
- new Vue({
- el: '#root',
- data: {
- persons: [
- {id:'001',name:'张三',age:'18'},
- {id:'002',name:'张四',age:'19'},
- {id:'003',name:'张五',age:'20'}
- ]
- }
- })
- </script>
<li v-for="p in persons" :key="p.id">{{p.name}}-{{p.age}}</li>
<li v-for="(p, index) in persons" :key="p.id">{{p.name}}-{{p.age}}</li>
- <li v-for="(value, key) in car" :key="key">{{key}}-{{value}}</li>
-
- car: {
- name:'奥迪A8',
- price:'70w',
- color:'black'
- }
- <li v-for="(char, index) in str" :key="index">{{index}}-{{char}}</li>
-
-
- str: 'hello'
<li v-for="(number, index) in 5" :key="index">{{index}}-{{number}}</li>
详细探讨使用v-for渲染列表时,所传递的key的作用和原理。
key是Vue在用的,Vue用完之后弄成真实DOM以后就将key去掉了。
这part听明白就好了。
面试题:react、vue中的key有什么作用?(key的内部原理)
注意str.indexof(' ')返回值为0,不是-1(-1表示字符串内不包含某个字符串值)
vscode折叠代码,//#region 和 //#endregion
【watch实现】
- <div id="root">
- <h2>人员列表</h2>
- <input type="text" placeholder="请输入名字" v-model="keyword">
- <ul>
- <li v-for="(p, index) in filPersons" :key="index">{{p.name}}-{{p.age}}</li>
- </ul>
- </div>
-
- <script type="text/javascript">
- Vue.config.productionTip = false
- new Vue({
- el: '#root',
- data: {
- keyword:'',
- persons: [
- {id:'001',name:'马冬梅',age:'18'},
- {id:'002',name:'周冬雨',age:'19'},
- {id:'003',name:'周杰伦',age:'20'},
- {id:'004',name:'温兆伦',age:'22'}
- ],
- filPersons: []
- },
- watch: {
- keyword:{
- // immediate为true时会在开始时执行一下handler()
- immediate:true,
- handler(val) {
- // console.log('key被改了')
- this.filPersons = this.persons.filter( (p) =>{
- return p.name.indexof(val) != -1
- })
- }
- }
- }
- })
- </script>
解读
结果
运行
【computed实现】
- <div id="root">
- <h2>人员列表</h2>
- <input type="text" placeholder="请输入名字" v-model="keyword">
- <ul>
- <li v-for="(p, index) in filPersons" :key="index">{{p.name}}-{{p.age}}</li>
- </ul>
- </div>
-
- <script type="text/javascript">
- Vue.config.productionTip = false
- new Vue({
- el: '#root',
- data: {
- keyword:'',
- persons: [
- {id:'001',name:'马冬梅',age:'18'},
- {id:'002',name:'周冬雨',age:'19'},
- {id:'003',name:'周杰伦',age:'20'},
- {id:'004',name:'温兆伦',age:'22'}
- ],
- },
- computed: {
- filPersons() {
- return this.persons.filter( (p) =>{
- return p.name.indexOf(this.keyword) != -1
- })
- }
- }
- })
计算属性computed不需要监视keyword,因为当他依赖的数据keyword发生变化时,整个filPersons会重新执行,这样就会拿到一个新的值。
当computed和watch都能实现的时候,我们优先使用computed。
p32跳过。用到再看。
p33 Vue如何实现数据监视的。
p34跳过。
p35跳过。
p36跳过。
p37跳过。
简单功能。
form的action属性用于提交表单提交的地址。
小tips
1
- <form >
- <label for="demo">账号:</label>
- <input type="text" id="demo">
- </form>
点击账号文字的时候,光标也跳到input文本框里。
2 性别选择的时候,只能二选一,可以在男女两个input框上添加同一个name属性,这样就是二选一,而不是可以同时都选了。
- 男:<input type="radio" name="gender">
- 女:<input type="radio" name="gender"><br/><br/>
代码实现上面的表单form
- <div id="root">
- <form >
- 账号:<input type="text"> <br/><br/>
- 密码:<input type="password"><br/><br/>
- 姓名:
- 男:<input type="radio" name="gender">
- 女:<input type="radio" name="gender"><br/><br/>
- 爱好:
- 学习:<input type="checkbox">
- 打游戏:<input type="checkbox">
- 吃饭:<input type="checkbox"><br/><br/>
- 所属校区:
- <select>
- <option value="">请选择校区</option>
- <option value="beijing">北京</option>
- <option value="shanghai">上海</option>
- <option value="shenzhen">深圳</option>
- </select><br/><br/>
- 其他信息:
- <textarea></textarea><br/><br/>
- <input type="checkbox">阅读并接受<a href="http://www.baidu.com">《用户协议》</a><br/><br/>
- <button>提交</button>
- </form>
- </div>
上面这些都要接受Vue的管理,下面开始Vue代码。
账号和密码这类用 v-model收集就行。
- <script type="text/javascript">
- Vue.config.productionTip = false
- new Vue({
- el: '#root',
- data: {
- userInfo: {account:'',
- password:'',
- gender:'female',
- hobby:[],
- city:'beijing',
- other:'',
- agree:'',}
- },
- methods:{
- demo(){
- console.log(JSON.stringify(this.userInfo))
- }
- }
- })
-
- </script>
一些小问题。
1 this._data就是包含account、password等所有数据。但是不要直接去访问下划线变量,一般就是放在一个对象里。但是此时v-model的右边加上对象.
2 只能输入数字:
3 文本框不需要实时收集,在失去焦点的瞬间收集。
4自动去掉空格。
p39跳过。
内置指令:Vue作者定义好的指令,比如v-on,v-bind等,之前学的都是内置指令。
自定义指令就是自己设计的指令。
学过的指令:
v-bind:单向绑定解析表达式,可简写为:xxx
v-model: 双向数据绑定
v-for:遍历数组/字符串/对象
v-on: 绑定事件监听。可简写为@
v-if:条件渲染(动态控制节点是否存在)
v-else:条件渲染(动态控制节点是否存在)
v-show: 条件渲染(动态控制节点是否显示)
代码
- <div id="root">
- <div>{{name}}</div>
- <div v-text="name">
- </div>
- </div>
-
- <script type="text/javascript">
- Vue.config.productionTip = false
- new Vue({
- el: '#root',
- data: {
- name:'尚硅谷',
- }
- })
- </script>
其实还是推荐插值语法,插值语法更灵活。
v-text会拿到name的值替换到整个div内的值。且不能解析标签,案例如下。
v-html存在安全问题。p41 18:25之后不看了。
cookie的概念
cookie的格式类似json格式的字符串,key-value组成。
cookie存在本地的浏览器中。
页面闪现问题,出现{{xxx}}。v-cloak结合css可以解决。
style里[v-cloak] 是指选中所有标签里含有v-cloak属性的元素。
v-cloak作用就是当网速过慢,可以不让未经解析的模板显示在页面上,不然会很丑。
需求:让Vue保存一个数值n,随后呈现到页面上
- <div id="root">
- <div v-once>初始化的n值:{{n}}</div>
- <div>当前的n值是:{{n}}</div>
- <button @click="n++">点我n+1</button>
- </div>
-
- <script type="text/javascript">
- Vue.config.productionTip = false
- new Vue({
- el: '#root',
- data: {
- n:1,
- }
- })
- </script>
结果
初始化的n值只读了一次n值,也就是n为1,之后不再读取n值。
p45跳过
p46跳过
p47跳过
案例:通过透明度变化的例子引出生命周期。
实现1:通过外部的定时器实现透明度变化(不推荐)
中间实现涉及的小知识点:只要数据发生改变,Vue就会重新解析模板。
实现2:通过mounted()实现
- <div id="root">
- <h2 :style="{opacity}">欢迎学习vue生命周期</h2>
- </div>
-
- <script type="text/javascript">
- Vue.config.productionTip = false
- new Vue({
- el: '#root',
- data: {
- opacity:1,
- },
- methods: { },
- mounted() {
- setInterval(() => {
- this.opacity -= 0.01
- if(this.opacity <= 0) {
- this.opacity = 1
- }
- }, 16);
- }
- })
- </script>
mounted 挂载,在Vue完成模板解析并把初始真实的DOM放入页面后(挂载完毕)调用mounted()
mounted()就是一个普通函数,只是在Vue某个关键时候被调用。与mounted类似的函数还有三个,这些都是Vue的生命周期函数。Vue的生命周期,又名Vue的一生。
红色圈里的是完整的挂载流程。
debugger;用来打断点的。
用了Vue就尽可能减少自己操作DOM
Init Events & Lifecycle(是个环节,不是生命周期),用来制定规则,生命周期函数的个数,名字,何时调用,以及事件修饰符处理,但数据代理还没开始,此时vm还没有_data。
生命周期本质就是函数,等待Vue调用。
Init Events & Lifecycle之后马上调用了beforeCreate(),此为第一个生命周期函数。此时无法通过vm访问_data中的数据和methods中的方法。
Init injections & reactivity,数据监测(Vue如何监测对象和数组变化,为对象的属性匹配getter和setter,对操作数组的方法进行二次包装)和数据代理。
beforeCreate(),在数据监测和数据代理创建之前。
created(),在数据监测和数据代理创建完毕后,此时可以通过vm访问到data中的数据和methods中的方法。
created()之后,黄色菱形框,问:是否有el配置项,即在创建Vue的时候传没传el配置项?
传了。走yes那条线。
下一步,还是一个黄色菱形框,问:有没有template这个配置项(template与data和methods同等位置),
没传,那就走No那条线。
编译el的outerHtml作为template。
解释:这里,如果是innerHtml,那么就是下面红色区域的内容是模板;而如果是outerHtml,那么就是下面绿色区域的内容是模板。
直接写el:"#root",那么整个绿色的部分都是模板(即包括最外面一层的div)。
模板是肯定要有的,如果不写template,那么el指定谁是模板谁就是template。
右边注释,此时Vue开始解析模板,此时代码里的插值语法,@click,计算属性等等都开始被解析了。
然后生成虚拟DOM,注意是在内存中,此时页面还不能显示解析好的内容。因为此时还没有转成真实DOM。
beforeMount(),挂载之前,页面呈现的是未经Vue编译的DOM,此时Vue已经解析完了DOM,但是没有来得及往页面上放。此时所有对DOM的操作,最终都不奏效。如果在这里修改DOM,到了下一步,仍然是将虚拟DOM转成真实DOM,往vm.$el上存了一份,然后往页面一放。刚才不管是对DOM进行什么操作,最终都是将虚拟DOM转为真实DOM然后插入页面了。
意思是:不要在beforeMount()里操作DOM,不过操作了也是白费功夫。
Create vm.$el and replace 'el' with it。用 vm.$el替换掉整个el里的东西,也就是容器里的东西。在此步,Vue将内存中的虚拟DOM转成真实DOM,转成真实DOM后,往vm.$el上存了一份。
为什么要存一份呢?Vue在进行新虚拟DOM和旧虚拟DOM比较,万一有的元素节点可以复用,那么得有之前的节点或元素才能复用。所以说存真实的DOM节点无可厚非。
Mounted(),此时页面呈现的是经过Vue编译的DOM。
此时对DOM的操作均有效,但是尽可能避免,因为用了Vue就尽量不要直接操作DOM。
此时,Vue先去忙,忙完了,将真实DOM挂载到页面上了。
至此初始化过程结束。一般在此进行开启定时器、发送网络请求、订阅消息、绑定自定义事件等操作。
回头说一下前面的两条线,没有el和有template的两条线。
没有el:如果不写el,Vue就不知道他为哪个容器服务。
这里跳过了。P49 25:00
蓝色框里就是更新流程。
When data changes,只要data对象的数据发生改变,那么Vue立马调用beforeUpdate()。
beforeUpdate(),数据是新的,页面是旧的。此时页面和数据尚未保持同步。
Virtual DOM re-render and patch,虚拟DOM重新渲染以及,新旧虚拟DOM比较。
根据新数据,生成新的虚拟DOM,随后与旧的虚拟DOM进行比较,最终完成页面更新,即:完成了Model→View的更新。
MVVM模型
model:模型,即数据,View:即数据。此处就是完成了从model到view的步骤。这里挂载的时候就完成过一次了,只是那次叫初次渲染,这次叫更新。
Updated(),数据是新的,页面也是新的,数据和页面保持同步。
其实常用的生命周期也就那两三个。
销毁流程之前,经历 when vm.$destroy() is called,vm开始进行自我毁灭。
这里是在methods里面重新写一个方法,调用this.$destroy()。位置跟mounted()还是不大一样的。
调用vm.$destroy()后,vm被销毁。但是vm临死前的工作成果还是在的,只是没有人去管理了。且借助Vue的开发者工具,啥也看不到了。
官网介绍,调用vm.$destroy()就会完全销毁一个Vue实例,即vm。清理他与其他实例(组件实例对象,一个应用只能有一个vm,但是一个vm会管理一堆的组件实例对象。由于组件实例对象与vm十分相似,因此也称组件实例对象为微型vm)的连接,解绑vm上的全部指令以及事件监听器(自定义事件,而不是原生的DOM事件。原生的DOM事件绑定后就不能撤销,即便是vm被销毁了,也不会被撤销。)。
beforeDestroy(),销毁之前,也就是还没有被销毁。此时,vm的data、methods、指令等等,都处于可用状态。马上要执行销毁过程,一般在此阶段:关闭定时器,取消订阅消息,解绑自定义事件等收尾操作。但是所有对数据的更改不会再触发更新了。
Teardown watchers child components and event listeners。移除监听器,子组件和事件监听器(自定义事件)。只留下原生的事件。
destroyed(),这里数据改变也是不再触发更新了。react里没有这个钩子。这个钩子什么也不干,是存在感最低的钩子。
8个生命周期钩子,4对
beforeCreate() 和created(),数据监测和数据代理创建之前和之后,
beforeMounted()和mounted(),mounted(),做点初始化的事,开启定时器,发送网络请求,订阅消息,绑定自定义事件等等。
beforeUpdate()和updated()
beforeDestroy()和destroy(),beforeDestroy()做一点收尾性的工作,关闭定时器,取消订阅消息,
人的出生和将要离开——重要
挂载和将要销毁——重要
初始化的工作——mounted()
收尾性的工作——beforeDestroy()
温柔地取消透明度变化的显示。
- <div id="root">
- <h2 :style="{opacity}">欢迎学习vue生命周期</h2>
- <button @click="stop">点我停止变换</button>
- </div>
-
- <script type="text/javascript">
- Vue.config.productionTip = false
- new Vue({
- el: '#root',
- data: {
- opacity:1,
- },
- methods: {
- stop() {
- clearInterval(this.timer)
- }
- },
- mounted() {
- // 往vm的timer属性上存了一个定时器id
- this.timer = setInterval(() => {
- this.opacity -= 0.01
- if(this.opacity <= 0) {
- this.opacity = 1
- }
- }, 16);
- }
- })
- </script>
老师要求别的方法。
要求暴力停止,把vm也给清了。
stop里面调用this.$destroy()
- methods: {
- stop() {
- this.$destroy()
- }
- },
但是此时定时器还没关闭。关闭定时器在beforeDestroy里完成
- beforeDestroy() {
- clearInterval(this.timer);
- }
干掉vm,走销毁流程,那么beforeDestroy就会被调用,那么定时器就会被clear。
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。