vue学习 - 基础篇

初始工程结构

这里我们使用script标签从cdn获取vue.js, 而不是使用脚手架vue-cli, 因为cdn比较方便一点, 也不用配置node之类的比较麻烦

index.html

<!DOCTYPE html>
<html>

<head>
  <title>VueJS Course</title>
  <link rel="stylesheet" type="text/css" href="main.css" />
</head>

<body>
  <div id="app">
    <p>Hey</p>
  </div>
  <!-- vue cdn -->
  <script src="https://unpkg.com/vue@next"></script>
  <script src="app.js"></script>
</body>

</html>

app.js

Vue.createApp({})
    // 挂载vue到id=app的元素     .mount('#app')

main.css

body {
  font-size: 22px;
}

input[type="text"] {
  margin: 10px 0;
  display: block;
}

vue devtools 调试工具

在谷歌插件商店安装, 没有也没关系

为了我们打开html(cdn引入了vue)也能调试vue

在浏览器打开文件的方式(我们使用的是vscode)

#1 - 创建并挂载vue实例

createApp会创建一个vue实例, 它有一个mount方法可以将该实例挂载到指定的dom元素上, 该实例会解析这个dom元素的vue语法, 进行处理
// 创建实例 Vue.createApp({})
    // 挂载vue到id=app的元素     .mount('#app')

#2 - data: 定义数据 | 插值表达式

// 定义在vue实例外面的不会被vue实例识别并渲染 let lastName = 'abc'
Vue.createApp({
    // 定义数据     data() {
        return {
            firstName:'John'
        }
    }
})
    // 挂载vue到id=app的元素     .mount('#app')
在html里使用
<!DOCTYPE html>
<html>

<head>
  <title>VueJS Course</title>
  <link rel="stylesheet" type="text/css" href="main.css" />
</head>

<body>
  <!-- {{firstName}} -->
  <div id="app">
    <!-- 插值表达式,vue会运行里面的js表达式,并将结果渲染到页面 -->
    {{2+2}}
    <br />
    {{firstName}}
    <br />
    <!-- 没有定义在vue对象里 -->
    <!-- operty "lastName" was accessed during render but is not defined on instance. at <App> -->
    {{lastName}}
    <!-- error: avoid using JavaScript keyword as property name: "const" -->
    <!-- {{const a = 'foo'}} -->
  </div>
  <!-- vue cdn -->
  <script src="https://unpkg.com/vue@next"></script>
  <script src="app.js"></script>
</body>

</html>

#3 多个vue实例

同一个vue实例不能同时挂载到两个dom元素, 但是可以有多个vue实例, 分别挂载到不同的dom上
<!DOCTYPE html>
<html>

<head>
  <title>VueJS Course</title>
  <link rel="stylesheet" type="text/css" href="main.css" />
</head>

<body>
  <!-- {{firstName}} -->
  <div id="app">
    <!-- 插值表达式,vue会运行里面的js表达式,并将结果渲染到页面 -->
    {{2+2}}
    <br />
    {{firstName}}
    <br />
    <!-- 没有定义在vue对象里 -->
    <!-- operty "lastName" was accessed during render but is not defined on instance. at <App> -->
    {{lastName}}
    <!-- error: avoid using JavaScript keyword as property name: "const" -->
    <!-- {{const a = 'foo'}} -->
  </div>
  <!-- 无法同时挂载到多个对象 -->
  <div id="app">
    {{firstName}}
    <br />
  </div>
  <!-- 可以有多个vue实例,分别挂载不同对象 -->
  <div id="app2">
    {{firstName}}
    <br />
  </div>
  <!-- vue cdn -->
  <script src="https://unpkg.com/vue@next"></script>
  <script src="app.js"></script>
</body>

</html>
app.js
// let lastName = 'abc' Vue.createApp({
    // 定义数据     data() {
        return {
            firstName: 'John'
        }
    }
})
    // 挂载vue到id=app的元素     .mount('#app')
