vue开发环境与基础语法、计算属性、侦听属性

20 阅读7分钟

一、开发环境

1.通过CDN引入(暴露了全局的vue类对象)
  • 全局构建版本:

这个类对象提供了一个createApp()方法,用来创建一个vue应用

<head>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>

<body>
    <div id="app"></div>
    <script>
        const { createApp } = Vue  // 对象解构
    </script>
</body>
  • ES模块构建版本:
<script type="module">
import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
</script>
2.工程构建

在命令行中运行 npm create vue@latest

二、创建应用示例

通过createApp()方法创建一个vue应用,通过mount()方法挂载到指定div节点下显示

data选项(函数方法) - 定义数据,返回的属性将会成为响应式的状态

methods选项 - 定义方法,是一些用来更改状态与触发更新的函数

template选项 - 定义模板

为方便vue各选项的理解,这里用template选项定义模板(去vcsode应用商店安装es6-string-html扩展,在template选项上方加/html/注释),也可直接写入到div标签中

<!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>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>

<body>
    <div id="app"></div>
    <script>
        //方法一
        // const app = Vue.createApp({// 创建vue应用
        //     data() {
        //         return {
        //             message: 'helloworld'  //定义数据模型
        //         }
        //     },
        //     template: `<p>{{message}}</p>`  // 定义模板  模板文本插值语法 {{ }}
        // })
        // app.mount('#app')// 挂载到指定div节点下显示

        //方法二
        const { createApp } = Vue  // 对象解构
        // 根组件(组件本质是有指定选项属性的javascript对象)
        const root = {
            data() {
                return {
                    message: 'helloworld',  //定义数据模型
                }
            },

            /*html*/
            template: `<p>{{message}}</p>`  // 定义模板  模板文本插值语法 {{ }}
        }

        createApp(root).mount('#app')// 创建vue应用并挂载到指定div节点下显示
    </script>
</body>
</html>

三、基础语法

1. 文本插值 

{{ 变量/表达式 }}

2. 指令(带有v-前缀的特殊属性)
2.1 操作内容文本

v-html  解析标签元素(innerHTML)

v-text  不解析标签元素(innerText)    

v-pre   vue不解析{{ }}

2.2 操作属性

v-bind:属性名=属性值(setAttribute(属性名,属性值),getAttribute(属性名))

:属性名=属性值(简写形式)

2.3 操作样式

:class=”字符 / 对象{样式:控制样式变量} / 数组[,]”(class="")

2.4 操作事件

v-on:事件类型=事件处理函数(onclick="")

@事件类型=事件处理函数(简写形式)

2.5 v-if和v-show

v-if和v-show区别:

v-if 动态添加移除dom节点(满足条件渲染dom节点,不满足不渲染)

v-show 通过css样式display控制dom节点隐藏显示(本质是css样式的 display: none/block)

2.6 列表渲染v-for

(v-for要绑定key,以便虚拟dom diff算法能够快速找到列表项,对列表项进行高效操作)

不建议v-for与v-if合用:

v-for会比v-if优先执行,如果一起用会造成性能浪费,可以v-for外嵌套v-if

如果v-for内嵌套v-if,可以先用计算属性computed过滤遍历数组,再用v-for,优化性能

2.7 表单数据双向绑定v-model

:value="" @input=""/v-model(通过event.target.value获取输入框的值)

2.8 v-cloak 性能优化,用于隐藏未完成编译的DOM模板

网速比较慢或者加载东西比较多时,可能会出现未编译模板闪现情况,用户可能看到还没编译完成的双大括号标签。

v-cloak 会保留在所绑定的元素上,直到相关组件实例被挂载后才移除。配合像[v-cloak]{display:none}这样的CSS规则,它可以在组件编译完毕前隐藏原始模板。

<style>
[v-cloak]{display:none}
</style>
<div v-cloak></div>
3. 指令修饰符模板语法
3.1表单修饰符

number将输入框内容转换为number类型

trim去除前后空格         

lazy懒加载,input事件替换成change事件(不是输入时触发,而是输入完成时触发)

<input v-model.lazy="msg" >
3.2事件修饰符

prevent阻止默认行为(链接跳转、表单提交/event.preventDefault())

stop阻止事件传播(事件冒泡、事件捕获)

passive滚动事件的默认行为 (scrolling) 将立即发生,而非等待 onScroll 完成。( 不能同时使用.passive 和 .prevent,因为 .passive 已经向浏览器表明了你不想阻止事件的默认行为。如果同时使用 .prevent 会被忽略,并且会报错。)

self仅当 event.target 是元素本身时才会触发事件处理器

capture添加事件监听器时,指向内部元素的事件,在被内部元素处理前,先被外部处理(事件捕获)

once点击事件最多被触发一次

3.3按键修饰符

enter/tab/delete (捕获“Delete”和“Backspace”两个按键)/esc/space/up/down/left/right

