一、Vue之导入、二、实例成员、三、指令、四、前台数据库、五、组件、 六、组件通信

一. Vue

  一个可以独立完成前后端分离式web项的轻量级的JavaScript框架

  三大主流框架之一:Angular  React  Vue

  Vue可以完全脱离服务器端,以前端代码复用的方式渲染整个页面:组件开发

二. Vue实例成员

  1. el: 挂载点  data:数据  methods:管理方法  delimiters:分隔符,解决前后台不分离语言冲突问题  

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Title</title>
    <style>
        .box{
            background-color: orange;
        }
    </style>
</head>
<body>
<div id="app">
    <div class="box" v-on:click="pClick">测试</div>
    <br>
    <div class="box" v-on:mouseover="pOver">悬浮测试</div>
</div>
</body>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el:'#app',
        data:{

        },
        methods:{
            pClick (){
                alert('box被点击了')
            },
            pOver (){
                alert('鼠标悬浮了?')
            }
        }
    })
</script>
</html>
View Code

  2. computed:计算属性     一个变量监听多个变量,并且渲染到页面中

       1)内部书写方法, 管理监听多个变量的方法

    2)方法名 可以直接作为变量被渲染,值为方法的返回值

       3)内部只要有一个变量有变化都会被监听,且方法名对应的值都会被影响【依方法的逻辑】

       4)computed用来解决一个变量值依赖多个变量值

两个案例:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <p><input type="text" v-model="first_name"></p>
    <p><input type="text" v-model="last_name"></p>
    <p> 全名:{{full_name}}</p>


</div>
</body>
<script src="js/vue.min.js"></script>
<script>
    new Vue({
        el:'#app',
        data:{
         first_name:'',
         last_name:'',
        },
        computed:{
            full_name (){
                return this.first_name + " " + this.last_name;
            }
        }
    })
</script>
</html>
View Code
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <input type="text" v-model="a_val">
    <input type="text" v-model="b_val">
    <input type="text" v-model="c_val">


    {{c}}

</div>
</body>
<script src="js/vue.min.js"></script>
<script>
    new Vue({
        el:'#app',
        data:{
        a_val:'',
        b_val:'',
        c_val:'',


        },
        computed:{
            c () {
                //将要监听的变量放在c方法中
                this.a_val;
                this.b_val;
                this.c_val;
           // console.log('该方法被调用了')
                return this.a_val + this.b_val + this.c_val
            }
        }
    })
</script>
</html>
View Code

   3.watch:监听属性

    1. watch内部书写方法,该方法名就是绑定的属性名,监听绑定的属性必须要提前初始化值

    2. 方法名代表的属性值发生改变,绑定的方法就会被自动触发/调用,

    3.  如full_name属性值发生变化了,就触发该方法。如可以转跳或向后台发送数据

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <p>
        姓名<input type="text" v-model="full_name">
    </p>


</div>
</body>
<script src="js/vue.min.js"></script>
<script>
    new Vue({
        el:'#app',
        data:{
        full_name:"",
            first_name:"",
        },
        watch:{
            full_name (){
                console.log('我被调用了');
 
            }
        }

    })
</script>
</html>
View Code

   4.delimiters:处理差值表达式与后台模板语言冲突问题,详见文本指令补充