Vue.createApp({
    // 定义数据     data() {
        return {
            firstName: 'Bob'
        }
    }
})
    // 挂载vue到id=app2的元素     .mount('#app2')

#4 methods: 定义方法

<!DOCTYPE html>
<html>

<head>
  <title>VueJS Course</title>
  <link rel="stylesheet" type="text/css" href="main.css" />
</head>

<body>
  <div id="app">
    {{`${firstName} ${lastName.toUpperCase()}`}}
  </div>
  <!-- vue cdn -->
  <script src="https://unpkg.com/vue@next"></script>
  <script src="app.js"></script>
</body>

</html>
但是我们希望视图和逻辑分开, js写方法的具体逻辑, html里是样式和标签
我们定义一个函数, 放到vue实例的methods里, 然后在html里使用
const vm = Vue.createApp({
    // 定义数据     data() {
        return {
            firstName: 'John',
            lastName: 'Bob'
        }
    },
    methods: {
        fullName() {
            return `${this.firstName} ${this.lastName.toUpperCase()}`
        }
    },
})
    // 挂载vue到id=app的元素     .mount('#app')
在插值表达式里使用方法
<!DOCTYPE html>
<html>

<head>
  <title>VueJS Course</title>
  <link rel="stylesheet" type="text/css" href="main.css" />
</head>

<body>
  <div id="app">
    {{ fullName() }}
  </div>
  <!-- vue cdn -->
  <script src="https://unpkg.com/vue@next"></script>
  <script src="app.js"></script>
</body>

</html>

#5 v-cloak 实现渲染完再显示

先调整网速至低俗3G(按f12打开该界面)

此时刷新页面会发现, 插值表达式还在, 数据还没被渲染, 过了一会加载完成, 才渲染上数据

我们使用v-cloak来让加载时不出现这些vue语法
这个cloak在加载的时候会存在, 加载完成后会消失, 我们可以css选择clock, 让加载时cloak不显示页面元素, 等加载完移除cloak, 然后自动恢复元素显示
/* 加载时存在,加载并处理完成后变成data-v-app */
[v-cloak] {
  /* 实现加载时不出现插值表达式等模板语法,加载完直接显示结果 */
  display: none;
}

<!-- v-cloak,元素加载完成后会消失 -->
<div id="app" v-cloak>
  {{ fullName() }}
</div>

#6 v-model: 数据绑定

v-model 可以将input框的value和data里的数据绑定, 改变input的value, 也能同时改变data里对应的变量
<!DOCTYPE html>
<html>

<head>
  <title>VueJS Course</title>
  <link rel="stylesheet" type="text/css" href="main.css" />
</head>

<body> 
  <div id="app" v-cloak>
    <p>{{ fullName() }}</p>
    <hr>
    <label>First Name</label>
    <!-- 响应式Reactivity --> 
    <input type="text" v-model="firstName">
    <label>Last Name</label>
    <input type="text" v-model="lastName">
  </div>
  <!-- vue cdn -->
  <script src="https://unpkg.com/vue@next"></script>
  <script src="app.js"></script>
</body>

</html>

其实v-model是v-bind和@input的语法糖

#7 v-bind 绑定data里的变量到dom元素的属性上

<p><a v-bind:href="url" target="_blank">bing</a></p>
<!-- 简写 -->
<p><a :href="url" target="_blank">bing</a></p>

const vm = Vue.createApp({
    // 定义数据     data() {
        return { 
            url: 'https://bing.com'
        }
    }, 
})
    // 挂载vue到id=app的元素     .mount('#app')

#8 v-html: 渲染富文本

<p v-html="raw_url"></p>

const vm = Vue.createApp({
    // 定义数据     data() {
        return { 
            raw_url: '<p><a href="https://bing.com" target="_blank">bing</a></p>'
        }
    }, 
})
    // 挂载vue到id=app的元素     .mount('#app')

#9 事件监听

我们用 v-on 或简写 @事件名 来监听事件
<label>Last Name</label>
<!-- <input type="text" v-model="lastName"> -->
<!-- 监听input事件 -->
<input type="text" :value="lastName" @input="updateLastName">
<hr>
<p>{{age}}</p>
<!-- 监听事件 -->
<button v-on:click="increment">Increment</button>
<button @click="age--">Decrement</button>

const vm = Vue.createApp({
    // 定义数据     data() {
        return { 
            lastName: 'Bob', 
            age: 20
        }
    },
    methods: { 
        increment() {
            this.age++
        },
        updateLastName(e) {
            this.lastName = e.target.value
        }
    },
})
    // 挂载vue到id=app的元素     .mount('#app')

#10 (调用函数时)传递事件对象 event

向方法传递参数时,如果想传递自定义参数,又想获取事件对象e,需要手动传递$event
<input type="text" :value="lastName" @input="updateLastName('update lastname',$event)">

const vm = Vue.createApp({
    // 定义数据     data() {
        return { 
            lastName: 'Bob', 
        }
    },
    methods: { 
        updateLastName(msg, e) {
            e.preventDefault()
            console.log(msg);
            this.lastName = e.target.value
        }
    },
})
    // 挂载vue到id=app的元素     .mount('#app') 

#11 事件修饰符

事件修饰符,简化像e.preventDefault这种操作, 被加上了.xxx的方法, 会执行对应的js

<input type="text" :value="lastName" @input.prevent="updateLastName('update lastname',$event)">

const vm = Vue.createApp({
    // 定义数据     data() {
        return { 
            lastName: 'Bob', 
        }
    },
    methods: { 
        updateLastName(msg, e) {
            // 加了.prevent, 不需要再加这句             // e.preventDefault()             console.log(msg);
            this.lastName = e.target.value
        }
    },
})
    // 挂载vue到id=app的元素     .mount('#app') 

#12 keyboard 键盘修饰符

<label>Middle Name</label>
<!-- 按下enter触发 -->
<input type="text" @keyup.enter="updateMiddleName">
<!-- 点击按钮+ctrl键才能触发 -->
<button @click.ctrl="...">Decrement</button>

const vm = Vue.createApp({
    // 定义数据     data() {
        return { 
            middleName: '',  
        }
    },
    methods: { 
        updateMiddleName(e) {
            this.middleName = e.target.value
        }
    },
})
    // 挂载vue到id=app的元素     .mount('#app')

#13 v-model的事件修饰符

<!-- 在输入框中,v-model 默认是同步数据,使用 .lazy 会转变为在 change 事件中同步  也就是在失去焦点 或者 按下回车键时才更新** -->
<input type="text" v-model.lazy.trim="firstName"> 
<!-- input框输入数字时,转为number类型,如果没有.number,则依然是string -->
<input type="text" v-model.number="age">

#14 Computed Properties 计算属性

如果在method里计算fullname,则当其他data的数据更新时,fullname也会被重新计算,因为每次更新数据,vue都会重新渲染数据到页面上,则会调用所有method方法(由事件触发的方法不会),所以,我们需要计算属性来让方法在需要时才被调用
const vm = Vue.createApp({
    // 定义数据     data() {
        return {
            firstName: 'John',
            middleName: '',
            lastName: 'Bob', 
        }
    },
    methods: { 
        fullName() {
            console.log(1);
            return `${this.firstName} ${this.middleName} ${this.lastName.toUpperCase()}`
        }, 
    },
})
    // 挂载vue到id=app的元素     .mount('#app') 

<!DOCTYPE html>
<html>

<head>
  <title>VueJS Course</title>
  <link rel="stylesheet" type="text/css" href="main.css" />
</head>

<body>
  <div id="app" v-cloak>
    {{fullName()}}
    <div @click="age++">
      {{age}}
    </div>
  </div>
  <!-- vue cdn -->
  <script src="https://unpkg.com/vue@next"></script>
  <script src="app.js"></script>
</body>

</html>

一直点击div, 更新age, 触发视图更新, 此时可以看到触发了很多次的fullname方法

只有和计算属性关联的值的更新,才会触发计算属性的更新
const vm = Vue.createApp({
    // 定义数据     data() {
        return {
            firstName: 'John',
            middleName: '',
            lastName: 'Bob',
            age:20
        }
    },
    // 计算属性     computed: {
        fullName() {
            console.log(1);
            return `${this.firstName} ${this.middleName} ${this.lastName.toUpperCase()}`
        },
    },
})
    // 挂载vue到id=app的元素     .mount('#app') 

#15 watch 监听

监听值的更新,用得比较少
const vm = Vue.createApp({
    // 定义数据     data() {
        return { 
            age: 20
        }
    }, 
    // watch可以执行异步任务     watch: {
        age(newval, oldval) {
            setTimeout(() => {
                this.age = 100
            }, 2000);
        }
    }
})
    // 挂载vue到id=app的元素     .mount('#app')

#16 动态绑定class

 body{
 font-size: 20px;
 font-family: sans-serif;
}
label{
 margin-bottom: 20px;
 font-size: 20px;
 display: block;
}
select{
 font-size: 20px;
 margin-bottom: 20px;
}
input[type=number]{
 display: block;
 font-size: 20px;
 margin-bottom: 20px;
}
.circle{
 width: 150px;
 height: 150px;
 border-radius: 100%;
 background-color: #45D619;
 text-align: center;
 color: #fff;
 line-height: 150px;
 font-size: 32px;
 font-weight: bold;
}

.purple{
 background-color: #767DEA;
}
.text-black{
 color: #424242;
}
.text-orange{
 color: #FFC26F;
}

<!DOCTYPE>
<html>

<head>
 <title>VueJS Course</title>
 <link rel="stylesheet" type="text/css" href="main.css" />
</head>

<body>
 <div id="app">
 <label>
 <input type="checkbox" v-model="isPurple" /> Purple
 </label>

 <div class="circle" :class="{purple: isPurple}">
      Hi!
 </div>
 </div>

 <script src="https://unpkg.com/vue@next"></script>
 <script src="app.js"></script>
</body>

</html>

let vm = Vue.createApp({
    data() {
 return { isPurple: false }
    }
}).mount('#app')
当需要多个class时,这种写法会很乱,所以我们把它移到计算属性去
<!DOCTYPE>
<html>

<head>
  <title>VueJS Course</title>
  <link rel="stylesheet" type="text/css" href="main.css" />
</head>

<body>
  <div id="app">
    <label>
      <input type="checkbox" v-model="isPurple" /> Purple
    </label>
    <select v-model="selectedColor">
      <option value="">white</option>
      <option value="text-black">black</option>
      <option value="text-orange">orange</option>
    </select>
    <!-- 添加多个class: 传递数组 -->
    <div class="circle" :class="[circle_classes,selectedColor]">
      Hi!
    </div>
  </div>

  <script src="https://unpkg.com/vue@next"></script>
  <script src="app.js"></script>
</body>

</html>

let vm = Vue.createApp({
    data() {
        return { isPurple: false, selectedColor: '' }
    },
    computed: {
        // 计算多个class         circle_classes() {
            return { purple: this.isPurple }
        }
    }
}).mount('#app')

#17 绑定style

<input type="number" v-model="size" />  
<div class="circle" :class="[circle_classes,selectedColor]"
  :style="[{width:size+'px',height:size+'px',lineHeight: size+'px'},{transform: 'rotate(30deg)'}]">
  Hi!
</div>
<!-- 可以多个style对象 -->
<div class="circle" :class="[circle_classes,selectedColor]"
  :style="{width:size+'px',height:size+'px',lineHeight: size+'px'}">
  Hi!
