Vue 04 生命周期 组件化 内置关系 Vue脚手架 render函数 ref属性 _props配置 mixin混入 插件 scoped样式

引出生命周期

此时调用change,定时器回调修改opacity,数据修改,模板重新解析,再次调用change。

挂载流程

更新流程

销毁流程

解绑(自定义)事件监听器

生命周期

注意注意注意!

但如果大家的模型层数据是从后台动态响应返回的,那么你肯定会遇到这么一个问题,为什么我mounted函数中的方法获取模型层数据是空的了??

经过我查看了:Vue.js 生命周期官方介绍,我才了解到:created和mounted执行时,异步初始化还没执行(还没执行完),也就是created里的数据还没获取到,mounted就开始了渲染视图的工作,那么这时模型层数据肯定就是为空的啦,而mounted只会调用一次,这就陷入了一个死局,mounted永远等不到created获取完数据后在渲染,那么解决的方法就是为mounted中的方法设置一个定时器,因为created获取数据的速度是很快的,我们只用让mounted停那么一丢丢时间就ok了!

解决方法:设定等待一个时间,确保你的初始值都已经被初始化在渲染视图

生命周期总结

 <div id="root">
        <!-- <h2 :style="{opacity}">hello,{{name}}</h2> -->
        <h2 :style="{opacity:opacity}">hello,{{name}}</h2>
        <button @click="stop">click stop</button>
        <button @click="opacity = 1">opacity 1</button>
       


    </div>
    <script type="text/javascript">
        Vue.config.productionTip = false;

        new Vue({
            el: "#root",
            data: {
                name: "atguigu",
                opacity: 1,
              

            },
            methods: {
                stop(){
                    this.$destroy();
                }
            },
            beforeDestroy() {
                clearInterval(this.timer);
            },

            //vue完成模板解析,并把初始的真实的dom元素放入页面后(挂载完毕),会调用该函数。
            mounted() {
                this.timer = setInterval(() => {
                    this.opacity -= 0.01;
                    if (this.opacity <= 0) { this.opacity = 1 }
                }, 16);
            },
            
        });


     
    </script>

 组件化

templat可以写在文件上部,也可以写在配置对象里面。

templat

Vue中不使用template时:

整个root容器当作模板

Vue使用template时:

会直接替换掉root,把template当作模板进行解析。 

 

组件不要写el属性。

new Vue({})、 Vue.extend、Vue.component

new Vue

1.new Vue({}),创建一个vm实例,vm.$mount('#app')挂载到app div上。

Vue.extend

1.Vue.extend({}),创建一个组件,组件的本质是一个VueComponent构造函数。

2.cosnt s = Vue.extend({options})可以简写为const s = {options}。简写也调用了Vue.extend。

3.写组件标签时<school></school>,就会创建school组件实例对象,相当于

new VueComponent({options})。

4.每次调用Vue.extend,返回的都是一个新的VueComponent。

内部sub变量接收VueComponent函数,返回sub。

vc是可复用的vm。el是vm特有的。

VueComponent.prototype.__proto__ === Vue.prototype

所以vc能够访问的Vue原型上的方法。

Vue.component

1.Vue.component其实内部是调用Vue.extend创建的子类构造方法,并且创建后放入Vue.options.components里面,以实现全局注册。而Vue.extend仅仅是创建子类构造方法,不放入Vue.options.components。其他细节和应用可看官方文档和网上文章。
 

// Vue.extend扩展子类
var subExtendClass = Vue.extend({
  name: 'SubExtendClass',
  data: function() {
    return {
      name: 'php'
    };
  },
  template: "<p>hi {{name}}, I'm dclnet</p>"
});
window.subExtendClass = subExtendClass;
console.log('Vue.extend class: subExtendClass ', subExtendClass);
// -----------------------------------------------
// Vue.component注册组件
var subComponent = Vue.component('SubComponent', {
  data: function() {
    return {
      name: 'java'
    };
  },
  template: "<p>hello {{name}}, I'm dclnet</p>"
});
window.subComponent = subComponent;
console.log('Vue.component class: subComponent ', subComponent);
// ===============================================
// html中使用组件
<div id="dclnet">
  <sub-component></sub-component>
  <sub-extend-class></sub-extend-class>
</div>
 
window.app = new Vue({
  el: '#dclnet',
  // 注意:这里直接放components里面,局部注册 <<<<<
  components: {'sub-extend-class': subExtendClass}
});

 

 非单文件组件

data需要用函数式写法

 

<div id="root">
        <h2>{{msg}}</h2>
       <!--组件标签-->
       <school>
       </school>

       <hr>

       <student>       
       </student>

       <student>   
       </student>

       <hello>
       </hello>
      
    </div>

    <div id="root2">

    </div>
    <script type="text/javascript">
        Vue.config.productionTip = false;


        //创建school组件
       const school = Vue.extend({

            template:`
            <div>
                <h2>schoolname:{{schoolname}}</h2>
                 <h2>schoolage{{schoolage}}</h2>
                 <button @click='show'>点击提示</button>
            </div>
            `,
            data(){
                return{
                    schoolname: "atguigu",
                    schoolage:20,
                }
            },
            methods: {
                show(){
                    alert(this.schoolname);
                }
            },
       });
       //创建stu组件
       const student = Vue.extend({
        template:`
            <div>
                <h2>stuname:{{stuname}}</h2>
                <h2>stuage{{stuage}}</h2>
            </div>
            `,
            data(){
                return{
                    stuname:'tom',
                    stuage:18,
                }
            },
       });
       //创建hello组件
       const hello = Vue.extend({
            template:`
            <div>
                <h2>stuname:{{stuname}}</h2>
                <h2>stuage{{stuage}}</h2>
            </div>
            `,
            data(){
                return{
                    stuname:'tom',
                    stuage:18,
                }
            },
       });


       //全局注册组件
       Vue.component('hello',hello);

        new Vue({
            el: "#root",
            data:{
                msg:'this is msg'
            },
            //局部注册组件
            components:{
                school:school,
                student,
            }
           
        });





     
    </script>

 组件的几个注意点


 组件的嵌套

 

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script type="text/javascript" src="../js/vue.js"></script>
    <title>Document</title>

</head>


<body>
    <div id="root">
   
      
    </div>

    
    <script type="text/javascript">
        Vue.config.productionTip = false;

        //创建student组件
        const student = Vue.extend({
            template:`
            <div>
                <h2>stuname:{{stuname}}</h2>
                <h2>stuage{{stuage}}</h2>
            </div>
            `,
            data(){
                return{
                    stuname:'tom',
                    stuage:18,
                }
            },
            
       });
       
        //创建school组件
       const school = Vue.extend({
            template:`
            <div>
                <h2>schoolname:{{schoolname}}</h2>
                 <h2>schoolage{{schoolage}}</h2>
                 <button @click='show'>点击提示</button>
                 <student></student>
            </div>
            `,
            data(){
                return{
                    schoolname: "atguigu",
                    schoolage:20,
                }
            },
            methods: {
                show(){
                    alert(this.schoolname);
                }
            }, 
            components:{
                student:student,               
            }  
       });
      
       //创建hello组件
       const hello = Vue.extend({
            template:`
            <div>
                <h2>{{msg}}</h2>
                
            </div>
            `,
            data(){
                return{
                    msg:'hello!'
                }
            },
       });


       const app = Vue.extend({
           template:`
                <div>
                    <hello></hello>

                    <school></school>
                </div>
           `,
           components:{
                school,
                hello,              
            } 


       })


       //vue
        new Vue({
            template:'<app></app>',
            el: "#root",
            //局部注册组件
            components:{
                app,             
            }         
        });


    </script>

</body>

</html>

 VueComponent

每次调用extend,都返回了一个VueComponent

 

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script type="text/javascript" src="../js/vue.js"></script>
    <title>Document</title>

</head>


<body>
    <div id="root">

        <!--组件标签-->
        <school>
        </school>

        <hello>
        </hello>



    </div>

    <div id="root2">

    </div>
    <script type="text/javascript">
        Vue.config.productionTip = false;


        //创建school组件
        const school = Vue.extend({

            template: `
            <div>
                <h2>schoolname:{{schoolname}}</h2>
                 <h2>schoolage{{schoolage}}</h2>
                 <button @click='show'>点击提示</button>
            </div>
            `,
            data() {
                return {
                    schoolname: "atguigu",
                    schoolage: 20,
                }
            },
            methods: {
                show() {
                    console.log(this)//VueComponent实例对象  vc
                    alert(this.schoolname);
                }
            },
        });


        //创建hello组件
        const hello = Vue.extend({

            template: `
            <div>
                <h2>hello:{{hello}}</h2>
               
            </div>
            `,
            data() {
                return {
                    hello: "hello",
                    
                }
            },
           
        });



        console.log(school);//一个构造函数
        console.log(hello);//一个构造函数
        console.log(school === hello);//false

        new Vue({
            el: "#root",
            data: {

            },
            //局部注册组件
            components: {
                school: school,
                hello:hello,
            }

        });

    </script>