@keyup.enter="bindLogin"

<!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>模板语法</title>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <style>
        .p1 {
            width: 100px;
            height: 100px;
            background-color: skyblue;
        }
        .d1 {
            color: pink;
        }
        .d2 {
            background-color: rgb(43, 67, 226);
        }
        .d3{
            width: 400px;
            height: 400px;
            background-color: skyblue;
        }
        .d4{
            width: 200px;
            height: 200px;
            background-color: pink;
        }
        [v-cloak] {
            display: none;
        }
    </style>
</head>

<body>
    <div id="app"></div>
    <script>
        const { createApp } = Vue
        const root = {
            // 定义数据
            data() {
                return {
                    title: '文本插值',
                    num: 10,
                    isOk: true,
                    message: 'helloworld',

                    contenthtml: '<h1>v-html操作内容</h1>',
                    contenttext: '<h1>v-text操作内容</h1>',

                    url: 'http://www.baidu.com',
                    pic: 'https://img0.baidu.com/it/u=1705694933,4002952892&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1672160400&t=7153143fa69e03b8233f4d808da5c4b9',

                    onLine: 2, // 0 在线,1 隐身,2 离线
                    show: true,

                    list: [
                        { id: 1001, name: 'javascript高级编程', price: 88.98 },
                        { id: 1002, name: 'vue高级编程', price: 108.89 },
                        { id: 1003, name: 'css高级编程', price: 68.89 },
                    ],

                    modelmsg: '双向绑定',
                    state: false,

                    numberValue: '',
                    trimValue: '',
                    lazyValue: '',
                }
            },

            // methods选项定义方法
            methods: {
                onAlert() {
                    alert('执行onAlert方法 >>>>');
                },

                // methods选项方法不能用箭头函数
                bindInput() {
                    //this: vue实例对象
                    this.modelmsg = event.target.value
                },

                bindNumberConfirm() {
                    alert(typeof (this.numberValue))
                    console.log('this.numberValue ', this.numberValue, typeof (this.numberValue))
                },

                bindTrimConfirm() {
                    alert(this.trimValue)
                    console.log('this.trimValue ', this.trimValue)
                },

                bindBaidu() {
                    // event.preventDefault()
                    alert('bindBaidu>>>>')
                    console.log('bindBaidu>>>>')
                },

                bindSubmit() {
                    alert('bindSubmit >>>> ')
                    console.log('bindSubmit >>>> ')
                },

                bindStopOne(){
                    alert('bindStopOne >>>')
                    console.log('bindStopOne >>>')
                },

                bindStopTwo(){
                    alert('bindStopTwo >>>')
                    console.log('bindStopTwo >>>')
                },

                bindLogin(){
                    alert('bindLogin >>>')
                    console.log('bindLogin >>>')
                },
            },

            // 定义模板
            template: `<div v-cloak>

                        <p>----文本插值-----</p>
                        <h2>{{title}}</h2>
                        <p>{{ num+1 }}</p>
                        <p>{{ isOk?'YES':'NO' }}</p>
                        <p>{{ message.split('').reverse().join('') }}</p>

                        <p>----操作内容-----</p>
                        <p v-html="contenthtml"></p>
                        <p v-text="contenttext"></p>
                        <h2 v-pre>{{title}}</h2>

                        <p>----操作属性-----</p>
                        <a v-bind:href="url">百度</a>
                        <div><img :src="pic" alt="图片"/></div>

                        <p>----操作样式-----</p>
                        <p class="p1">操作样式字符</p>
                        <p v-bind:class="{'p1':isOk}">操作样式对象</p>
                        <p :class="['d1','d2']">操作样式数组</p>

                        <p>----操作事件-----</p>
                        <button v-on:click="onAlert">确定1</button>
                        <button @click="onAlert">确定2</button>

                        <p>----v-if和v-show-----</p>
                        <p v-if="onLine === 0">在线</p>
                        <p v-else-if="onLine === 1">隐身</p>
                        <p v-else>离线</p>
                        <p v-show="show">显示</p>

                        <p>----列表渲染v-for-----</p>
                        <table>
                            <tr>
                               <th>索引号</th>
                               <th>ID</th>
                               <th>名称</th>
                               <th>价格</th>
                            </tr>

                            <tr v-for="(item,index) in list ">
                               <td>{{ index}}</td>   
                               <td>{{ item.id }}</td>   
                               <td>{{ item.name }}</td>   
                               <td>{{ item.price }}</td>   
                            </tr>  
                        </table>

                        <ul>
                           <li v-for="(item,index) in list" >{{index}} - {{item.id}} - {{item.name}} - {{item.price}}</li>
                        </ul>

                        <p>----表单数据双向绑定v-model-----</p>
                        <p>{{modelmsg}}</p>
                        <input type="text" :value="modelmsg" @input="bindInput"/>
                        <input type="text" v-model="modelmsg"/>

                        {{state?'yes':'no'}}
                        <input type="checkbox" v-model="state"/>

                        <p>----表单修饰符-----</p>
                        <p>{{ numberValue }}</p>
                        <input type="text" v-model.number="numberValue"> <button @click="bindNumberConfirm">确定</button>

                        <p>{{ trimValue }}</p>
                        <input type="text" v-model.trim="trimValue"> <button @click="bindTrimConfirm">确定</button>

                        <p>{{lazyValue}}</p>
                        <input type="text" v-model.lazy="lazyValue">

                        <p>----事件修饰符-----</p>
                        <a :href="url" @click.prevent="bindBaidu">百度</a>
                        <form :action="url" @submit.prevent="bindSubmit">
                            <input type="submit" value="提交">
                        </form>

                        <div class="d3" @click="bindStopOne">
                            <div class="d4" @click.stop="bindStopTwo">按钮1</div>
                        </div>

                        <p>----按键修饰符-----</p>
                        <input type="text" @keyup.enter="bindLogin"/>
                      </div>`
        }

        createApp(root).mount('#app')
    </script>