三. 指令

  v-text、v-html、v-html、v-once  |  v-on  |  v-bind、v-model  |  v-if、v-else-if、v-else  |   v-show

  这些指令都是书写在标签的头部,没有Vue环境都是自定义属性;有Vue环境就是Vue语法

  直接等于一个变量;

    v-text

    v-html【可以解析html代码】

    v-html

    v-once

    v-if

    v-else-if

    v-else 【前面两个满足剩下的】

    v-model   【绑定value, 单选项框、独立单选框绑定true与false、多选框绑定数组】

    

  1.简写:  @ =  v-on:     |  :  =  v-bind

  2. 条件指令,方法methods提供;数据data提供

      v-if  页面消失时不渲染、即不显示页面结构; v-if、v-else-if、v-else: 后面跟条件表达式

      v-show  页面消失时以display:none 方式处理

  3. 属性指令:v-bind绑定普通属性就一个变量,绑定style就是多个变量,key、value形式

        v-bind绑定给类属性

  4.循环指令:v-for  ="ele in 容器变量"    【案例1=>     todolist案例】

    数组的循环

    <!--传统点0索引取值-->
    <!--for循环,谁要多个,就在哪里写for循环-->
    <!--可以取索引,数据在前,索引在后,在Vue中重要的数据在前-->

    <!--注:key属性是vue的属性,表示该标签在内存中建立缓存的依据-->
    <!--b为普通属性,cc就是普通字符串-->
    <!--a为绑定的属性,msg为变量,必须在data中定义-->

    案列1,

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>循环指令</title>
    <style>
        ul{
            list-style: none;
        }
        /*[v-cloak]{*/
            /*display: none;*/
        /*}*/
    </style>
</head>
<body>
<div id="app" v-cloak>
    <!--数组的循环-->
    <div>{{arr}}</div>

    <hr>
     <!--传统点0索引取值-->
    <ul>
        <li>{{ arr[0] }}</li>
        <li>{{ arr[1] }}</li>
        <li>{{ arr[2] }}</li>
    </ul>

    <hr>
    <!--for循环,谁要多个,就在哪里写for循环-->
        <ul>
        <li v-for="i in arr">{{i}}
        </li>
    </ul>

    <hr>
    <!--可以取索引,数据在前,索引在后,在Vue中重要的数据在前-->
    <ul>
        <li v-for="(s, i) in arr">第{{i+1}}个:{{s}}</li>
    </ul>
    <hr>

    <!--注:key属性是vue的属性,表示该标签在内存中建立缓存的依据-->
    <!--b为普通属性,cc就是普通字符串-->
    <!--a为绑定的属性,msg为变量,必须在data中定义-->
        <ul>
        <li v-for="(s, i) in arr" :key="s+i" b="cc" :a="msg">第{{i+1}}个:{{s}}</li>
    </ul>


</div>
</body>
<script src="js/vue.min.js"></script>
<script>
    new Vue({
        el:'#app',
        data:{
            arr:['aaa', 'bbb', 'ccc']
        },
    })
</script>
</html>
View Code

 

     对象的循环

      <!--对象循环只拿val-->
      <!--key、value都取,value在前,key在后-->
      <!--对象也可以取索引,默认从0开始-->

      <!--列表里套字典,不可以放变量,直接放[{}, {}, {}]-->

     对象循环案例
     
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>对象循环指令</title>
</head>
<body>
<div id="app">
    <ul>
        <!--对象循环只拿val-->
        <li v-for="(v) in dict">{{ v}}</li>
    </ul>
    <hr>

    <ul>
        <!--value在前,key在后-->
        <li v-for="(v, k) in dict">key:{{k}},值:{{v}}</li>
    </ul>

    <hr>
    <ul>
        <!--对象也可以取索引,默认从0开始-->
        <li v-for="(v, k, index) in dict">key:{{k}},值:{{v}},第{{ index }}</li>
    </ul>

    <hr>
    <!--列表里套字典-->
    <p v-for="stu in students">
        <span v-for="(val, ke, i) in stu">
            <b v-if="i != 0">|</b>
            <b>{{ ke }}:{{ val }}</b>

        </span>
    </p>

</div>
</body>
<script src="js/vue.min.js"></script>
<script>
    new Vue({
        el: '#app',
        data: {
            dict: {
                'name': 'jason',
                'gender': 'male',
                'age': 17

            },


            students: [
                {
                'name': 'owen',
                'gender': '哇奥',
                'age': 27
            },

             {
                'name': 'jason',
                'gender': '哇塞',
                'age': 21
            },

          {
                'name': 'egon',
                'gender': '我去',
                'age': 30
            },]
        }
    })
</script>
</html>
View Code


todolist案例