</body>

</html>

 Vue实例与组件实例

一个重要的内置关系

复习原型对象: 

让组件vc,可以访问到Vue原型对象(一个object对象)上的属性、方法。

*查找属性和方法,会沿着隐式原型链查找。

<body>
    <div id="root">
        <school></school>
       
      
    </div>

   
    <script type="text/javascript">

        Vue.config.productionTip = false;
         //全局注册组件
       //Vue.component('hello',hello);
        Vue.prototype.x = 123;//此时x在vm的原型对象上
        
        //创建school组件
       const school = Vue.extend({
            name:'atguigu',
            template:`
            <div>
                <h2>schoolname:{{schoolname}}</h2>
                 <h2>schoolage{{schoolage}}</h2>
                 <button @click='show'>点击提示x</button>
            </div>
            `,
            data(){
                return{
                    schoolname: "atguigu",
                    schoolage:20,
                }
            },
            methods: {
                show(){
                    alert(this.x);//vc.x
                }
            },
       });
      

        const vm = new Vue({
            el: "#root",
            data:{
                msg:'this is msg',
                //x:123,  此时x在vm上
            },
            
            components:{
               school,
            }
           
        });

        console.log(school.prototype.__proto__ === Vue.prototype);//true


           
    </script>

</body>

单文件组件

Student.vue:

<template>
  <div class="demo">
    <h2>stuname:{{ stuname }}</h2>
    <h2>stuage{{ stuage }}</h2>
  </div>
</template>


<script>

            export default Vue.extend({
                name:"student",
                data() {
                    return {
                    stuname: "tom",
                    stuage: 18,
                    };
                },
                });

            //export default student;
</script>



<style>
        .demo{
            background-color: yellow;
        }
</style>

School.vue:

<template>
    <div class="school">
        <h2>schoolname:{{ schoolname }}</h2>
        <h2>schoolage{{ schoolage }}</h2>
        <button @click="show">点击提示</button>
    </div>
</template>


<script>
        export default Vue.extend({
        name:'school',
        data() {
            return {
            schoolname: "atguigu",
            schoolage: 20,
            };
        },
        methods: {
            show() {
            alert(this.schoolname);
            },
        },
        });
</script>



<style>
.school {
  background-color: red;
}
</style>

App.vue:

<template>

    <div>
        <school></school>
        <student></student>
        
    </div>
  
</template>


<script>
    import School from './School.vue';
    import Student from './Student.vue';

    export default{
        name:'App',
        components:{
            School,
            Student,
        }
        
        
    }
</script>



<style>

</style>

main.js:

import App from './App.vue';


new Vue({

    el:'#root',
    template:' <App></App>',
    components:{
        App,
    }

})

index.html:

<!DOCTYPE html>
<html lang="en">
<head>

    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>Document</title>

</head>

<body>

    <div id="root">
        
    </div>
    
    <script src="../js/vue.js"></script>
    <script src="./main.js"></script>
</body>
</html>

Vue脚手架

 在桌面创建一个demo文件夹

 编译helloworld

 helloworld界面

 分析脚手架结构

目前需要把组件名称改为双驼峰(SchoolMsg)这种,不然会报错!!!!!!!

不要用School!!!!

asssts :静态资源

components:子组件

public :页面

流程:执行nmp run serve,进入src找到main.js,发现需要引入App.vue,然后进入App.vue,引入App里面的子组件,main完成引入App,创建Vue实例,把组件放入容器中。

不需要在页面中引入main.js,脚手架已经配置好了。

main.js:

/*
该文件为入口文件
*/

//引入vue
import Vue from 'vue'

//引入App组件  所有组件的父组件
import App from './App.vue'

//关闭vue生产提示
Vue.config.productionTip = false

//创建vue实例对象
new Vue({
  //将App组件放入容器中
  render: h => h(App),
}).$mount('#app')

App.vue:

<template>

    <div>
        <img src="./assets/logo.png" alt="">
        <school></school>
        <student></student>
        
    </div>
  
</template>