</body>
</html>

四、计算属性computed

缓存计算的结果,依赖项变化重新计算(计算属性的值可以修改,要定义成对象形式,语法上用get、set写法,但要避免直接修改计算属性的值,一般是通过依赖项自动修改)

computed:{}

例如计算总价

<!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>计算总价</title>
    <script src="../lib/vue.global.js"></script>
</head>

<body>
    <div id="app"></div>
    <script>
        const { createApp } = Vue
        const root = {

            data() {
                return {
                    list: [
                        { id1, name'js高级编程', price88.89 },
                        { id2, name'vue高级编程', price118.88 },
                    ]
                }
            },

            methods: {
                bindAddBook(){
                    let product = {id:3,name:'react高级编程',price:200}
                    this.list.push(product)
                }
            },

            computed: {// computed声明时定义成方法,但本质上是一个属性,一定有一个返回值,在computed方法体中定义依赖,当依赖变化重新
                totalPrice(){
                    // let sum = 0
                    // for(let i = 0; i < this.list.length; i++){
                    //     let res = this.list[i]
                    //     sum += res.price
                    // }

                    //累加方法 .reduce((previous, current) => {return previous + current.price}, 0)
                    let sum = this.list.reduce((previous, current) => previous + current.price, 0)
                    return sum.toFixed(2)
                }

          //计算属性的值可以修改,要定义成对象形式,语法上用get、set写法,但要避免直接修改计算属性的值。一般是通过依赖项自动修改

          //fullName:{

              //get(){return xx},

              //set(newvalue){}

          //}

            /* html */
            template: `<div>
                         <table>
                             <tr>
                                 <th>序号</th>
                                 <th>名称</th>
                                 <th>价格</th>
                             </tr>

                             <tr v-for="item,index in list">
                                 <td>{{item.id}}</td>
                                 <td>{{item.name}}</td>
                                 <td>{{item.price}}</td>
                             </tr>
                         </table>

                         <h2>总价: <span>{{totalPrice}}</span></h2>

                         <button @click="bindAddBook">添加商品</button>
                    </div>`

        }
        createApp(root).mount('#app')
    </script>
</body>
</html>

五、侦听属性watch

侦听响应式数据的变化和一些非DOM元素改变,可以获取数据改变前后的值。

默认情况下,组件初次加载完毕不会调用watch侦听器。如果想让watch侦听器立即被调用,需要使用 immediate 选项。

watch:{
  username(){},//函数形式
  username:{//对象形式,立即执行
    handler:(){},//固定写法,自动调用
    immediate:true,
    deep:true,//侦听的是个对象user:{name:’zc’,age:20},改变属性侦听不到,需要深度侦听
  }
}
<!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>watch侦听器</title>
    <script src="../lib/vue.global.js"></script>
</head>

<body>
    <div id="app"></div>
    <script>
        const {createApp} = Vue
        const App = {
            data() {
                return {
                    username:'jack',
                    keyword:'衣服',
                    user:{
                        name:'rose',
                        age:20
                    }
                }
            },

            //侦听器
            watch: {
                username(newValue,oldValue){
                    console.log('newValue ',newValue, '  oldValue',oldValue);
                },
                keyword:{
                    // handler是固定写法,侦听器触发执行的方法。表示当keyword值变化自动调用handler处理函数,
                    handler(newValue,oldValue){
                        console.log('keyword newValue ',newValue, '  oldValue',oldValue);
                    },
                    // 立即执行
                    immediate:true
                },
                user:{
                    handler(newValue,oldValue){
                        console.log('user newValue ',newValue, '  oldValue',oldValue);
                    },
                    // 深度侦听
                    deep:true
                }
            },

            /* html */

            template:`<div>
                        <h2>watch侦听器</h2>
                     </div>`
        }
        const app = createApp(App).mount('#app')
    </script>
</body>
</html>