1) 数据为空直接结束

2)数据添加到留言数组中 

this.msg.push(this.msg_val); // 尾增
this.msg.unshift(this.msg_val); //首增

3)清空输入框

4)操作数组

// this.msg.splice(index, count,arg); // 从第几位开始,操作多少位,可变长的新数据
// count:0 新增 arg
// count:1,2 修改 成arg
// arg:0 删除
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>todolist</title>
    <style>
        li:hover{
            cursor:pointer;
            color: red;

        }
    </style>
</head>
<body>
<div id="app">
    <input type="text" v-model="msg_val" >
    <button @click="send_msg">留言</button>


    <ul>
        <li v-for="(v, i) in msg"  @click="del_msg">{{v}}</li>
    </ul>
</div>
</body>
<script src="js/vue.min.js"></script>
<script>
    new Vue({
        el:"#app",
        data:{
        msg:['第一条', '第二条'],
        msg_val:""
        },
        methods:{
            send_msg (){
                // 1) 数据为空直接结束
                if (!this.msg_val) return;

                // 2)数据添加到留言数组中
                // this.msg.push(this.msg_val); // 尾增
                this.msg.unshift(this.msg_val);  //首增

                // 3)清空输入框
                this.msg_val=''
            },
            del_msg (index){
                // this.msg.splice(index, count,arg); // 从第几位开始,操作多少位,可变长的新数据
                // count:0   新增 arg
                // count:1,2 修改 成arg
                // arg:0  删除
                this.msg.splice(index, 1)
            }
        }
    })
</script>
</html>
View Code

    

  5. 文本相关指令:v-text  v-html  v-once  ==>三者后面绑定的都是变量名,【加引号就是普通字符串】    变量名必须在data中定义

   {{ msg }}  插值表达式  相当于是标签的text,  必须由Vue实例的data提供, 否则报not defined

    

  补充:差值表达式与后台模板语言冲突问题?【前后台不分离时,如由django的试图函数加载,导致前后台数据加载冲突】

  解决方式:符号格式化, 非delimiters中的符号不会识别,会以普通字符串处理

 delimiters:['[{', '}]']  |   delimiters:[ '${',   '}$' ]
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <!--不是delimiters定义的符号,不会被识别-->
    {{msg}}  
    
    <!--会被vue识别-->
    <p>[{ msg }]</p>

</div>
</body>
<script src="js/vue.min.js"></script>
<script>
    new Vue({
        el:'#app',
        data:{
            msg:"信息"
        },
        delimiters:['[{', '}]']
    })
</script>
</html>
View Code

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

   v-text:

      <p v-text='msg'>原文本</p>       原文本会被msg替换 ,就是文本

      <p v-text='"msg"'>123</p>   加引号就是普通字符串

    v- html : 

     可以解析标签,非标签就解析为字符串,原文本会被变量替换

     <p v-html="htmlMsg" @click="changeMsg">1230000</p>
        methods:{
changeMsg:function () {
this.htmlMsg = "<i>htmlMsg被点击后的</i>"
}
}

  v-once:

     默认为初始值,不会被改变

    <p v-once="htmlMsg">{{htmlMsg}}</p> 

 四、前台数据库  存取支持点或[ ] 语法   

  window.localStorage;  //永久存储仓库【基于服务器的】
  window.sessionStorage //临时存储仓库 【浏览器关闭,数据就消失】
  Cookies 有过期时间的存储仓库
  
  localStorage
  存: localStorage['name'] = 'owen'  
     localStorage.name = 'owen'  

  取  localStorage.name

   清空   localStorage.clear()

  sessionStorage
  存  window.sessionStorage.name ='egon'
  取  console.log(window.sessionStorage['name'])
  清空  sessionStorage.clear()

优化todolist: 

1.  数据库中有值就存入,没有值就创建一个空数组, 数据库中数据存入默认是以字符串形式存入,所以要将字符串split为数组

  msg: localStorage.msg ? localStorage.msg.split(',') :[],

2. 数据删除后,需同步到数据库

localStorage.msg = this.msg;

 更新后代码:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>todolist</title>
    <style>
        li:hover{
            cursor:pointer;
            color: red;

        }
    </style>
</head>
<body>
<div id="app">
    <input type="text" v-model="msg_val" >
    <button @click="send_msg">留言</button>


    <ul>
        <li v-for="(v, i) in msg"  @click="del_msg">{{v}}</li>
    </ul>
</div>
</body>
<script src="js/vue.min.js"></script>
<script>
    new Vue({
        el:"#app",
        data:{
        // msg:['第一条', '第二条'],
         msg: localStorage.msg ? localStorage.msg.split(',') :[],
        msg_val:""
        },
        methods:{
            send_msg (){
                // 1) 数据为空直接结束
                if (!this.msg_val) return;

                // 2)数据添加到留言数组中
                // this.msg.push(this.msg_val); // 尾增
                this.msg.unshift(this.msg_val);  //首增

                //同步到数据库
                localStorage.msg = this.msg;

                // 3)清空输入框
                this.msg_val=''
            },
            del_msg (index){
                // this.msg.splice(index, count,arg); // 从第几位开始,操作多少位,可变长的新数据
                // count:0   新增 arg
                // count:1,2 修改 成arg
                // arg:0  删除
                this.msg.splice(index, 1);

                // 删除后同步到数据库
                localStorage.msg = this.msg;
            }
        }
    })
</script>
</html>
View Code

五、组件  【每个组件均由 html模板、css样式、js逻辑组成】、根组件 |  局部组件  |   全局组件

  根组件:new Vue({})   |  el作为template  |    data 直接绑定{}

  局部组件与全局组件:只有一个根标签  |   必须明确自己的  html(template)、css、js  |     data是一个函数,函数的返回值是{}

  局部组件:let localTag = {template:``, data (){ return {}}, methods:{ func(){}}, }   |   必须在父组件注册才能使用  |  js驼峰对应的-链接语法

  全局组件:Vue.component(' ', {相当于是一个局部组件})    |   无需注册  |   js驼峰对应的-链接语法

  1.一个new Vue创建的是vue实例,一个实例就是一个vue组件

  2. new 定义的对象实例称之为根组件【实际开发中一个页面只有一个根组件】

  3. 两个根组件之间数据的是相互隔离的,可以将new出来的实力赋值给变量,然后利用原生的js来处理,

      template:··      抄写真实DOM: 用引号包裹,【样式、事件逻辑都一样可以包含】

   注:挂载点是必须的(作为虚拟DOM渲染替换的依据),挂载点可以读取挂载点的内容及所有结构,作为根组件自己的template,所以根组件无需书写template。

    挂载点为什么是必须的? 即使有了自己的template,还是需要指定替换页面中的哪个部分。

    相当于:Vue组件将挂载点的内容读到内存中,然后加载自己的数据,加载完后再用组件的虚拟DOM替换挂载点对应的真实DOM

    结论:1.挂载点是必须的,作为虚拟DOM渲染替换的依据。

       2.挂载点读取挂载点中的内容及结构可以作为组件自己的template, 所以template不是必须的。

  案例

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Title</title>
</head>
<body>
<div id="app01">
    {{msg}}
</div>

<div id="app02">
    {{msg}}
</div>



</body>
<script src="js/vue.min.js"></script>
<script>
    let app01 = new Vue({
        el:'#app01',
        data:{
            msg:"我是app01msg",
            c:'red',  // template中的C
        },
        // template:'<ul>{{msg}}</ul>'  //替换挂载点对应的真实DOM
        template:`
        <div id="app01" :style="{color: c}" @click="action">
            {{msg}}
        </div>
        ` , //抄写真实DOM:用引号包裹,
        methods:{
            action (){
                alert(this.msg)
            }
        }

    });






    let app02 = new Vue({
        el:'#app02',
        data:{
            msg:"我是app02msg"
        }
    });
    // console.log(app01.msg)

    // app01.msg = app02.msg
    //根组件间通过原生js在外组件外界进行通信

