上篇文章我们学了 uni-app 的简单入门,uni-app 是一个使用 Vue.js 开发所有前端应用的框架,这节我们来学习一下如何使用 vue 。
Vue简介
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
Vue使用体验
双向绑定
- jquery 写法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script type="text/javascript" src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js" />
</head>
<body>
<input type="text" data-bind-0=name/>
<span data-bind-0="name"></span>
<script type="text/javascript">
function DataBinder(object_id) {
var pubSub = jQuery({});
var data_attr = "bind-" + object_id,
message = object_id + ":change";
jQuery(document).on("change", "[data-" + data_attr + "]", function (evt) {
var $input = jQuery(this);
pubSub.trigger(message, [$input.attr("data-" + data_attr), $input.val()]);
});
pubSub.on(message, function (evt, prop_name, new_val) {
jQuery("[data-" + data_attr + "=" + prop_name + "]").each(function () {
var $bound = jQuery(this);
if ($bound.is("input,textarea,select")) {
$bound.val(new_val);
} else {
$bound.html(new_val);
}
});
});
return pubSub;
}
function User(uid) {
var binder = new DataBinder(uid),
user = {
attributes: {},
set: function (attr_name, val) {
this.attributes[attr_name] = val;
binder.trigger(uid + ":change", [attr_name, val, this]);
},
get: function (attr_name) {
return this.attributes[attr_name];
},
_binder: binder
};
return user;
}
var user = new User(0);
user.set("name", "text");
</script>
</body>
</html>
- Vue 写法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--引入vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<!--双向绑定-->
<div id="app-1">
<p>{{ msg }}</p>
<input type="text" v-model="msg"/>
</div>
</body>
<script>
var app = new Vue({
el: "#app-1",
data: {
msg: "时刻在奔跑"
}
})
</script>
</html>
从这里例子可以看出,Vue写法非常简洁,便利。
条件表达式
代码如下所示
<body>
<!--条件与循环-->
<div id="app-if">
<!--继续在控制台输入 appIf.seen = false,你会发现之前显示的消息消失了。-->
<p v-if="seen">看到我了吗</p>
<button @click="hidden">点下{{msg}}</button>
</div>
</body>
<script>
new Vue({
el:"#app-if",
data:{
seen:true,
msg:'隐藏'
},
methods:{
hidden(){
this.seen = false;
this.msg= '显示';
}
}
})
</script>
for循环
<body>
<div id="app">
<ol>
<li v-for="city in citys">
{{city.name}}
</li>
</ol>
</div>
</body>
<script>
new Vue({
el:"#app",
data:{
citys:[
{name:"合肥市"},
{name:"铜陵市"},
{name:"安庆市"}
]
}
})
</script>
渲染Html
<body>
<div id="app">
<p>html内容: {{ rawHtml }}</p>
<p>html显示: <span v-html="rawHtml"></span></p>
</div>
</body>
<!--双大括号会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML,你需要使用 v-html 指令:-->
<script>
new Vue({
el:"#app",
data: {
rawHtml: "<a href='#'>时刻在奔跑</a> <img src='https://i.loli.net/2021/04/15/3jHaiZg4fUneRQT.gif' />"
}
})
</script>
Html 属性绑定
<body>
<div id="app">
<input type="text" v-model="userName" />
<!--对于布尔 attribute (它们只要存在就意味着值为 true),v-bind 工作起来略有不同,在这个例子中:-->
<button v-bind:disabled="isButtonDisabled" v-on:click="submit">提交</button>
<!--如果 isButtonDisabled 的值是 null、undefined 或 false,则 disabled attribute 甚至不会被包含在渲染出来的 <button> 元素中。-->
</div>
</body>
<!--Attribute
Mustache 语法不能作用在 HTML attribute 上,遇到这种情况应该使用 v-bind 指令:-->
<script>
new Vue({
el:"#app",
data: {
userName:"",
isButtonDisabled:false
},
methods:{
submit(){
var _this = this;
alert("userName="+_this.userName);
// 提交按钮禁用
_this.isButtonDisabled = true;
// 提交等待后台数据响应
setTimeout(function (){
// 提交完成之后,提交按钮放开
alert("提交成功");
_this.isButtonDisabled = false;
}, 3000);
}
}
})
</script>
JavaScript 表达式
<body>
<div id="app">
<div v-bind:id="'list-' + id"></div>
<div v-bind:hidden="ok?true:false">显示出来</div>
<p><span>1+1=</span>{{number+1}}</p>
<div><span>are you ok ? {{ ok ? 'yes':'no'}}</span></div>
<div>{{message.split('').reverse().join('')}}</div>
</div>
</body>
<!--实际上,对于所有的数据绑定,Vue.js 都提供了完全的 JavaScript 表达式支持。
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
-->
<script>
new Vue({
el:"#app",
data: {
id: 1,
number:1,
ok:true,
message:"abcd",
hidden:false
}
})
</script>
<!--这些表达式会在所属 Vue 实例的数据作用域下作为 JavaScript 被解析。有个限制就是,每个绑定都只能包含单个表达式,所以下面的例子都不会生效。
这是语句,不是表达式
{{ var a = 1 }}
流控制也不会生效,请使用三元表达式
{{ if (ok) { return message } }}
模板表达式都被放在沙盒中,只能访问全局变量的一个白名单,如 Math 和 Date 。你不应该在模板表达式中试图访问用户定义的全局变量。
-->
计算属性
<div id="example">
品牌名称: <input type="text" v-model="brandName"></input>
<p>首字母:{{firstLetter}}</p>
</div>
</body>
<!--计算属性 对于任何复杂逻辑,你都应当使用计算属性。
Vue 提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:侦听属性。
当你有一些数据需要随着其它数据变动而变动时,你很容易滥用 watch——特别是如果你之前使用过 AngularJS。
然而,通常更好的做法是使用计算属性而不是命令式的 watch 回调。细想一下这个例子:-->
<script>
var vm = new Vue({
el: "#example",
data: {
brandName:"Adidas",
},
// 计算属性
computed:{
firstLetter:{
// 计算属性默认只有 getter,不过在需要时你也可以提供一个 setter:
get:function () {
var brandName = this.brandName;
// 取首字母,并转大写
var firstLetter = brandName.substr(0,1).toUpperCase();
return firstLetter;
},
// 另外set设置属性,并不是直接修改计算属性,而是修改它的依赖。
set: function (newValue) {
//this.firstLetter = newValue 这种写法会报错
this.brandName = newValue;
}
}
}
})
</script>
计算属性缓存 vs 方法
我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。
watch 侦听器
<div id="example">
品牌名称: <input type="text" v-model="brandName"></input>
<p>首字母:{{firstLetter}}</p>
</div>
</body>
<script>
var vm = new Vue({
el: "#example",
data: {
brandName: "Adidas",
firstLetter:''
},
// 计算属性
watch: {
brandName: function (newVal,oldVal) {
this.firstLetter = newVal.substr(0,1).toUpperCase();
}
}
})
</script>
watch 与 computed 对比
从上面流程图中,我们可以看出它们之间的区别:
- watch:监测的是属性值, 只要属性值发生变化,其都会触发执行回调函数来执行一系列操作。
- computed:监测的是依赖值,依赖值不变的情况下其会直接读取缓存进行复用,变化的情况下才会重新计算。
除此之外,有点很重要的区别是:计算属性不能执行异步任务,计算属性必须同步执行。也就是说计算属性不能向服务器请求或者执行异步任务。如果遇到异步任务,就交给侦听属性。watch也可以检测computed属性。
v-bind 缩写
<!-- 完整语法 -->
<a v-bind:href="url">...</a>
<!-- 缩写 -->
<a :href="url">...</a>
<!-- 动态参数的缩写 (2.6.0+) -->
<a :[key]="url"> ... </a>
v-on 缩写
<!-- 完整语法 -->
<a v-on:click="doSomething">...</a>
<!-- 缩写 -->
<a @click="doSomething">...</a>
<!-- 动态参数的缩写 (2.6.0+) -->
<a @[event]="doSomething"> ... </a>
Vue生命周期
<body>
<div id="app">
</div>
</body>
<!--每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,
需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。
同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。
比如 created 钩子可以用来在一个实例被创建之后执行代码:-->
<!--也有一些其它的钩子,在实例生命周期的不同阶段被调用,如 mounted、updated 和 destroyed。
生命周期钩子的 this 上下文指向调用它的 Vue 实例。-->
<script>
new Vue({
data: {
a: "初始化"
},
created: function () {
// `this` 指向 vm 实例
alert('a is: ' + this.a)
// => "a is: 1"
}
})
</script>
下图展示了实例的生命周期。你不需要立马弄明白所有的东西,不过随着你的不断学习和使用,它的参考价值会越来越高。
生命周期钩子:cn.vuejs.org/v2/api/#cre…
组件化
<body>
<!--因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,
例如 data、computed、watch、methods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。-->
<div id="components-demo">
<button-counter></button-counter>
<!-- 解析结果
<div id="components-demo"><button>点了我 8 次.</button></div>
-->
<!-- 组件的复用 -->
<button-counter></button-counter>
<button-counter></button-counter>
<!--注意当点击按钮时,每个组件都会各自独立维护它的 count。因为你每用一次组件,就会有一个它的新实例被创建。-->
</div>
</body>
<script>
// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
// 一个组件的 data 选项必须是一个函数
// 当我们定义这个 <button-counter> 组件时,你可能会发现它的 data 并不是像这样直接提供一个对象:data:{count:0}
// 如果 Vue 没有这条规则,点击一个按钮就可能会像如下代码一样影响到其它所有实例
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">点了我 {{ count }} 次.</button>'
});
/*为了能在模板中使用,这些组件必须先注册以便 Vue 能够识别。这里有两种组件的注册类型:全局注册和局部注册。
至此,我们的组件都只是通过 Vue.component 全局注册的:
Vue.component('my-component-name', {
// ... options ...
})
全局注册的组件可以用在其被注册之后的任何 (通过 new Vue) 新创建的 Vue 根实例,也包括其组件树中的所有子组件的模板中。
*/
new Vue({
el: '#components-demo'
});
</script>
组件系统是 Vue 的另一个重要概念,因为它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用。仔细想想,几乎任意类型的应用界面都可以抽象为一个组件树: