VUE框架(一)

一、VUE环境搭建

1.1、下载开发版本的Vue

开发版本:https://cn.vuejs.org/js/vue.js

生产版本:https://cn.vuejs.org/js/vue.min.js

1、下载完毕后引入

<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <script type="text/javascript" src="../js/vue.js"></script>
</head>

1.2、安装开发者工具

谷歌应用商店直接下载:Vue.js devtools

https://chrome.google.com/webstore/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd

安装完毕后查看:

 1.3、关闭vue在启动时生成的生产环境提示

<script type="text/javascript">
Vue.config.productionTip = false // 阻止vue在启动时生成的生产环境提示
</script>

在浏览器上检查

二、写一个 hello world

<body>

<!--准备一个容器-->
<div id="root">
    <h1>hello: {{name}},{{age}}</h1>
    <!-- {{}} 模板选择器,读取data里面的数据  -->
</div>

<script type="text/javascript">
// 阻止vue在启动时生成的生产环境提示
Vue.config.productionTip = false

// 创建Vue实例
const x = new Vue({
    el: "#root",  // 绑定id="root"的容器,值通常为css选择器字符串 (CSS里面的ID选择器)
    data:{  // data里面存储的数据,给'el'指定的容器使用
        name: "wdl",
        age:18
    }
})
</script>

</body>

# 执行结果:hello: wdl,18

2.1、总结下这个简单的代码
    1、想让Vue工作,就必须创建一个vue实例,并且传入一个配置对象(el和data)
    2、root容器的代码依然符合html规范,只不过混入了一些特殊的Vue语法
    3、root容器里的代码被称为(Vue模板)

     

三、延伸一下

3.1、在div容器内{{}}里面除了写vue的data里面的,还可以写js表达式

<body>

<!-- 容器 -->
<div id="root">
  <!-- 这里面写js表达式(a,a+b,demo(1)这种) 和 js代码(if(){},for(){}这种) -->
  <h1>1,{{name}},{{addr.toUpperCase()}},{{1 + 1}}</h1>
  <!--
  addr.toUpperCase() 字符串大写
  addr.toLowerCase() 字符串小写
  -->
</div>

<script type="text/javascript">
Vue.config.productionTip = false // 阻止vue在启动时生成的生产环境提示

// 创建Vue实例
new Vue({
    el: '#root',   // el 指定当前实例为哪个容器服务,值通常为CSS里面的选择器
    data: {        // 用于存储数据,给el指定的容器'#root'使用。
        name: 'sudada',
        addr: 'shanghai',
    },
})

</script>

</body>

# 执行结果:1,sudada,SHANGHAI,2

3.2、总结下

    1、Vue实例和容器是一一对应的。
    2、真是开发中只有一个Vue实例,并且会配合着组件一起使用。
    3、一旦data中的数据发生改变,那么模板中用到改数据的地方也会自动更新。
    4、{{xxx}}中的xxx要写js表达式,且xxx可以自动读取到data中的所有属性

四、模板语法

4.1、插值语法和指令语法(v-xxx)


<body>
  <div id="root">
    <h1>插值语法</h1>
    <!--
    插值语法:一般用于解析标签体内容
    -->
    <h3>hello,{{name}}</h3>
  
    <h1>指令语法</h1>
    <!--
    指令语法:一般用于解析标签(格式为:v-xxx)
    -->
    <h1>奥术{{name}}大师</h1>
    <a :href="url">百度</a>
    <a :href="school.url">点我去学校{{school.name}}学习</a>
  </div>

</body>

<script type="text/javascript">
  Vue.config.productionTip = false
  
  new Vue ({
    el:'#root',
    data:{
        name:'jack',
        url:'http://www.baidu.com',
        school:{
            name:"sudada",
            url:'http://www.sougou.com'
        }
    }
  })
</script>

4.2、总结插值语法和指令语法

  1、插值语法:一般用于解析"标签体"内容(<h1>xxx</h1>,这个标签了里面的"xxx"就是标签体)
    写法:{{xxxx}},xxxx是js表达式,且可以直接读取到data中的所有属性
  2、指令语法:格式为 "v-xxx" 一般用于解析"标签" (包含标签属性,标签内容,绑定事件等)(<a :href="school.url" x="hello">,这里面的":href"和x="hello"就是标签属性 )
    写法:v-bind:href="xxx" 简写为 :href="xxx","xxx"会被当做js表达式执行,可以直接读取到data中的所有属性。

五、数据绑定

5.1、单向、双向数据绑定

<body>
  <div id="root">
    <h1>{{name}}</h1>
    单向数据绑定: <input type="text" :value="name"><br>
    双向数据绑定: <input type="text" v-model="name"><br>
    <!--错误代码示例,如下,因为v-model只能应用在"表单"类元素(输入类元素,如上)-->
    <h2 v-model:x="name">hello</h2>
  </div>
</body>

<script type="text/javascript">
  Vue.config.productionTip = false
  new Vue({
    el:"#root",
    data:{
      name:"wdl",
      input_value:"xxx"
    }
  })
</script>

5.2、单向、双向数据绑定总结

  单向数据绑定(只针对表单input输入类,input输入的值就是value):v-bind:value="name",里面的'value'会去读"name"的值,当修改'value'的值时,"name"的值不会改变。只能读不能改
  双向数据绑定(只针对表单input输入类,input输入的值就是value):v-model:value="name",里面的'value'会去读"name"的值,当修改'value'的值时,"name"的值也会跟着改变。可读可改写。
    v-model:value 可以简写为:v-model,因为v-model默认收集的就是value值。
  数据绑定简写:
      单向数据绑定: <input type="text" :value="name"><br>
      双向数据绑定: <input type="text" v-model="name"><br>

六、el和data的两种写法

<body>

<div id="root">
  <h1>hello,{{name}}</h1>
</div>

<script type="text/javascript">
  // 一、el 的2种写法(2种方式皆可正常使用)
  // el 方法:把vue实例对象绑定(挂载)到容器(定义时就指定绑定哪个容器 )
  new Vue({
      el:"#root",
      data:{
          name:"111",
      }
  })
  // $mount 方法:把vue实例对象,绑定(挂载)到容器(最后在指定绑定哪个容器)
  const v = new Vue({
      data:{
          name:"222",
      }
  })
  console.log(v)
  v.$mount("#root")

  // 二、data 的2种写法
  new Vue({
      el: "#root",
      // data的第一种写法:对象式
      data: {
          name: "sudada",
      },
      // data的第二种写法:函数式(不能写成"=>"函数。data函数必须要返回一个数据,这个返回的数据,就是容器内用到的数据。比如容器内用的是name,那么这里就要return一个name)
      data(){                 // 普通函数,原生写法:data:function
          console.log(this)   // 此处的this是vue实例对象(这里的this就等于"const v = new Vue"的v)
          return{
            name: "szq"
          }
      }
  })
</script>

七、MVVM模型

7.1、MVVM模型图解

MVVM模型:
  1、M:模型(Model):data中的数据
  2、V: 视图(View):页面模板(DOM)
  3、VM:视图模型(ViewModel):Vue实例,简称vm
观察发现:
  1、data对象中的所有属性(值),最后都出现在了vm身上。(可以通过vm.xxx拿到data对象里面xxx的值)
  2、vm身上的所有属性以及Vue原型上所有属性,在Vue模板中都可以直接使用。(vm 这个变量名就表示了Vue实例对象)

 7.2、用法说明

<body>
<!-- View 模型 -->
  <div id="root">
    <h1>学校:{{name}}</h1>
    <h1>地址:{{addr}}</h1>
    <h1>1:{{$options}}</h1>
    <!-- $options:vm身上的属性,这里直接可以调用(仅做测试,目的是证明"模板"里面可以直接调用vm的所有属性) -->
  </div>
</body>

<script type="text/javascript">
  Vue.config.productionTip = false
  // ViewModel模型,简称vm(vm 这个变量名就表示了Vue实例对象)
  const vm = new Vue({
      el:"#root",
      // Model 模型
      data:{
          name:"sudada",
          addr:"shanghai",
      }
  })
  console.log(vm)
  console.log(vm.name)
</script>

八、Vue中的数据代理

8.1、原理与实现

1、Vue中的数据代理:是通过vm对象中属性的操作(读/写)
2、Vue中数据代理的好处:更加方便的操作data中的数据
3、基本原理
  通过Object.defineProperty()把data对象中所有属性添加到vm上。
  为每一个添加到vm的属性,都指定一个"getter/setter"。
  在"getter/setter"内部去操作(读/写)data中对应的属性。
4、实践证明:
  console.log(vm.name):获取的是data里面name属性的值,实际上调用的是Vue的"get name"方法实现的。
  console.log(vm.name="szq"):修改的是data里面name属性的值,实际上调用的是Vue的"set name"方法实现的。
5、vm如何获取data对应的值,使用vm._data,返回的值是是一个对象。(vm._data == options.data == data)

8.2、数据代理图示 

九、事件处理

9.1、绑定事件(鼠标点击/单击时触发)

    1、绑定事件v-on:click 简写为 @click
    2、绑定事件触发的函数要写到methods里面,不建议写到data里面

<body>