<script>
    import School from './components/School.vue';
    import Student from './components/Student.vue';

    export default{
        name:'App',
        components:{
            School,
            Student,
        }
        
        
    }
</script>



<style>

</style>

 index.html:

<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8">
    <!--使IE以最高级别渲染页面-->
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <!--开启移动端理想视口-->
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <!--配置页签图标  路径封装 public文件夹-->
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <!--配置网页标题-->
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>


  <body>
    <!--当浏览器不支持script时,标签中的元素就会被渲染-->
    <noscript>
      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>

    <!--容器-->
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

目录结构:

 编译项目:

render函数

使用template+components:

 会报错,提示引入的Vue有问题:

当前引入语法(ES6模块化语法)

 要么交给render函数,要么引入带有模板解析器的Vue。

当前引入的Vue版本(残缺了模板解析器):

此时接收一个函数作为参数,会在页面创建一个h1元素,效果等同于template:`<h1>你好啊<h1>`

此时为什么要用render?

因为考虑到了引入的是残缺版的Vue,不能解析模板的版本。

 没有用到this,进行简写。并将组件App传入。

 为什么要用不完整版本的Vue,节省打包后的文件体积,模板解析器也不应该出现在打包文件里。

 解析标签类型的template

 修改默认配置

在vue.config.js里面修改。

 配置参考:配置参考 | Vue CLI (vuejs.org)https://cli.vuejs.org/zh/config/

 ref属性

标签添加ref属性,vc的一个属性会有这个dom。

对于传统的HTML标签,id 和 ref 都能实现获取dom的功能,

对于组件标签,给它加id标签时,相当于给该组件最外层容器加id,获得外层div。

 添加ref时,获得的是组件实例对象。

 

<template>

    <div>
        <h1 v-text="msg" ref="title"></h1>
        <button @click="show">button get dom</button>
        <img src="./assets/logo.png" alt="">
        
        <school-info ref="sch"></school-info>
        
        <student-info></student-info>

        
    </div>
  
</template>


<script>
    import SchoolInfo from './components/SchoolInfo.vue';
    import StudentInfo from './components/StudentInfo.vue';

    export default{
        name:'App',
        data(){
            return {
                msg:'this is a msg!'
            }
        },
        components:{
            // eslint-disable-next-line vue/no-unused-components
            SchoolInfo,
            // eslint-disable-next-line vue/no-unused-components
            StudentInfo,
        },
        methods: {
            show(){
                console.log(this.$refs);
                console.log(this.$refs.title);//dom
                console.log(this.$refs.sch);//获取school组件实例对象

            }
        },
        
        
    }
</script>



<style>

</style>

 _props配置

此时vc的_data中只有msg属性

 使用v-bind:  使标签引号里面的内容变为js表达式,age的值是运行引号里面表达式的结果。

props上的属性优先级大于data里面的。

<template>
  <div class="demo">
    <h1>{{msg}}</h1>
    <h2>stuname:{{ Mystuname }}</h2>
    <h2>stuage:{{ Mystuage+1 }}</h2>
    <h2>stusex:{{ Mystusex }}</h2>
    <button @click="set">修改age</button>
  </div>
</template>


<script>

            export default {
                name:"StudentInfo",
                data() {
                    return {
                    msg:'尚硅谷666',//msg出现在vc身上
                    Mystuname:this.stuname,
                    Mystuage:this.stuage,
                    Mystusex:this.syusex,

                    };
                },

                props:['stuname','stuage','stusex'],//简单申明接收


                //接收的同时对类型进行限制
                /*
                props:{
                  stuname:String,
                  stuage:Number,
                  stusex:String,
                }*/


                //接收的同时对类型、默认值、必要性进行限制
                // props:{
                //   stuname:{
                //     type:String,
                //     required:true,//必须要传的参数
                //   },
                //   stuage:{
                //     type:Number,
                //     default:99,//默认值
                //   },
                //   stusex:{
                //     type:String,
                //     required:true,
                //   },
                //},
                methods:{
                  set(){
                      
                      this.Mystunage ++;
                  }
                }

              }
            //export default student;
</script>



<style>
        .demo{
            background-color: yellow;
        }
</style>

mixin混入

 

mixin.js

// eslint-disable-next-line no-unused-vars
export const mixin = {
    methods: {
        show() {
          alert(this.name);
        },
      },
    mounted() {
        console.log('(mixin)挂载完毕')
    },
}