</script>
</html>
View Code

   4. 根组件内部可以注册使用n个子组件, 子组件必须拥有自己的  html模板、css样式、js逻辑。

   5. 创建局部组件  => 在根组件中注册  =>  解析{} 中的vue语法  => 组件形成

    注:new出来的就是根组件, 定义一个对象【 let  box= {...}】 局部组件

      Vue中取名建议小驼峰,html标签中标签名忽略大小写,都会默认成小写,这样Vue中的名字与HTML就对不上了【例】:

        错误的:  Vue中的                                  html

        components:{            <boxTag></boxTag>
            boxTag: boxTag
          }
     建议:1. 都用小写加下划线
        2. 或者js引号包裹:‘box-tag’     html:  box-tag   
        3. Vue中建议用小驼峰,Html中支技用中线隔开语法,对应着就是JS中的驼峰语法
      components中: boxTag        html中:box-Tag

6.局部组件data必须要是一个函数,return一个字典,因为每个组件必须要有一套自己的数据,【data的数据还必须是字典】
  类似闭包函数,每执行一次外部函数,内部函数就会产生一个局部名称空间

闭包案例
# 闭包案例

def outer():
    def inner():
        num=1
        return inner
    print(inner.__dict__, id(inner)) 

obj1 = outer()
obj2 = outer()

{} 2137236028272
{} 2137236028408
View Code

Veu局部组件案例

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>局部组件</title>
    <style>
        .box {
            width: 200px;
            text-align: center;
            border: 1px solid black;
            border-radius: 10px;
            overflow: hidden;
            float: left;
        }

        .box img {
            width: 100%;
        }

        .box:hover span {
            cursor: pointer;
            color: red;
        }
    </style>
</head>
<body>
<div id="app">
    <box-tag></box-tag>
    <box-tag></box-tag>
</div>
</body>
<script src="js/vue.js"></script>
<script>
    let boxTag = {  //局部组件
        //html模板
        template: `
         <div class="box">

        <img src="img/333.jpg" alt="">
        <p>
        <span @click="btnClick">点击了下{{ num }}</span>
        </p>
        <p>美人</p>
    </div>
        `,
        data() {  // 组件执行一次就会产生一个局部名称空间,来存放自己的一套数据
            return {
                num:0
            }
        },
        methods: {
            btnClick() {
                this.num++
            }
        }
    };


    new Vue({
        el: '#app',
        components: {
            // 'box-tag': boxTag
            boxTag,
        }

    })
</script>

</html>
View Code

六、组件通信

  1. 父传子,数据在父组件 => 父组件模板写子组件标签  =>子组件标签自定义属性绑定数据变量

     父组件提供数据  |      子组件通props绑定属性  |   子组件拿到属性就拿到父组件的变量值, props中可以看成是一个反射,可以直接拿到对应的变量值

    父传子案例一:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>父传子</title>
</head>
<body>
<div id="app">
    <sub-tag :a="msg" ></sub-tag>
    <!--<sub-tag></sub-tag>-->
</div>
</body>
<script src="js/vue.js"></script>

<script>
    let subTag ={
        //子组件通过实例成员props获取自身自定义属性,通过插值表达式反射拿到对应的变量的值
        props:['a'],
        template:`
        <div>
            <h1>{{ a }}</h1>
        </div>

        `,
        // data (){
            // return {
                // msg:'123'  //该数据必须由父组传进来,不可以写死
            // }
        // },
    };

    new Vue({
        el:'#app',
        components:{
            subTag,
        },
        data:{
            msg:"父级数据"
        },
    })

</script>

</html>
View Code

    

    父传子案例二:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Title</title>
    <style>
        .box{
            width: 200px;
            border-radius: 10px;
            border: 2px solid black;
            text-align: center;
            float: left;
            overflow: hidden;
        }
        .box img{
            width: 100%;

        }
        .box:hover {
            cursor: pointer;
            color: red;
        }
    </style>