<div id="root">
    <!--
    v-on:click 简写为 @click
    <button v-on:click="showinfo1">点我提示1</button>  注释:当"button"元素被click(点击)时,执行一个回调函数"showinfo1"
    -->
    <button @click="showinfo1">点我提示1(不传参)</button>

    <!--
    点击时传入一个参数:showinfo2(666)
    点击时传入一个参数:showinfo2($event,666) 保留event,需要通过"$"占位符实现,这样可以在函数内部使用event.xxx的一些功能
    -->
    <button @click="showinfo2($event,666)">点我提示2(传参)</button>
</div>

</body>

<script type="text/javascript">
    Vue.config.productionTip = false
    const vm =  new Vue({
        el:'#root',
        data:{
            name:'xxx',
            address:'sh',
        },
        // 通过methods配置项,把事件的回调函数放到这里面。
        methods:{
            // showinfo1 函数可以传递对象,默认对象式event
                // event:事件对象(点击按钮后,默认提供)
                    // 可以通过event.target拿到目标("button"按钮)
                // 函数内的打印this, 拿到的就是vm(Vue实例对象)
            // 所有被vue管理的函数最好都写成普通函数,尽量不写箭头函数
            showinfo1(event){
                console.log(event.target)
                console.log(this)
                alert('点我提示1')
            },
            showinfo2(event,number){
                console.log(event.target)
                console.log(number)
                alert('点我提示2')
            },
        }
    })
</script>

9.2.1、绑定事件总结

  1、使用v-on:xxx 或者 @xxx 绑定事件,其中"xxx"是事件名
  2、事件的回调需要配置在methods对象中,最终会在vm上
  3、methods配置的函数,不需要用箭头函数,否则this就不是vm了
  4、methods配置的函数,都是被Vue所管理的函数,this的指向是vm或者组件实例对象
  5、@click="showInfo1" 和 @click="showInfo2($event,66)"效果一样,但是后者可以传参。

9.2、事件的修饰符

  事件修饰符可以连着写:@click.prevent.stop  先阻止默认事件,再阻止事件冒泡

  1、@click.prevent 阻止默认事件(常用)
  2、@click.stop 阻止事件冒泡(常用)
  3、@click.once 事件只触发一次(常用)

  4、@click.capture 使用事件的捕捉模式
  5、@click.self 只有event.target是当前操作的元素时才触发时间
  6、@click.passive 事件的默认行为立即执行,无需等待事件回调执行完毕

9.2.1、事件处理是先捕获,在冒泡。
  捕获阶段:由外往内
  冒泡阶段:由内往外

9.2.2、代码示例


<body>

<style>
    /* 通配符,所有元素之间都有20px的间距*/
    *{
        margin-top:20px;
    }
    .demo1{
        width: 115px;
        height: 110px;
        float: left;
        margin: 7px;
        background-color: red;
    }
    .box1{
        padding: 5px;
        background-color: aqua;
    }
    .box2{
        padding: 5px;
        background-color: rosybrown;
    }
</style>

<div id="root">
    <!-- 常用
    @click.prevent(事件修饰符): 阻止默认行为,也就是点击后,只有弹窗,没有a标签的URL跳转
    -->
    <a href="https://www.baidu.com" @click.prevent="showinfo">点我跳转</a>

    <!-- 常用
    @click.stop:阻止事件冒泡,也就是点击后只触发一次alert提示。否则会有多次alert提示
    -->
    <div class="demo1" @click="showinfo">
        <!-- 这里加@click.stop之后,里面的button被点击时就不会触发"alert" -->
        <button @click.stop="showinfo">点我提示2</button>
    </div>

    <!-- 常用
    @click.once:事件只触发一次alert提示,下次点击就不会在触发alert提示了。
    -->
    <button @click.once="showinfo">点我提示3</button>

    <!-- 不常用 @click.capture:使用事件的捕捉模式-->
    <div class="box1" @click.capture="showmsg(1)">
        div1
        <div class="box2" @click="showmsg(2)">
            div2
        </div>
    </div>

    <!-- 不常用 @click.self:只有event.target是当前操作的元素时才触发时间-->
    <div class="demo1" @click.self="showinfo">
        <button @click="showinfo">点我提示4</button>
    </div>

</div>

</body>

<script type="text/javascript">
    Vue.config.productionTip = false
    new Vue({
        el:"#root",
        data:{
            name:"sudada",
            addr:"shanghai",
        },
        methods:{
            showinfo(e){
                // e.preventDefault();   // 阻止默认行为,需要在函数内接收参数"e"
                // e.stopPropagation();  // 阻止事件冒泡,需要在函数内接收参数"e"
                alert("同学你好")
            },
            showmsg(msg){
                console.log(msg)
            }
        }
    })
</script>

9.3、键盘事件

9.3.1、总结键盘事件

    keyup:任意键盘"按下去然后松手"就会触发
    keydown:任意键盘"按下去"就会触发

1)、Vue常见的按键别名:
        回车键:@keyup.enter
        删除键:@keyup.delete(退格键和delete键都能触发)
        退出键:@keyup.esc
        空格键:@keyup.space
        换行键:@keyup.tab(这个键比较特殊,需要使用:@keydown.tab,使用@keyup.tab会和"tab键"本身的功能有冲突)
        上键:@keyup.up
        下键:@keyup.down
        左键:@keyup.left
        右键:@keyup.right

2)、系统修饰键(特殊用法):@keyup.ctrl,@keyup.alt,@keyup.shift,@keyup.meta
        配合@keydown使用:正常触发
        配合@keyup使用:按下修饰键的同时,在按下其他键,随后释放其他键,时间才会触发。

9.3.2、键盘事件示例

<body>

<div id="root">
    <h1>hello,{{name}}</h1>

    <!--
    keyup:任意键盘"按下去然后松手"就会触发
    keydown:任意键盘"按下去"就会触发

    Vue常见的按键别名:
        回车键:@keyup.enter
        删除键:@keyup.delete(退格键和delete键都能触发)
        退出键:@keyup.esc
        空格键:@keyup.space
        换行键:@keyup.tab(这个键比较特殊,需要使用:@keydown.tab,使用@keyup.tab会和"tab键"本身的功能有冲突)
        上键:@keyup.up
        下键:@keyup.down
        左键:@keyup.left
        右键:@keyup.right

    系统修饰键(特殊用法):@keyup.ctrl,@keyup.alt,@keyup.shift,@keyup.meta
        配合@keydown使用:正常触发
        配合@keyup使用:按下修饰键的同时,在按下其他键,随后释放其他键,时间才会触发。
    -->

    <!--
    @keyup.enter:在input框内输入内容,只有按下"回车"键后,才能拿到input框内所有的内容。
    如果写成@keyup="showinfo",那么输入一行就拿到一行,拿到的内容就不完整(有多余的)
  -->
    <input type="text" @keydown.tab="showinfo">
</div>

</body>

<script type="text/javascript">
    Vue.config.productionTip = false
    const vm = new Vue({
        el:"#root",
        data:{
            name:"szq"
        },
        methods:{
            showinfo(e){
                // e 就是event,默认传递的事件对象
                // e.target.value 拿到的就是input框内输入的值
                console.log(e.target.value)
            }
        }
    })
</script>

十、计算属性

什么是属性 Property ?

data(对象) 里面定义的值,都是属性,都可以使用 {属性 }} 直接解析到 属性的值

        
data:{
     firstname:"苏",
     lastname:"三",
},

什么是方法 method ?

fullname 这个函数就是一个方法,可以使用 {fullname() }} 直接拿到 方法的返回值

methods:{
    fullname(){
        return this.firstname + "-" + this.lastname
    }
}

10.1、什么是计算属性?

计算属性是单独定义的属性(格式和data一样),是一个全新的配置项 "computed"。