</div>

let vm = Vue.createApp({
    data() {
        return { size: 150 }
    }, 
}).mount('#app')

#18 条件渲染

<!DOCTYPE>
<html>

<head>
  <title>VueJS Course</title>
  <link rel="stylesheet" type="text/css" href="main.css" />
</head>

<body>
  <div id="app">
    <!-- 这些v-if的元素必须在同一个层级 -->
    <p v-if="mode==1">showing v-if directive content</p>
    <!-- template是vue提供的标签,类似<></>,不会渲染为html元素 -->
    <template v-else-if="mode==2">
      <p>v-else-if</p>
      <div>hello</div>
    </template>
    <p v-else>v-else</p>

    <!-- 这个要放在vue实例挂载的元素里v-model才能生效 -->
    <select v-model="mode">
      <option value="1">v-if</option>
      <option value="2">v-else-if</option>
      <option value="3">v-else</option>
    </select>
  </div>
  <script src="https://unpkg.com/vue@next"></script>
  <script src="app.js"></script>
</body>

</html>

const vm = Vue.createApp({
    // 定义数据     data() {
        return { 
            moed:1
        }
    }, 
})
    // 挂载vue到id=app的元素     .mount('#app') 

#19 v-show

<!-- v-if是替换,v-show是设置display -->
<!-- v-show不能使用v-else和template标签 -->
<!-- v-show的性能更好 -->
<i v-show="mode==1">v-show</i>

#20 循环渲染

let vm = Vue.createApp({
    data() {
        return {
            birds: ['Pigeons', 'Eagles', 'Doves', 'Parrots'],
            people: [
                { name: 'John', age: 20 },
                { name: 'Rick', age: 18 },
                { name: 'Amy', age: 33 }
            ]
        }
    }
}).mount('#app');

<!DOCTYPE>
<html>

<head>
  <title>VueJS Course</title>
  <link rel="stylesheet" type="text/css" href="main.css" />
</head>

<body>
  <div id="app">
    <!-- 遍历数组 -->
    <ul>
      <!-- 第二个参数是索引下标 -->
      <li v-for="(bird,index) in birds" :key="bird">
        {{bird}}-{{index}}
      </li>
    </ul>
    <hr>
    <!-- 遍历对象数组 -->
    <ul>
      <!-- <li v-for="person in people">  <div>{{person.age}}</div>  <div>{{person.name}}</div>  </li> -->
      <li v-for="person in people">
        <!-- 遍历对象 -->
        <div v-for="(value,key,index) in person">
          index:{{index}} - {{key}} : {{ value }}
        </div>
      </li>
    </ul> 
  </div>

  <script src="https://unpkg.com/vue@next"></script>
  <script src="app.js"></script>
</body>

</html>

#21 key的作用

let vm = Vue.createApp({
  data() {
    return {
      people: [
        {
          name: 'John',
          message: 'Hello world!'
        },
        {
          name: 'Rick',
          message: 'I like pie.'
        },
        {
          name: 'Amy',
          message: 'Skydiving is fun!'
        }
      ]
    }
  },
  methods: {
    move() {
      const first = this.people.shift()

      this.people.push(first)
    }
  }
}).mount('#app')

<!DOCTYPE>
<html>

<head>
  <title>VueJS Course</title>
  <link rel="stylesheet" type="text/css" href="main.css" />
</head>

<body>
  <div id="app">
    <button type="button" class="move" @click="move">
      Move to Bottom
    </button>
    <!-- 不加key,则input不动 -->
    <!-- 加key,强制元素移动,但是性能开销大 -->
    <div class="card" v-for="person in people" :key="person.name">
      <h3>{{ person.name }}</h3>
      <p>{{ person.message }}</p>
      <input type="text" />
    </div>
  </div>

  <script src="https://unpkg.com/vue@next"></script>
  <script src="app.js"></script>
</body>

</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飞鸟malred

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值