</head>
<body>
    <div id="app">
        <sub-tag v-for="box_obj in boxTag" :box-tag="box_obj"></sub-tag>
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    let subTag = {
        props:['boxTag'],
        template:`
        <div class="box">
            <img :src="boxTag.img_url" alt="">
            <span @click="action">点了{{num}}下</span>
            <p>
            <span>{{ boxTag.img_title}}</span>

            </p>
        </div>>

        `,
        data (){
            return {
                num:0
            }
        },
        methods:{
            action (){
                this.num ++
            },
        },
    };
    let back_data = [
        { img_url:'img/222.jpg',
          img_title:'美1'},
        {img_url:'img/333.jpg',
          img_title:'美2'},
        {img_url:'img/444.jpg',
          img_title:'美3'},
    ];


    new Vue({
        el:'#app',
        components:{
            subTag,
        },
        data:{
            boxTag:back_data,
        },
    })
</script>
</html>
View Code

  2. 子传父, 数据在子组件 =>  父组件模板写子组件标签 => 子组件内部通过事件发送数据给外部,子组件与父组件链接的桥梁子组件标签

    子组件提供数据  |    子组件 $emit('自定义事件', 数据们)  |  父组件模板中的子组件标签绑定自定义事件  |   自定义事件的方法由父组件实现  |  实现的方法的参数就是子组件的数据 

    @send_pag2 子组件的自定义事件   recv_page2  父组件的变量事件

    <view-tag v-if="page == 'tag1'"  @send_pag2="recv_page2"></view-tag>
  子传父案例:
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>父子组件</title>
    <style>
        body, h1{
            margin: 0;
        }
    </style>
    <style>
        .header_tag{
            height: 120px;
            background-color: orange;
        }
        .body{
            height: 800px;
            background-color: papayawhip;
        }
        .footer{
            height: 120px;
            background-color: cyan;
        }
        span:hover{
            cursor: pointer;
            color: red;

        }
    </style>
</head>
<body>
<div id="app">
    <view-tag v-if="page == 'tag1'"  @send_pag2="recv_page2"></view-tag>
    <view-tag2 v-else-if="page == 'tag2'" @send_pag2="recv_page2"></view-tag2>

</div>
</body>
<script src="js/vue.js"></script>
<script>
    let headerTag ={
         template:`

        <div class="header_tag">
            <h1 style="text-align: center; line-height: 80px"></h1>
            <span @click="changPage('tag1')" >免费</span>
            &nbsp;&nbsp;&nbsp;&nbsp;
            <span @click="changPage('tag2')" >轻课</span>
        </div>
    `,
        methods:{
             changPage (page) {
                this.$emit('send_data', page)
             },
        },
    };

    let footerTag ={
        template:`
          <div class="footer">
            <h1 style="text-align: center; line-height: 120px"></h1>
           </div>
        `,
    };



    let viewTag = {
    template:`
    <div>
        <header-tag @send_data="rev_sub"></header-tag>
        <div class="body" style="background-color: green"></div>
       <footer-tag></footer-tag>
    </div>
    `,
    components:{
        headerTag,
        footerTag,
    },
     methods:{
        rev_sub (val){
            this.$emit('send_pag2', val)
        },
     },


    };
      let viewTag2 = {
    template:`
    <div>
        <header-tag @send_data="rev_sub"></header-tag>
        <div class="body" style="background-color: blue"></div>
        <footer-tag></footer-tag>
    </div>
    `,
   components:{
        headerTag,
        footerTag,
   },
     methods:{
        rev_sub (val){
            this.$emit('send_pag2', val)
        },
     },
    };



    new Vue({
        el:'#app',
        components:{
            viewTag,
            viewTag2,
        },
        data:{
            page:'tag1'

        },
        methods:{
            recv_page2 (val){
                console.log(val);
                this.page = val;
            }
        }
    })
</script>
View Code






原文地址:https://www.cnblogs.com/qingqinxu/p/11318466.html