计算属性总结:先拿到现有的属性(a,b),然后做一次加工(a+b),最后生成一个全新的属性(a+b=c,c这个属性就是计算属性)
1、定义:要用的属性c不存在,要通过"已有的属性a,b","计算a+b=c"得来的。
2、原理:底层借助了Object.defineproperty方法提供getter和setter。
3、get函数什么时候执行?(计算属性什么时候执行?
  初次读取时会执行一次;
  当计算属性内"任何一个被依赖的数据"发生"改变"时,计算属性会被再次执行。

4、优势:与methods实现相比,内部有"缓存机制(可以复用)",效率更高,调试方便。
5、备注:
  计算属性最终会出现在vm上,直接读取使用即可:this.xxx。
  如果计算属性要被修改,那必须写"set函数"去响应修改,且"set函数"要对原属性a或者b的值做修改,修改的值就是"set函数"传入的值。

10.2、代码示例

<body>
<div id="root">
    姓:<input type="text" v-model="firstname"> <br>
    名:<input type="text" v-model="lastname"> <br>
    全名: <span>{{fullname}}</span>
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false
    const vm = new Vue({
        el:"#root",
        data:{
            firstname:"su",
            lastname:"dada",
        },

        // 计算属性 computed
        computed:{
            // 把计算过程配置成一个对象
            fullname:{
                // 读fullname时,执行get函数,并返回值
                // get什么时候调用?
                 // 1.初次读取fullname时
                 // 2.所依赖的数据(this.firstname或者this.lastname)发生变化时。
                get(){
                    console.log('get被调用')
                    return this.firstname + "-" + this.lastname
                },
                // 当fullname被修改时,那么执行set函数
                // value 就是被修改后收到的值,比如把 fullname="张-三"修改为 fullname="李-四",那么"value"的值就是"李-四"
                set(value){
                    console.log('set被调用', value)
                    // 把收到的value的值,做拆分
                    const arr = value.split('-')
                    // 姓就是数组的第一个值
                    this.firstname = arr[0]
                    // 名就是数组的第二个值
                    this.lastname = arr[1]
                }
            }
        }
    })
</script>

10.3、计算属性简写(只有在不写set的情况下才能使用简写方式,如果有set的话,不能简写。)

<body>

<div id="root">
  姓:<input type="text" v-model="firstname"> <br>
  名:<input type="text" v-model="lastname"> <br>
  全名: <span>{{fullname}}</span>
</div>

</body>

<script type="text/javascript">
Vue.config.productionTip = false
const vm = new Vue({
    el:"#root",
    data:{
        firstname:"su",
        lastname:"dada",
    },
    // 计算属性 computed
    computed:{
      // 这里的函数"fullname",就是计算属性的名称,这个函数和"getter函数"写法一致。
      fullname(){
          console.log("get发生了调用")
          return this.firstname + '-' + this.lastname
      }
    }
})
</script>

十一、监视属性

 11.1、监视属性watch总结
  1、当"被监视"属性发生变化时,"回调函数handler"自动调用,进行相关操作
  2、"被监视"属性必须存在,才能进行监视
  3、监视属性的2种写法:
    1. new Vue 时传入watch配置
    2. 通过 vm.$watch 监视

11.2、监视属性,代码示例

<body>
<div id="root">
  <h2>今天天气很{{info}}</h2>
  <button @click="changeweather">切换天气</button>
</div>
</body>

<script type="text/javascript">
  Vue.config.productionTip = false
  const vm = new Vue({
      el:"#root",
      data:{
          isHot: true,
      },
      computed:{
          info(){
              return this.isHot ? "炎热" : "凉爽"
          }
      },
      methods:{
          changeweather(){
              this.isHot = !this.isHot
          }
      },
      
      // 监视方法一(2选1):
      watch:{
          // 使用watch方法,监测一个数据,这里是"isHot"
          isHot:{
              // 初始化时让handler调用一下。
              immediate:true,

              // 当 isHot 发生改变时,handler被调用。
              // oldValue 修改前的值
              // newValue 修改后的值
              handler(newValue,oldValue){
                console.log("isHot被修改了",newValue,oldValue)
              },
          }
      }
  })

  // 监视方法二(2选1):
  // vm.$watch("isHot",{
  //     immediate:true,
  //     handler(newValue,oldValue){
  //         console.log("isHot被修改了",newValue,oldValue)
  //     },
  // })
</script>

11.3、深度监视(举例说明)
    1.Vue中的watch默认不监测"对象内部值"的改变   (详见:11.3.1)

    2.配置的"deep:true"可以监测"对象内部值"改变     (详见:11.3.2)

    3.备注:
        1.Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以。
        2.使用watch时可以根据数据的具体结构,决定是否采用深度监视(deep:true)。

11.3.1、Vue中的watch默认不监测"对象内部值"的改变

例子1:当numbers属性值是numbers:{a=1,b=2},numbers.a发生改变时,watch是不监测的,handler函数不会执行

<body>
<div id="root">
    <h3>a的值是:{{numbers.a}}</h3>
    <button @click=numbers.a++>点我a++</button>
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false
    const vm = new Vue({
        el:"#root",
        data:{
            numbers:{
                a:1
            }
        },
        watch:{
            // 使用watch方法,监测numbers属性
            numbers:{
                handler(newValue,oldValue){
                    console.log("numbers被修改了",newValue,oldValue)
                }
            }
        }
    })

</script>

例子2:当numbers属性值是numbers:true,此时当numbers的值发生改变(numbers=false)时,watch是监测的,handler函数会执行

<body>
<div id="root">
    <h3>a的值是:{{numbers}}</h3>
    <button @click=numbers=!numbers>点我修改a</button>
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false
    const vm = new Vue({
        el:"#root",
        data:{
            numbers:true
        },
        watch:{
            // 使用watch方法,监测numbers属性
            numbers:{
                handler(newValue,oldValue){
                    console.log("numbers被修改了",newValue,oldValue)
                }
            }
        }
    })

</script>

11.3.2、配置"deep:true"时,watch可以监测"对象内部值"改变

当numbers属性值是numbers:{a=1,b=2},numbers.a发生改变时,watch是监测的,handler函数会执行

<body>
<div id="root">
    <h3>a的值是:{{numbers.a}}</h3>
    <button @click=numbers.a++>点我a++</button>
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false
    const vm = new Vue({
        el:"#root",
        data:{
            numbers: {
                a:1,
                b:2
            }
        },
        watch:{
            // 使用watch方法,监测numbers属性
            numbers:{
                deep:true,
                handler(newValue,oldValue){
                    console.log("numbers被修改了",newValue,oldValue)
                }
            }
        }
    })
</script>

11.3.3、watch监视多级结构中"某个属性"的变化

当numbers属性值是numbers:{a=1,b=2}numbers.a发生改变时,或者numbers.b发生改变时,watch是能监测到的,handler函数会执行

<body>
<div id="root">
    <h3>a的值是:{{numbers.a}}</h3>
    <button @click=numbers.a++>点我a++</button>
    <hr/>
    <h3>b的值是:{{numbers.b}}</h3>
    <button @click=numbers.b++>点我b++</button>
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false
    const vm = new Vue({
        el:"#root",
        data:{
            numbers: {
                a:1,
                b:2
            }
        },
        watch:{
            // 监视多级结构中某个属性的变化,这里监视的是"numbers.a"
            "numbers.a":{
                handler(newValue,oldValue){
                    console.log("numbers.a被修改了",newValue,oldValue)
                },
            },
            // 监视多级结构中某个属性的变化,这里监视的是"numbers.b"
            "numbers.b":{
                handler(newValue,oldValue){
                    console.log("numbers.b被修改了",newValue,oldValue)
                },
            },
        }
    })
</script>

11.4、监视属性的简写(当对象里面只有 handler 时,就可以使用简写了。就不能配置 "immediate:true" 和 "deep:true")

<body>
<div id="root">
    <h3>a的值是:{{numbers}}</h3>
    <button @click=numbers=!numbers>点我修改a</button>
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false
    const vm = new Vue({
        el:"#root",
        data:{
            numbers: true
        },
        watch:{
            // 简写:当对象里面只有 handler 时,就可以使用简写了。就不能配置 "immediate:true" 和 "deep:true"
            numbers(newValue,oldValue){
                console.log("numbers被修改了",newValue,oldValue)
            }
        }
    })
  // 简写:就不能配置 "immediate:true" 和 "deep:true"
  // vm.$watch("isHot",function (newValue,oldValue){
  //     console.log("isHot被修改了",newValue,oldValue)
  // })
</script>

11.5、计算属性和监视属性的区分

computed和watch的区别:
  1.computed能完成的功能,watch都可以完成,
  2.watch能完成的功能,computed不一定能完成,比如watch可以进行异步操作
2个重要的小原则:
  1.所有被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或者 实例对象
  2.所有不被Vue管理的函数(定时器的回调函数,ajax的回调函数等),最好写成箭头函数,这样this的指向才是vm 或 组件实例对象。

十二、绑定样式(不变的样式写死,变化的样式使用":class"动态绑定)

12.1、绑定样式写法说明

  1.class 样式(常用)
    写法::class="xxx",xxx可以是字符串,对象,数组
      字符串写法,适用于:样式的类名不确定,需要动态指定。
      数组写法,适用于:要绑定的样式个数不确定,名字也不确定。
      对象写法,适用于:要绑定的样式个数确定,名字也确定,但要动态决定是否使用。
  2.style 样式(不常用)
    :style="{fontSize: xxx}" 其中xxx是动态值。
    :style="xxx"  其中xxx是样式对象。

12.2、绑定样式例子

<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <script type="text/javascript" src="../js/vue.js"></script>

  <style>
      .normal{
          color: red;
          font-size: 15px;
          margin-left: 25px;
      }
      .happy {
        color: yellow;
        font-size: 10px;
        text-decoration: line-through;
        margin-left: 10px;
      }
      .nohappy{
        color: green;
        font-size: 10px;
        text-decoration: line-through;
        margin-left: 10px;
      }
  </style>
</head>

<body>
<div id="root">
  <!--  绑定class样式,字符串写法,适用于:样式的类名不确定,需要动态指定。-->
  <div class=normal :class=mood @click=changemood>{{name}}</div>  <br/>

  <!--  绑定class样式,数组写法,适用于:要绑定的样式个数不确定,名字也不确定-->
  <div class=normal :class=classarr @click=changemood>{{name}}</div>  <br/>

  <!--  绑定class样式,对象写法,适用于:要绑定的样式个数确定,名字也确定,但要动态决定是否使用-->
  <div class=normal :class=classobj> {{name}} </div>  <br/>

  <!--  绑定style样式,对象写法-->
  <div class=normal :style=styleobj> {{name}} </div>  <br/>
</div>
</body>

<script type="text/javascript">
  Vue.config.productionTip = false
   const vm = new Vue({
      el:"#root",
      data:{
          name:"sudada",
          // 字符串写法
          mood:"normal",
          // 数组写法
          classarr:["nohappy","happy"],
          // 对象写法
          classobj:{
              normal:false,  // 为false默认不使用, 为true时使用
              happy:true
          },
          // 绑定style样式,对象写法
          styleobj:{
              fontSize:"40px",   // fontSize 为固定写法,是font-size的意思(显示字体大小的格式)
              color:"yellow",    // 字体颜色(单个字段)
          }
      },
      methods:{
          // 字符串写法例子
          changemood(){
              this.mood = "happy"
          },
      }
  })
</script>

十三、列表渲染(符合某些条件,做对应的渲染)

13.1、v-show使用

    写法:v-show="表达式"
    适用于:切换频率的场景
    特点:不展示的dom元素未被移出,仅仅是是使用样式隐藏掉。

<body>
<div id="root">
  <!--  v-show="false/true",为true时展示<div>,为false时不展示<div>
  v-show条件渲染:页面的显示与隐藏(结构还在)-->
  <div v-show="false">hello,{{name}}</div>

  <h2>当前的n值是{{n}}</h2>
  <button @click="n++">点我n+1</button>

  <!--  // 频率高的用v-show-->
  <div v-show="n===1">v-show显示111</div>
  <div v-show="n===2">v-show显示222</div>
  <div v-show="n===3">v-show显示333</div>

</div>
</body>

13.2、v-if使用

    适用于:切换频率场景
    特点:不展示dom元素,直接删除
    注意:v-if可以和v-else-if,v-else 一起使用,但要求结构不能被"打断"

<body>
<div id="root">
  <!--  // v-if="false(0)/true(1)",为true(1)时展示<div>,为false(0)时不展示<div>
   v-if条件渲染:页面的显示与隐藏(结构都不存在)-->
  <div v-if="false">hello,{{name}}</div>

  <!--  // 频率底的用v-if,还有v-else-if和v-else(后面不需要接条件)。
  这种写法不允许打断(也就是要连续,中间不写其他的任何)-->
  <div v-if="n===1">v-if显示111</div>
  <div v-else-if="n===2">v-if显示222</div>
  <div v-else-if="n===3">v-if显示333</div>
  <div v-else>v-else哈哈哈</div>

<!--  // template 只能和v-if配合使用,不能配合v-show(加了v-show的条件不会生效)-->
  <template v-if="n===1">
    <h2>111</h2>
    <h2>222</h2>
    <h2>333</h2>
  </template>
</div>
</body>

十四、列表渲染

14.1、v-for循环遍历

<body>
<div id="root">
    <h2>人员列表</h2>
    <ul>
        <!-- for循环遍历"数组"类型:(p,index) in persons,
        其中:"p"就是for循环"persons(数组类型)"的一行行数据,
        "index"就是"persons"的索引值(0,1,2,xxx),
        :key="index",绑定索引值 -->
        <li v-for="(p,index) in persons" :key="index">
            {{p.name}}-{{p.age}}
        </li>
    </ul>
    
    <ul>
        <!-- for循环遍历"对象"类型:v-for="(v,k) in car",
        其中"v"就是对象的value,
        k"就是对象的key,
        :key="k",绑定对象的key -->
        <li v-for="(v,k) in car" :key="k">
            {{v}}--{{k}}
    </ul>
    
    <ul>
        <!-- for循环遍历"字符串"类型:v-for="(s,index) in str",
        其中"s"就是字符串的一个个字符,
        "index"就是字符串的索引,
        :key="index",绑定索引值 -->
        <li v-for="(s,index) in str" :key="index">
            {{s}}--{{index}}
    </ul>
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false
    const vm = new Vue({
        el:"#root",
        data:{
            persons:[
                {id:'001',name:'zhangsan',age:19},
                {id:'002',name:'lisi',age:29},
                {id:'003',name:'wangwu',age:39},
            ],
            car:{
                name:"adA8",
                price:"80W",
                color:"black",
            },
            str:"hello"
        }
    })
</script>

14.1.1、v-for循环遍历,":key"的作用与原理

1、虚拟DOM中key的作用
  key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据"新数据"生成"新的虚拟DOM",随后Vue进行"新的虚拟DOM"与"旧的虚拟DOM"的差异比较,比较规则如下:
2、对比规则
  1.旧虚拟DOM中找到了与新虚拟DOM相同的key
    若虚拟DOM中内容没变,直接使用之前的真实DOM。
    若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM。
  2.旧虚拟DOM中未找到与新虚拟DOM相同的key
    创建新的真实DOM,随后渲染到页面
3、开发中如何选择:
  1.最好使用每行数据的"唯一标识"作为key
  2.如果不需要对数据做"逆序添加"(this.persons.unshift(p)),"逆序删除"等"破坏顺序"的操作时,使用index作为Key没有问题。

<body>
<div id="root">
    <h2>人员列表</h2>
    <ul>
        <!-- 前提:使用"this.persons.unshift(p)",在数组的"第一行"添加数据,才会出现如下情况,
                  如果使用"this.persons.push(p)",在数组的"最后一行"添加数据,那么:key="index"就没有影响 -->
        <!-- 如果不写:key="xxx",那么默认就会把v-for循环"对象"的"index"当做 :key="index" 自动传入 -->
        <li v-for="p in persons">
            {{p.name}}-{{p.age}}
            <input type="text">
        </li>

        <!-- 前提:使用"this.persons.unshift(p)",在数组的"第一行"添加数据,才会出现如下情况,
                  如果使用"this.persons.push(p)",在数组的"最后一行"添加数据,那么:key="index"就没有影响 -->
        <!-- 如果:key="index"(传入的是对象的"索引值"),那么"虚拟dom的对比算法"之后,点击按钮生成一个新数据,就会出现错位的情况 -->
        <li v-for="(p,index) in persons" :key="index">
            {{p.name}}-{{p.age}}
            <input type="text">
        </li>

        <!-- 使用"this.persons.unshift(p)" 或者 使用"this.persons.push(p)" 都不会有影响 -->
        <!-- 如果:key="p.id"(传入的是对象的"唯一值"),那么"虚拟dom的对比算法"之后,点击按钮生成一个新数据,就不会出现错位的情况 -->
        <li v-for="p in persons" :key="p.id">
            {{p.name}}-{{p.age}}
            <input type="text">
        </li>
    </ul>
    <button @click.once="add">点击添加一个人员</button>
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false
    const vm = new Vue({
        el:"#root",
        data:{
            persons:[
                {id:"001",name:"张三",age:18},
                {id:"002",name:"李四",age:28},
                {id:"003",name:"王五",age:38},
            ],
        },
        methods:{
            add(){
                const p = {id:'004',name:'老刘',age:49}
                this.persons.unshift(p)
            }
        }
    })
</script>

14.2、input框内的模糊搜索

14.2.1、计算属性实现

<body>
<div id="root">
    <h2>人员列表</h2>
    <input type="text" placeholder="请输入名字" v-model="keword">
    <!--  计算属性实现  -->
        <ul>
            <li v-for="(p,index) in filpersons" :key="index">
                {{p.name}}--{{p.age}}--{{p.sex}}
            </li>
        </ul>
</div>
</body>

<script type="text/javascript">
Vue.config.productionTip = false
const vm = new Vue({
    el:"#root",
    data: {
        keword:"",
        persons: [
            {id: "001", name: "马冬梅", age: 18, sex: "女"},
            {id: "002", name: "周冬雨", age: 28, sex: "女"},
            {id: "003", name: "周杰伦", age: 38, sex: "男"},
            {id: "004", name: "温兆伦", age: 48, sex: "男"},
        ],
    },
    // 计算属性实现
    computed:{
        filpersons(){
            return  this.persons.filter((p)=>{
                // indexOf(val) == -1 说明没匹配到,等于其他"0,1,2,xxx"表示匹配数据的索引值。
                // 这里依赖的数据是:"this.keword",也就是当"this.keword"发生改变,计算属性就会被执行。
                return  p.name.indexOf(this.keword) !== -1
            })
        },
    }
})
</script>

14.2.2、监视属性实现

<body>
<div id="root">
    <h2>人员列表</h2>
    <input type="text" placeholder="请输入名字" v-model="keword">
    <!--  监视属性实现  -->
        <ul>
            <li v-for="(p,index) in filpersons" :key="index">
                {{p.name}}--{{p.age}}--{{p.sex}}
            </li>
        </ul>
</div>
</body>

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

// 监视属性实现
const vm = new Vue({
    el:"#root",
    data: {
        keword:"",
        persons: [
            {id: "001", name: "马冬梅", age: 18, sex: "女"},
            {id: "002", name: "周冬雨", age: 28, sex: "女"},
            {id: "003", name: "周杰伦", age: 38, sex: "男"},
            {id: "004", name: "温兆伦", age: 48, sex: "男"},
        ],
        // 存放过滤后的数据
        filpersons:[]
    },
    watch:{
        // val 接收input框内输入的值
        keword:{
            // 初始化时让handler调用一下。
            immediate:true,
            handler(val){
              // filter方法:"p"就是"persons"里面的一行行数据。
              // 如果"val"的值为'空'时,使用"filter方法"就能拿到的就是"persons"里面所有的数据。
              this.filpersons = this.persons.filter((p)=>{
                    // indexOf(val) == -1 说明没匹配到,等于其他"0,1,2,xxx"表示匹配数据的索引值。
                  return  p.name.indexOf(val) !== -1
              })
          }
        },
    }
})
</script>

14.3、input框内数据排序(升降序)

<body>
<div id="root">
    <ul>
        <h2>人员搜索</h2>
        <input type="text" placeholder="输入名称" v-model="keyWord">
        <button @click="sortType=2">年龄升序</button>
        <button @click="sortType=1">年龄降序</button>
        <button @click="sortType=0">原顺序</button> <br/>

        <li v-for="(p,index) in filepersons" :key="index">
            {{p.name}}-{{p.age}}-{{p.sex}}-{{p.status}}
        </li>
    </ul>
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false
    new Vue({
        el: "#root",
        data: {
            keyWord: "",
            // 0原顺序,1降序,2升序
            sortType:0,
            persons: [
                {id:"001",name:"马冬梅",age:48,sex:"女"},
                {id:"002",name:"周冬雨",age:38,sex:"女"},
                {id:"003",name:"周杰伦",age:18,sex:"男"},
                {id:"004",name:"温兆伦",age:58,sex:"男"},
            ]
        },
        computed:{
            filepersons(){
                // 先过滤(拿到过滤后的数据arry)
                const arry = this.persons.filter((p) => {
                    return p.name.indexOf(this.keyWord) !== -1
                })
                // 然后对arry做判断是否需要排序(后排序)
                if (this.sortType){
                    // this.sortType = 1 或者 2 时,按年龄排序(升序或者降序)
                    arry.sort((a,b)=>{
                        return this.sortType === 1 ? b.age-a.age : a.age-b.age
                    })
                }
                // 如果this.sortType=0,就返回原值或者过滤后的值(无排序)
                // 如果this.sortType=1或者2,就返回原值或者过滤后的值(外加排序)
                return arry
            }
        }
    })
</script>

14.4、Vue监测数据的原理(通过Vue.set或者vm.$set)

14.4.1、例子,Vue.set:可以在"对象{}"内新增一个属性(这个属性之前是未定义的)

Vue.set:不能直接给data直接添加属性,只能给data里面的某一个对象,比如data.xxx添加属性。

<body>
<div id="root">
  <h2>姓名{{student.name}}</h2>
  <h2>年龄{{student.age}}</h2>
  <h2 v-if="student.sex">性别{{student.sex}}</h2>
  <button @click="addsex">点我添加性别属性</button>
  <ul>
    <h2>爱好</h2>
    <li v-for="(h,index) in student.hoppy" :key="index">
      {{h}}
    </li>

    <h2>朋友们</h2>
    <li v-for="(f,index) in student.friends" :key="index">
      {{f.name}}--{{f.age}}---{{f.sex}}
    </li>
  </ul>
</div>
</body>

<script type="text/javascript">
  Vue.config.productionTip = false
  const vm = new Vue({
      el:"#root",
      data:{
          name:"zzz",
          addr:"shanghai",
          student:{
              name:"sudada",
              age:18,
              hoppy:["抽烟","喝酒","烫头"],
          }
      },
      methods:{
          addsex(){
              // Vue.set:不能直接给data直接添加属性,只能给data里面的某一个对象,比如data.xxx添加属性。
              // 给data内的某一个对象添加一个"属性",添加完毕后这个"属性"就可以被调用了。以下两种方法 2选一
              // Vue.set(this.student,"sex","男")       // 方法一 (给"student"对象添加一个"sex"属性,属性值是"男")
              // Vue.set(this.student.hoppy,1,"打游戏")  // 方法一 (给"student"对象添加一个"hoppy"属性,属性值是"打游戏")
              vm.$set(this.student,"sex","男")          // 方法二 (给"student"对象添加一个"sex"属性,属性值是"男")
          }
      }
  })
</script>

14.4.2、直接对数组内的某个索引做"赋值替换",Vue是不生效的,例子如下:

直接对数组内的某个索引做"赋值替换",Vue是生效的

如果要修改数组内的某个索引对应的值(对象)的属性Vue是生效的

如果使用官方推荐的,数组的7种修改方法(push末尾行追加,pop末尾行删除,unshift首行追加,shift首行删除,splice数组内某个元素替换,sort排序,reverse反转数组)修改,Vue是生效的

<body>
<div id="root">
  <h2>姓名:{{name}}</h2>
  <h2>朋友</h2>
  <button @click="addfriend">添加一个朋友</button>
  <ul>
    <li v-for="(f,index) in friends" :key="index">
      {{f}}
    </li>
  </ul>
</div>
</body>

<script type="text/javascript">
  Vue.config.productionTip = false
  const vm = new Vue({
      el:"#root",
      data:{
        name:"szq",
        friends:[
            {name:"szq",age:28,sex:"男"},
        ]
      },
      methods:{
          addfriend(){
            // 直接对数组内的某个索引做"赋值替换",Vue是不生效的
            // this.friends[0]={name:"sudada",age:18,sex:"女"}
            // 如果要修改数组内的某个索引对应的值(对象)的属性,则可以生效
            // this.friends[0].name="sudada"
            // 如果使用官方推荐的7种方法(push末尾行追加,pop末尾行删除,unshift首行追加,shift首行删除,splice数组内某个元素替换,sort排序,reverse反转数组)修改,Vue是生效的
            this.friends.unshift({name:"wss",age:18,sex:"女"})
          }
      }
  })
</script>

14.4.3、总结Vue监视数据的原理
  1、vue会监视data中所有层次的数据

  2、如何监测对象中的数据?
    通过setter实现监视,且要在new Vue时就传入要监测的数据。
      1.对象中后追加的属性,Vue默认不做响应式处理
      2.如需给后添加 的属性做响应式,请使用如下API(2选1)
        Vue.set(target, propertyName, value)
        vm.$set(target, propertyName, value)

  3、如何监测数组中的数据?
    通过包裹数组更新元素的方式实现,本质就是做了两件事
      1.调用原生对应的方法对数组进行更新
      2.重新解析模板,进而更新页面

  4、在Vue修改"数组"中的某个元素的办法
    1.使用:push末尾行追加,pop末尾行删除,unshift首行追加,shift首行删除,splice数组内某个元素替换,sort排序,reverse反转数组
    2.Vue.set 或者 vm.$set

  5、特别注意:
    Vue.set 和 vm.$set 不能给vm或者vm的"根数据对象"(也就是data) 添加属性。

  6、代码示例

<body>
<div id="root">
    <h1>学生信息</h1>
    <button @click="student.age++">点我年龄加一</button> <br>
    <button @click="addsex">添加一个性别</button> <br>
    <button @click="student.sex='未知'">修改性别</button> <br>
    <button @click="addfriend">添加朋友</button> <br>
    <button @click="updatefirstfriendname">修改第一个朋友的名字</button> <br>
    <button @click="addhoppy">添加一个爱好</button> <br>
    <button @click="changehoppy">修改第一个爱好,开车</button> <br>
    <button @click="nosmoke">过滤掉抽烟的爱好</button> <br>

    <h2>姓名:{{student.name}}</h2>
    <h2>年龄:{{student.age}}</h2>
    <h2 v-if="student.sex">性别:{{student.sex}}</h2>
    <h2>爱好</h2>
    <ul>
        <li v-for="(h,index) in student.hoppy" :key="index">
            {{h}}
        </li>
        <h3>朋友们</h3>
        <li v-for="(f,index) in student.friends">
            {{f.name}}--{{f.age}}---{{f.sex}}
        </li>
    </ul>
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false
    const vm = new Vue({
        el:"#root",
        data:{
            student:{
                name:"sudada",
                age:18,
                hoppy:["抽烟","喝酒","烫头"],
                friends:[
                    {name:"yyy",age:18,sex:"女"},
                ]
            }
        },
        methods:{
            addsex(){
                vm.$set(this.student,'sex','男')
            },
            addfriend(){
                this.student.friends.unshift({name:"szq",age:28,sex:"男"})
            },
            updatefirstfriendname(){
                this.student.friends[0].name="张三"
            },
            addhoppy(){
                this.student.hoppy.push("打游戏")
            },
            changehoppy(){
                // 方法1:hoppy.splice(0,1,'开车') 把数组hoppy的第0个索引删掉,然后插入1个新的索引,值为"开车"。
                // this.student.hoppy.splice(0,1,'开车')
                // 方法2:把数组hoppy的第0个索引值改为'开车'
                Vue.set(this.student.hoppy,0,'开车')
            },
            nosmoke(){
                this.student.hoppy = this.student.hoppy.filter((h)=>{
                    return h !== '抽烟'
                })
            }
        }
    })
</script>

十五、收集form表单中的数据

15.1、例子

<body>
    <div id="root">
        <!-- 表达提交时(阻止默认行为"跳转页面"),触发的点击事件"demo" -->
        <form @submit.prevent="demo">
            <!-- v-model.trem:去除input框内首位输入的"空格" -->
            账号:<input type="text" v-model.trim="account"> <br>
            密码:<input type="password" v-model="password"><br>
            <!-- type="number":input框输入的值,只能是整数类型 -->
            <!-- v-model.number:Vue把收集到的值,转换为整数类型 -->
            <!-- type="number" 和 v-model.number,一般同时使用 -->
            年龄:<input type="number" v-model.number="age"><br>
            性别<br>
            <!-- name="sex":选项框只能勾选一个 -->
            <!-- value="male|female":因为使用了"v-model",而"v-model"需要绑定value,所以就单独写一个value -->
            男:<input type="radio" name="sex" v-model="sex" value="male">
            女:<input type="radio" name="sex" v-model="sex" value="female"><br>
            爱好<br>
            <!-- value="chouyan|hejiu|tangtou":同样因为使用了"v-model",而"v-model"需要绑定value,所以就单独写一个value -->
            <!-- 当type="checkbox"时(多组的勾选框),v-model="hobby"中的"hobby"需要为数组类型 -->
            抽烟:<input type="checkbox" v-model="hobby" value="chouyan" >
            喝酒:<input type="checkbox" v-model="hobby" value="hejiu">
            烫头:<input type="checkbox" v-model="hobby" value="tangtou"><br>
            所属校区:
            <select v-model="city">
                <option value="">请选择校区</option>
                <option value="beijing">北京</option>
                <option value="shanghai">上海</option>
                <option value="shenzhen">深圳</option>
                <option value="wuhan">武汉</option>
            </select><br>
            其他信息:
            <!-- v-model.lazy:等待input输入完之后,鼠标点击别处时,Vue再收集数据 -->
            <textarea v-model.lazy="other"></textarea><br>
            <!-- v-model="agree":这里只需要拿到一个"布尔值"即可(勾选是true,不勾选是false),不需要拿里面输入的内容 -->
            <input type="checkbox" v-model="agree"> 阅读并接受用户协议:<a href="http://www.baidu.com">《用户协议》</a><br>
            <button>提交</button>
        </form>
    </div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false
    const vm = new Vue({
        el:"#root",
        data:{
            account:'',
            password:'',
            age:'',
            sex:'male',
            hobby:[],
            city:'shanghai',
            other:'',
            agree:false,
        },
        methods:{
            demo(){
                console.log(this._data)
            }
        }
    })
</script>

15.2、收集form表单数据总结:

如果:input type="text/password/number" 则v-model收集的是value的值,用户输入的就是value的值。
如果:input type="radio" 则v-model收集的是value的值,且要给标签配置value值。
如果:input type="checkbox"
    1.没有配置input的value属性,那么收集的就是checked (勾选就是true 或 未勾选是false,是布尔值)
    2.配置input的value属性:
        2.1.v-model的初始值是非数组类型,那么收集的就是checked (勾选就是true 或 未勾选是false,是布尔值)
        2.2.v-model的初始值是数组类型,那么收集的就是value组成的数组(是一个数组)

v-model的三个修饰符
    1.v-model.lazy:失去焦点后在收集数据(不是事实采集数据,是输入完毕后,点击下一行时,在采集)
    2.v-model.number:输入字符串转为有效地数字
    3.v-model.trim:输入的字符串,首尾空格过滤(中间的空格不过滤)

十六、过滤器

16.1、过滤器的定义:对要显示的数据进行特定格式化后在显示(适用于一些简单逻辑的处理)

16.2、过滤器语法:
        1.注册过滤器:Vue.filter(name,callback) 或者 new Vue(filters:{})
        2.使用过滤器:{{xxx | 过滤器名}} 或 v-bind:属性 = "xxx | 过滤器名"

16.3、过滤器使用备注:
        1.过滤器也可以接收额外参数,多个过滤器也可以串联
        2.并没有改变原本的数据,是产生新的对应的数据。

16.4、例子


<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="../js/vue.js"></script>
    <script type="text/javascript" src="../js/dayjs.min.js"></script>
</head>

<body>
<div id="root">
    <h2>格式化后的时间</h2>
    <!-- 计算属性实现 -->
    <h3>现在是{{fmtTime}}</h3>
    <!-- methods实现 -->
    <h3>现在是{{getfmtTime()}}</h3>

    <!-- 过滤器实现(本质就是函数),其中timeFormater是(过滤器)函数,time作为函数的参数传递给timeFormater -->
    <h3>现在是{{time | timeFormater}}</h3>

    <!-- 过滤器传参(默认第一个参数(value)是time,第二个参数(str)是'YYYY_MM_DD') -->
    <h3>现在是{{time | timeFormater('YYYY_MM_DD')}}</h3>

    <!-- 过滤器传参(timeFormater默认第一个参数(value)是time,第二个参数(str)是'YYYY_MM_DD',然后把timeFormater函数执行后的返回值,作为参数传递给mySlice) -->
    <!-- "time"传递"timeFormater","timeFormater"传递给"mySlice",向下传递的过程 -->
    <h3>现在是{{time | timeFormater('YYYY_MM_DD') | mySlice}}</h3>
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false
    // 全局过滤器,这里的mySlice可以参考下面的局部过滤器写法对比即可。
    // Vue.filter('mySlice',function (value){
    //     return value.slice(0,4)
    // })
    new Vue({
        el:"#root",
        data:{
            time:1621561377603,
        },
        computed:{
            fmtTime(){
                return dayjs(this.time).format("YYYY年-MM月-DD日 HH:mm:ss")
            }
        },
        methods:{
            getfmtTime(){
                return dayjs(this.time).format("YYYY年-MM月-DD日 HH:mm:ss")
            }
        },
        // 局部过滤器,关键字 "filters"
        filters:{
            // 函数接受的参数value,其实就是time。
            // 参数str就是传递过来的'YYYY_MM_DD'
            // str='YYYY年-MM月-DD日 HH:mm:ss',参数str的默认值
            timeFormater(value,str='YYYY年-MM月-DD日 HH:mm:ss'){
                return dayjs(value).format(str)
            },
            mySlice(value){
                console.log(value)
                // value = 2021_05_21,取前4位
                return value.slice(0,4)
            },
        }
    })
</script>

十七、内置指令

17.1、v-test 指令使用

v-bind:单向绑定解析表达式,可简写为 :xxx
    例子:age="29"拿到的就是字符串类型"29":age="29"拿到的就是经过js解析后的值,是一个整数类型29
v-model:双向数据绑定
v-for:便利数组/对象/字符串
v-on:绑定事件监听,可以简写为 @
v-if:条件渲染(动态控制节点是否存在)
v-else:条件渲染(动态控制节点是否存在)
v-show:条件渲染(动态控制节点是否展示)

v-test:
  1.作用:向其所在的节点中"渲染"文本内容
  2.与插值语法的区别,v-text会替换掉标签中的内容,{{xx}}插值语法则不会。
  3.v-test例子

<body>
<div id="root">
    <!-- 插值语法 -->
    <div>名称,{{name}}</div>
    <div>地址,{{name}}</div>

    <!-- v-text拿到"name"的值之后,会替换掉div标签里面的内容,也就是"name"替换掉"名称," -->
    <div v-text="name">名称,</div>
    <div v-text="addr">地址,</div>
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false
    new Vue({
        el:"#root",
        data:{
            name:"sudada",
            addr:"shanghai",
        }
    })
</script>

17.2、v-html 指令使用

    1.作用:向指定节点中渲染包含 "html结构" 的内容
    2.与插值语法的区别
        1.v-html会替换标签中所有的内容,{{xx}}插值语法则不会
        2.v-html可以识别html结构
    3.严重注意:v-html有安全性问题!
        1.在网站上动态渲染任意html是非常危险的,容易导致XSS攻击、
        2.一定要在可信任的内容上使用v-html,永远不要再用户提交的内容上。

<body>
<div id="root">
    <h1>hello,{{name}}</h1>
    <h1 v-html="str">王大陆</h1>
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false
    new Vue({
        el: "#root",
        data: {
            name: "sudada",
            str: '<h3>你好</h3>',
        }
    })
</script>

17.3、v-cloak 指令使用

1.本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性
2.使用css配合v-cloak 可以解决网速慢时,页面展示出{{xxx}}的问题。

17.4、v-once 指令使用

1.v-once所在节点在初次动态渲染之后,就为静态内容了
2.之后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。

<body>
<div id="root">
    <!-- v-once只渲染一次,之后就不在动态渲染了。-->
    <h1 v-once>初始化的N值是{{n}}</h1>
    <h2>当前的n值是{{n}}</h2>
    <button @click="n++">点我N+1</button>
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false
    new Vue({
        el:"#root",
        data:{
            name:"sudada",
            n:1,
        }
    })
</script>

17.5、v-pre 指令使用

1.加上v-pre指令之后,该行就变成"所见即所得",也就是vue不解析该行代码了。
2.跳过其所在节点的编译过程
3.可利用它跳过:没有使用指令语法,没有使用插值语法的节点,会加快编译。

<body>
<div id="root">
    <h1 v-pre>v-pre指令的使用</h1>
    <h2 v-pre>当前的n值是{{n}}</h2>
    <button v-pre @click="n++">点我N+1</button>
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false
    new Vue({
        el:"#root",
        data:{
            name:"sudada",
            n:1,
        }
    })
</script>

十八、自定义指令

18.1、函数式(例子:定义个v-big指令,和v-text指令类似,但会把绑定的数值放大10倍)

<body>
<div id="root">
    <h1>hello, {{name}}</h1>
    <h2>当前的值是:<span v-text="n"></span></h2>
    <h2>放大10倍后的n值是 <span v-big="n"></span> </h2>
    <button @click="n++">点我N+1</button>
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false
    new Vue({
        el:"#root",
        data:{
            name:"sudada",
            n:1
        },
        // 定义一个自定义指令(局部指令),这个指令本质就是一个函数,但是不能写返回值,也就是不写return
        directives:{
            // big函数何时会被调用?
            //  1.指令与元素成功绑定时。
            //  2.指令所在的模板被重新解析时。
            big(element,binding){
                console.log(element)  // "element"是真实的DOM元素(div里面v-big是是放在span里面的,那么这里的DOM就是span)
                console.log(binding)  // "binding"是一个对象,里面有个value,这个value就是v-big="n"里面"n"的值
                // element.innerText:原生dom结构,元素内的文本内容。
                element.innerText = binding.value * 10
            }
        }
    })
</script>

18.2、对象式(例子:定义个v-fbind指令,和v-bind指令类似,但可以让其所绑定的input元素默认获取焦点)

<body>
<div id="root">
    <h1>hello, {{name}}</h1>
    <h2>当前的值是:<span v-text="n"></span></h2>
    <h2>放大10倍后的n值是 <span v-big="n"></span> </h2>
    <button @click="n++">点我N+1</button>
    <br>
    <input type="text" v-fbind:value="n">
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false
    new Vue({
        el:"#root",
        data:{
            name:"sudada",
            n:1
        },
        // 局部指令
        directives:{
            // big函数式
            //  1.指令与元素成功绑定时。
            //  2.指令所在的模板被重新解析时。
            big(element,binding){
                element.innerText = binding.value * 10
            },
            // fbind对象式
            // 和上面big函数式的区别:"big函数式"只执行了"bind函数"和"update函数",没有执行"inserted函数"。
            fbind:{
                // 指令与元素成功绑定时,执行bind函数
                bind(element,binding){
                    console.log("bind")
                    element.value=binding.value
                },
                // 指令所在元素被插入页面时,执行inserted函数
                inserted(element,binding){
                    console.log("inserted")
                    element.focus()
                },
                // 指令所在的模板被重新解析时,执行update函数
                update(element,binding){
                    console.log("update")
                    element.value=binding.value
                },
            }
        }
    })
</script>

18.3、自定义指令 总结

18.3.1、定义语法
    1.1、局部指令
        new Vue({
            directives:{指令名:配置对象}
        }) 或者
        new Vue({
            directives(){指令名:回调函数}
        })
    1.2、全局指令
        Vue.directive(指令名:配置对象) 或者 Vue.directive(指令名:回调函数)
18.3.2、配置对象中常用的3个回调:
    1.bind:指令与元素成功绑定时调用。
    2.inserted:指令所在元素被插入页面时调用。
    3.update:指令所在模版结构被重新解析时调用。
18.3.3、
    1.指令定时不加"v-",但是使用时要加"v-"。
    2.指令名如果是多个单词,要是有kebab-case命名方式,不能使用camelCase(驼峰体)。

十九、Vue生命周期函数

19.1、什么是周期回调函数

    1.又名:生命周期回调函数,生命周期函数,生命周期钩子
    2.是什么:vue在关键时刻帮我们调用的一些特殊名称的函数
    3.生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的
    4.生命周期函数中的this指向的是 vm 或 vue组件实例对象。

19.2、总结生命周期

19.2.1、常用的生命周期钩子:
    1.mounted:常用来发送ajax请求,启动定时器,绑定自定义事件,订阅消息等(初始化操作
    2.beforeDestroy:常用来清除定时器,解绑自定义事件,取消订阅消息等(收尾工作
19.2.2、关于销毁vue实例
    1.销毁后借助vue开发工具看不到任何信息。
    2.销毁后自定义事件会失效,但原生DOM事件依然有效。

19.3、生命周期图示

二十、组件的使用

20.1、什么是组件?

        组件是实现应用中"局部"功能"代码(html,css,js)"和"源(各种文件)"的"集合"。

组件式编程的方式,如下图:

什么是模块?

        模块一般就是一个js文件

为什么使用组件?

        复用编码,简化项目编码,提高运行效率。

20.2、非单文件组件(一个文件中有多个组件)缺点:样式CSS不能跟着组件走

20.2.1、组件的基本使用方法(三大步骤)

1、定义组件

    使用Vue.extend(options)创建,其中options和new Vue(options)时传入的那个options几乎一样,但区别如下:
    1.el不写,原因:最终所有的组件都要经过一个vm管理,由vm中的el决定服务哪个容器
    2.data必须写成函数,原因:避免组件被复用时,数据存在引用关系
    备注:使用template可以配置组件结构

2、注册组件(分局部注册和全局注册)

    1.局部注册:在vm里面传入components选项
    2.全局注册:使用Vue.component("组件名",组件值)

3、使用组件(写"组件"标签即可实现组件的使用与复用)

    <组件名></组件名>

4、案例

<body>
<div id="root">
    <h2>{{msg}}</h2>
    <!--  第三步:使用组件(直接写"组件"标签即可实现组件的使用与复用)  -->
    <school></school>
    <school></school>
    <hr>
    <student></student>
    <student></student>
    <hr>
    <!--  第3步:使用全局组件(直接写"组件"标签即可实现组件的使用与复用)  -->
    <hello></hello>
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false
    // 第一步:创建school组件:Vue.extend
        // 组件定义式不需要写"el"配置项
        // data必须要写函数式,这样每次拿到的值都是一样的,如果写成对象式的话,会在内存里面有引用关系,会修改对象内的值。
    const school = Vue.extend({
        // 非单文件组件使用"template"这种方式
        template:`
        <div>
            <h2>学校名称:{{schoolname}}</h2>
            <h2>学校地址:{{address}}</h2>
        </div>
        `,
        data(){
            return {
                schoolname:"学校",
                address:"上海",
            }
        }
    })
    // 第一步:创建student组件
    const student = Vue.extend({
        // 非单文件组件使用"template"这种方式
        template:`
        <div>
            <h2>学生地址:{{name}}</h2>
            <h2>学生名称:{{age}}</h2>
        </div>
        `,
        data(){
            return {
                name:"王大陆",
                age:18
            }
        }
    })

    // 第1步:创建hello组件(这个组件用来注册全局组件)
    const hello = Vue.extend({
        // 非单文件组件使用"template"这种方式
        template:`
        <div>
            <h2>你好啊~{{name}}</h2>
        </div>
        `,
        data(){
            return {
                name:"牛牛牛",
            }
        }
    })
    // 第2步:注册全局组件
    Vue.component('hello',hello)

    const vm = new Vue({
        el:"#root",
        data:{
            msg:"hello"
        },
        // 第二步:注册组件(局部注册)
        // 使用关键字:components,对象格式,里面的"key"就是使用时的"组件名"
        components:{
            school:school,
            student:student
        }
    })
</script>

20.2.2、组件的注意点

    1.关于组件名称
    一个单词组成的"组件名":
        写法1:school(首字母小写)
        写法2:School(首字母大写)
    多个单词组成的"组件名":
        写法1:'my-school'(必须要有引号)
        写法2:MySchool (需要脚手架支持,否则报错)
    备注:
        组件名不能和HTML已有的元素名称重复,比如:h2,H2都不行
        可以使用name配置项,指定组件在浏览器Vue开发者工具中呈现的名称。
    2.关于组件标签
        写法1:<school></school>  常用
        写法2:<school/>  不用脚手架时,<school/>会导致后续组件不能渲染。
    3.组件的简写方式:
        const school = Vue.extend({options}) 可简写为:const school = {options}

4.案例(包含上述1,2,3)

<body>
<div id="root">
    <h1>hello,{{name}}</h1>
    <school></school>  <!--  写法1,推荐  -->
    <!-- <school/> 写法2:单闭合  -->
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false
    // 组件定义简写:不需要 Vue.extend()
    const school = {
        // name:定义组件时,给组件起的别名(这个别名也就是浏览器Vue开发者工具拿到的组件名)
        // 具体在代码里面使用时还是要写'components'注册的组件名
        name:'sudada',
        template:`
        <div>
            <h2>学校名称:{{schoolName}}</h2>
            <h2>学校地址:{{address}}</h2>
        </div>
        `,
        data(){
            return {
                "schoolName": "上海大学",
                "address":"shanghai",
            }
        }
    }
    const vm = new Vue({
        el:"#root",
        data:{
            name:"szq",
            addr:"shanghai",
        },
        components:{
            school:school
        }
    })
</script>

5.还有个特殊的点(可以使用name配置项,指定组件在浏览器Vue开发者工具中呈现的名称。)

在定义组件时,定义一个name属性,那么这个属性就能被开发者工具识别到。

20.2.3、组建的嵌套

简单理解组件的嵌套:外面的就是父组件,里面的就是子组件。

组件嵌套的例子:

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

<script type="text/javascript">
    Vue.config.productionTip = false
    // 组件定义:student组件(子组件)
    const student = Vue.extend({
        template:`
          <div>
          <h2>学生名称:{{studentName}}</h2>
          <h2>学生年龄:{{age}}</h2>
          </div>
        `,
        data(){
            return {
                "studentName": "苏兆强",
                "age":18,
            }
        }
    })
    // 组件定义:school组件(父组件)
    const school = Vue.extend({
        template:`
        <div>
            <h2>学校名称:{{schoolName}}</h2>
            <h2>学校地址:{{address}}</h2>
            <student></student>
        </div>
        `,
        data(){
            return {
                "schoolName": "上海大学",
                "address":"shanghai",
            }
        },
        // school组件内,注册子组件student(局部注册)
        components:{
            student:student,
        }
    })
    // 组件定义:hello组件
    const hello = Vue.extend({
        template:`
          <div>
          <h2>hello:{{name}}</h2>
          </div>
        `,
        data(){
            return {
                "name": "sudada",
            }
        }
    })
    // 组件定义:app组件 (主组件)
    const app = Vue.extend({
        template:`
          <div>
              <hello></hello>
              <school></school>
          </div>
        `,
        // app组件内,注册子组件school和hello(局部注册)
        components:{
            school:school,
            hello:hello,
        }
    })
    // 注册组件(局部)
    const vm = new Vue({
        el:"#root",
        components:{
            app:app,
        }
    })
</script>

20.2.4、VueComponent分析

VueComponent说明:
    前言:vc 是源码vue.extend里面的VueComponent函数执行后返回的对象:
        Vue.extend = function (extendOptions) {
          var Sub = function VueComponent (options) {
          this._init(options);
          };
          return Sub
    1.school 组件本质是一个名为VueComponent"构造函数",且不是程序员定义的,是Vue.extend生成的
    2.我们只需要写<school></school>,vue解析时会帮我们创建school组件的实例对象,即Vue帮我们执行的:new VueComponent(options)。
    3.特别注意:每次调用vue.extend,返回的都是一个全新的VueComponent
    4.关于this指向:
        1.在"组件"配置中:
            data函数、methods函数、watch函数、computed函数 他们的this是 【VueComponent实例对象,简称vc,也就是组件实例对象】
        2.在New Vue({options}) 配置中:
            data函数、methods函数、watch函数、computed函数 他们的this是 【Vue实例对象,简称vm】
        3.vm下的$children可以看到对应的vc,也就可以理解为vm管理vc如果vc内部还有子组件的话,那就去vc下的$children可以看到对应的子vc
    5.vm 和 vc 的区别
        vm有el属性,vc没有,同时vc也没法定义el。其他的属性都一样。

    6.children 例子:vm里面注册了school组件(school组件里面注册了student组件)

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

<script type="text/javascript">
    Vue.config.productionTip = false
    const student = Vue.extend({
        template:`
          <div>
          <h2>学生名称:{{studentName}}</h2>
          <h2>学生年龄:{{age}}</h2>
          </div>
        `,
        data(){
            return {
                "studentName": "王大陆",
                "age":18,
            }
        }
    })
    const school = Vue.extend({
        template:`
        <div>
            <h2>学校名称:{{schoolName}}</h2>
            <h2>学校地址:{{address}}</h2>
            <student></student>
        </div>
        `,
        data(){
            return {
                "schoolName": "上海大学",
                "address":"shanghai",
            }
        },
        components:{
            student:student
        }
    })
    const vm = new Vue({
        el:"#root",
        data:{
            name:"szq"
        },
        components:{
            school:school
        }
    })
</script>

  children 例子展示:

20.2.5、一个重要的内置关系(VueComponent.prototype.__proto__ = Vue.prototype)

为什么要有这个关系:让(组件实例对象vc)可以访问到"Vue原型"上的属性和方法。

 举例说明:

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

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

    // // 定义一个构造函数
    // function demo(){
    //     this.a=10
    //     this.b=20
    // }
    // // 创建一个d实例对象
    // const d = new demo()
    //
    // console.log(demo.prototype)  //显示原型属性(函数才有这个属性)
    // console.log(d.__proto__)  //隐式原型属性(对象才有这个属性)

    // 定义Vue的原型属性,在里面新增一个:x=99
    Vue.prototype.x = 99

    // 组件定义 (组件实例对象vc)
    const school = Vue.extend({
        template:`
        <div>
            <h2>学校名称:{{schoolName}}</h2>
            <h2>学校地址:{{address}}</h2>
            <button @click="showX">点我查看x</button>
        </div>
        `,
        data(){
            return {
                "schoolName": "上海大学",
                "address":"shanghai",
            }
        },
        methods:{
            showX(){
                // 在这里通过(组件实例对象vc)获取Vue的原型属性: x=99
                // 这里的this就是(组件实例对象vc)
                console.log(this.x)
            }
        }
    })
     const vm = new Vue({
        el:"#root",
        data:{
            name:"sudada",
            addr:"shanghai",
        },
        components:{
            school:school
        },
    })
</script>

20.3、单文件组件.vue(一个文件中只有一个组件)

"单文件组件" 格式

<script>
    // 非单文件组件写法
    const school = Vue.extend({
        data(){
            return {
                "schoolName": "上海大学",
                "address":"shanghai",
            }
        },
        methods:{
            showName(){
                alert(this.schoolName)
            }
        }
    })
</script>

"单文件组件" 默认暴露简写方式

<!-- 组件的结构(HTML) -->
<template>
<div class="demo">
    <h2>学校名称:{{name}}</h2>
    <h2>学校地址:{{address}}</h2>
    <button @click="showName">点我显示学校名称</button>
</div>
</template>

<!-- 组件交互的代码(JS) -->
<script>
    // 单文件组件的简写方式:暴露方式3("默认暴露"),简写方式
    export default {
        name: "School",  // name配置项,指定组件在浏览器Vue开发者工具中呈现的名称
        data(){
            return {
                "name": "上海大学",
                "address":"shanghai",
            }
        },
        methods:{
            showName(){
                alert(this.schoolName)
            }
        }
    }
</script>

<!-- 组件的样式(CSS) -->
<style>
    .demo{
        background-color: orange;
    }
</style>

"单文件组件"的其他暴露方式

<script>
    // "分别暴露",主要是给import引用使用 (暴露方式1) import {xxx} from './xxx'
    export const school = Vue.extend({
        data(){
            return {
                "schoolName": "上海大学",
                "address":"shanghai",
            }
        },
        methods:{
            showName(){
                alert(this.schoolName)
            }
        }
    })
</script>

<script>
    const school = Vue.extend({
        data(){
            return {
                "schoolName": "上海大学",
                "address":"shanghai",
            }
        },
        methods:{
            showName(){
                alert(this.schoolName)
            }
        }
    })
    export {school}  // "统一暴露"(代码就是写在底部),主要是给import引用使用(暴露方式2)import {xxx} from './xxx'
</script>

<script>
    const school = Vue.extend({
        data(){
            return {
                "schoolName": "上海大学",
                "address":"shanghai",
            }
        },
        methods:{
            showName(){
                alert(this.schoolName)
            }
        }
    })
    export default school  // "默认暴露"(代码就是写在底部),主要是给import引用使用(暴露方式3,推荐) import xxx from './xxx'
</script>

X、函数调用表达式

<div id="root">
  addr.toUpperCase() 字符串大写
  addr.toLowerCase() 字符串小写
</div>

# if 判断
if(e.target.value !== 13) return

# 定时器,延时1000毫秒后执行
setTimeout(()=>{
  console.log("xxx")
},1000)

# 三元表达式(如果a=3。返回100,否则返回200)
a === 3 ? 100 : 200

# 在数组的开头添加一个值
persons=[]
const p = {id:'004',name:'laoliu',age:49}
persons.unshift(p)
this.persons.push(p)   #在数组的末尾添加一个值

#filter方法(过滤数组内某个值)
persons: [
    {id: "001", name: "马冬梅", age: 18, sex: "女"},
    {id: "002", name: "周冬雨", age: 28, sex: "女"},
    {id: "003", name: "周杰伦", age: 38, sex: "男"},
    {id: "004", name: "温兆伦", age: 48, sex: "男"},
],
this.persons.filter((p)=>{
// indexOf(value) == -1 说明没匹配到,indexOf(value)等于其他"0,1,2,xxx"表示匹配数据的索引值(也就是匹配到了)。
return  p.name.indexOf(value) !== -1

# sort排序
let arr = [1,3,6,2,5,4]
arr.sort((a,b)=>{
    return a-b
})
console.log(arr)
// return a-b:升序 [1, 2, 3, 4, 5, 6]
// return a-b:降序 [6, 5, 4, 3, 2, 1]

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java Vue框架是指使用Java语言和Vue.js框架来开发Web应用程序的一种技术架构。Java是一种跨平台的编程语言,具有强大的面向对象特性和丰富的生态系统,被广泛应用于企业级应用程序开发。而Vue.js是一种轻量级的JavaScript框架,用于构建用户界面,具有简洁的语法和灵活的组件化开发模式。 Java Vue框架的优势在于它能够充分发挥Java的后端能力和Vue.js的前端特性。Java作为后端语言,可以处理各种复杂的业务逻辑和数据处理,同时提供了可靠的安全性和性能。而Vue.js作为前端框架,能够提供丰富的用户界面和良好的用户体验,支持响应式设计和组件化开发。 使用Java Vue框架可以迅速构建现代化的Web应用程序。Java提供了强大的后端支持,包括数据库访问、事务处理、安全认证等功能。Vue.js提供了灵活的前端组件化开发模式,可以构建出复杂的用户界面,并实现前后端数据的无缝交互。这使得开发人员可以按照自己的需求,选择合适的组件和技术,快速构建出高质量的Web应用程序。 此外,Java Vue框架也具有良好的可维护性和扩展性。Java的面向对象特性使得代码可以更加模块化和可复用,便于团队协作和项目管理。Vue.js的组件化开发模式使得前端代码可以更好地组织和维护,而且可以根据需求进行灵活的扩展和定制。 综上所述,Java Vue框架结合了Java的后端能力和Vue.js的前端特性,可以快速构建现代化的Web应用程序,具有良好的可维护性和扩展性。这使得Java Vue框架成为开发人员的首选技术之一。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值