// eslint-disable-next-line no-unused-vars
export const mixin2 = {
    data(){
        return{
            x:200
        }
    }
}

StudentInfo.vue

<template>
  <div class="demo">
    <h1>{{ msg }}</h1>
    <h2 @click="show">stuname:{{ name }}</h2>
    <h2>stuage:{{ stuage }}</h2>
  </div>
</template>


<script>
//引入一个混合
// eslint-disable-next-line no-unused-vars
import {mixin} from '../mixin'
export default {
  name: "StudentInfo",
  data() {
    return {
      msg: "尚硅谷666", //msg出现在vc身上
      name: "jack",
      stuage: 18,
    };
  },
  mixins:[mixin],
  mounted() {
    console.log('(StudentInfo)挂载完毕')
  },
};
</script>



<style>
</style>

SchoolInfo.vue


<template>
  <div class="school">
    <h2 @click="show">schoolname:{{ name }}</h2>
    <h2>schoolage{{ schoolage }}</h2>
  </div>
</template>


<script>
//引入一个混合
// eslint-disable-next-line no-unused-vars
import {mixin} from '../mixin'
export default {
  name: "SchoolInfo",
  data() {
    return {
      name: "atguigu",
      schoolage: 20,
      x:66,//以本身的属性值为主
    };
  },
  mixins:[mixin],
  mounted() {
    console.log('(SchoolInfo)挂载完毕')
  },
 
};
</script>



<style>
</style>

全局引入混入:

/*
该文件为入口文件
*/

//引入vue
import Vue from 'vue'

//引入App组件  所有组件的父组件
import App from './App.vue'

//全局引入混合 vm vc 都能用
// eslint-disable-next-line no-unused-vars
//import {mixin,mixin2} from './components/mixin';

//关闭vue生产提示
Vue.config.productionTip = false

//Vue.mixin(mixin)
//Vue.mixin(mixin2)

//创建vue实例对象
new Vue({
  
  //将App组件放入容器中
  render: h => h(App),


}).$mount('#app')

插件

在 main.js引入并应用插件:

 定义一个插件,其中定义了全局过滤器、全局自定义指令、全局混入、Vue原型对象方法。vm和vc都能用。

plugins.js:

// eslint-disable-next-line no-unused-vars
export default {
    install(Vue,x){
        console.log(x)//1
       //全局过滤器
       Vue.filter('mySlice',function(value){
           return value.slice(0,4);
       });

       //定义全局自定义指令
       //指令语法就是操作dom元素的属性,内容,绑定事件。
       Vue.directive('fbind', {
           //指令与元素成功绑定时调用(一上来就调用)
           bind(el, binding) {
                el.value = binding.value;
           },
           //指令所在元素插入页面时调用
           inserted(el) {
               //默认获取焦点
                el.focus();
           },
           //指令所在模板重新解析时调用
           update(el, binding) {
               el.value = binding.value;
           },
       });

       //全局混入
       Vue.mixin({
           data(){
               return{
                   x:100,
                   y:200,
               }
           },
           methods: {
               show(){
                   alert(this.y);
               }
           },
       });

       //给Vue原型添加方法
       //vm和vc都能用
       Vue.prototype.hello = ()=>{
           alert("hello");
       }
    }
}

SchoolInfo.vue:


<template>
  <div class="school">
    <h2>schoolname:{{ name|mySlice }}</h2>
    <h2>schoolage{{ schoolage }}</h2>
    <button @click="show">获取y</button>
    <button @click="hello">hello!</button>
  </div>
</template>


<script>

export default {
  name: "SchoolInfo",
  data() {
    return {
      name: "尚硅谷atguigu尚硅谷",
      schoolage: 20,
      x:66,//以本身的属性为准
    };
  },
};
</script>



<style>
</style>

StudentInfo.vue

<template>
  <div class="demo">
    <h1>{{ msg }}</h1>
    <h2 >stuname:{{ name }}</h2>
    <h2>stuage:{{ stuage }}</h2>
    <input type="text" v-fbind:value='name'>
  </div>
</template>


<script>

export default {
  name: "StudentInfo",
  data() {
    return {
      msg: "尚硅谷666", //msg出现在vc身上
      name: "jack",
      stuage: 18,
    };
  },
};
</script>



<style>
</style>

scoped样式

使两个子组件的class可以重名,并且效果不同。

查看并安装less-loader

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值