什么是Vue?
Vue是一种渐进式JavaScript 框架。易用,灵活,高效
易用:只要会HTML, css, Javascript就可以使用
灵活:Vue 的核心库只关注视图层,可以配合市场已流行的其他脚本库及平台使用
流行的脚本库及平台:如Jquary,axios,loadash,node.js,express,koa等
高效:40kB min+gzip 运行大小,超快虚拟DOM,省心优化
Vue作者?尤雨溪
Vue中文官网 http://cn.vuejs.org
命令行工具有两种版本,学习最新的CLI3.0
npm install -g @vue/cli
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
高内聚,低耦合。
组件封装追求的低耦合
作业:
使用vue的v-if v-for等制作一个类似QQ的手风琴效果
效果:
源码:
https://blog.csdn.net/fengtingYan/article/details/82934542
下面的所有的源码都要导入(本地文件)
<script src="vue.min.js"></script>
声明式渲染
需要视图模板和数据,先声明数据,然后把数据和视图模板绑定在一起,让视图使用声明的数据进行视图渲染的过程
<!-- 视图模板 -->
<div id="app">
{{message}}
</div>
<script>
// 数据必须使用Vue传,使用原生js定义不行
var message = "hello"
// 必须用Vue框架来准备数据
// 创建Vue对象的一个实例来对应一个视图,让他控制视图
// vue构造函数中通过配置项来控制视图
var app = new Vue({
el:"#app", //el=>element,用来设置Vue实例控制的视图,它是Vue实例和视图练习的纽带
data:{//向视图准备数据
message:"Hello Vue!"
}
});
/* 响应式
app.$date.message
当你更改了Vue实例中的数据,Vue视图会立即更新视图,(立即响应数据变化)就叫做响应式
*/
app.message = "你好"
</script>
效果:
初识指令
<div id="app">
<!-- Vue实例中的数据可以在元素内容区使用“{{}}” 语法来使用(插值语法),但在元素属性中使用{{}}不能被Vue解析
想让Vue控制元素的属性,必须使用Vue指令
v-bind:用来给属性绑定数据
可以直接绑定一个常量字符串,注意引号,不加引号时,Vue会当做变量解析-->
<h1 v-bind:title='message'>{{message}}</h1>
<h1 v-bind:title="'hello'">{{message}}</h1>
<!--v-if指令控制元素的显示/隐藏 ,值是一个布尔表达式
v-if指令会控制dom的创建和销毁,不用担心性能问题,Vue使用缓存技术对这些操作做了特殊处理-->
<div v-if="false">我是div</div>
<div v-if="1==1">我是div</div>
<div v-if="show">我是div</div>
<!-- v-show也可以控制元素的显示/隐藏,但他不会创建和销毁dom,会通过简单的css样式(display=none)控制 -->
<h2 v-show="show">我是h2</h2>
<ul>
<!-- v-for循环遍历数组 -->
<li v-for="f in foods">{{f}}</li>
</ul>
</div>
<script>
var app = new Vue({
el:"#app",
data:{
message:"让数据在元素中使用",
show:true,
foods:["肉","肉2","肉3"]
}
})
</script>
效果:
v-for练习
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>初步认识Vue指令</title>
<script src="vue.min.js"></script>
<style>
table{
border-collapse: collapse;
width: 600px;
}
th,td{
border: grey groove 2px;
}
</style>
</head>
<body>
<div id="app">
<table>
<tr>
<th>索引</th>
<th>价格</th>
<th>姓名</th>
<th>性别</th>
<th>年龄</th>
<th>生日</th>
</tr>
<!-- i表示数据的索引,key属性是Vue专门为v-for提供的属性,key属性对应的值唯一值v-bind:key="s.id" v-bind可以绑定所有属性(符合HTML5 规范是属性,Vue添加的属性,自定义属性data-dsh)-->
<tr v-for="(s,i) in students" v-bind:key="i" v-bind:data-dsh="s.id">
<td>{{i}}</td>
<td>{{s.id | currency}}</td>
<td>{{s.name | upperCase}}</td>
<!-- <td v-if="s.sex">男</td>
<td v-else-if="s.sex='zbc'">不男不女</td>
<td v-else>女</td> -->
<td >{{s.sex?'男':'女'}}</td>
<td v-if="s.age==20">年轻</td>
<td v-else-if="s.age==50">中年</td>
<td v-else-if="s.age==80">老年</td>
<td v-else>未知</td>
<!-- 在Vue中想对数据进行格式化操作,不仅可以使用v-if判断,
还可以使用过滤器,Vue1.x中有很多自带的过滤器,但vue.2把自带的过滤器全部移除了 -->
<td>{{s.birthday | dateFormat}}</td>
</tr>
</table>
</div>
<script>
var app = new Vue({
el:"#app",
data:{
students:[
{id:1,name:"zhangsan",sex:true,age:20,birthday:new Date()},
{id:2,name:"ls",sex:false,age:50,birthday:new Date()},
{id:3,name:"ww",sex:true,age:80,birthday:new Date()}
]
},
filters:{//过滤器
upperCase: function(value){
if(typeof value=="string"){
return value.toUpperCase();//大写
}
},
lowerCase: function(value){
if(typeof value=="string"){
return value.toLowerCase();
}
},
currency: function(value){
if(typeof value=="number"){
return '¥' + value.toFixed(2);
}
},
dateFormat: function(date){
var date = new Date(date);
var y = date.getFullYear();
var M = date.getMonth() + 1;
var d = date.getDate();
var h = date.getHours();
var m = date.getMinutes();
var s = date.getSeconds();
return `${y}-${m}-${d} ${h}:${m}:${s}`
}
}
})
</script>
</body>
</html>
效果:
双向数据绑定(v-model)
<div id="app">
<!-- v-bind指令是把数据绑定到视图,是单向的
而v-model不仅把数据绑定到视图,当视图上的数据发生变化时,会影响Vue实例数据,是双向的
v-model是“语法糖”,两个指令的封装,v-bind v-on
-->
<input type="text" v-model="message">{{message}}
</div>
<script>
var app = new Vue({
el:"#app",
data:{
message:"hello vue!"
}
})
</script>
效果:
操作数据
<div id="app">{{message}}
<!-- 当访问的方法不带参数时,小括号可以不加 -->
<button v-on:click="changeMessage">更改message</button>
<button v-on:click="changeMessage2('你好')">更改message(带参数)</button>
<button v-on:click="fun">事件句柄</button>
</div>
<script>
var app = new Vue({
el:"#app",
data:{
message:"hello vue"
},
methods:{
changeMessage:function(){
this.message = "abc";
},
changeMessage2:function(content){
this.message = content;
},
// ev就相当于给event起一个别名,不加形参ev时在方法中直接通过event访问
fun:function(ev){
//event是事件句柄,Vue自带的
console.log(ev);
console.log(event);
//ev.target获取当前点击的宿主
console.log(ev.target.innerText);
}
}
})
</script>
效果:
初识组件
<div id="app">
<!-- 使用组件像使用标签一样 -->
<dsh></dsh>
<abc></abc>
</div>
<div id="app1">
<dsh></dsh>
<!-- abc不能在app1中使用,因为没有在app1实例中定义,全局组件也没有abc -->
<abc></abc>
</div>
<script>
// 在Vue中组件和过滤器一样,有两种创建方式:局部组件和全局组件
// 创建全局组件,参数1:组件名称,不要和HTML已存在的标签名称同名。
// 参数2:组件的配置项全局组件可以在所有的vue实例使用
Vue.component('dsh',{
template:"<h1>自定义的h1标签</h1>"
})
// 当全局和局部拥有同名组件时候,视图会优先使用局部组件
Vue.component('abc',{
template:"<p>我是全局组件abc</p>"
})
var app = new Vue({
el:"#app",
// 局部组件
components:{
abc:{
template:"<session>我是自定义的session标签</session>"
}
}
})
var app1 = new Vue({
el:"#app1"
})
</script>
效果:
<div id="app">
<!-- 使用组件像使用标签一样。 -->
<dsh></dsh>
<abc></abc>
<zs></zs>
</div>
<!-- <script id="tpl-zs" type="text/html"> -->
<script id="tpl-zs" type="x/template">
<div>
我是组件的视图模板 有且只有一个根元素
</div>
</script>
<script>
Vue.component('dsh',{
// 使用``这种ES6的模板字符串语法,可以很容易控制template。
// 组件中的模板有且只有一个根元素
template:`
<h1>
自定义的h1标签
<span style="color:red;">我是span</span>
</h1>`
})
Vue.component('zs',{
// 引用<script id="tpl-zs" type="text/html">
template: '#tpl-zs'
})
var app = new Vue({
el:"#app",
})
</script>
效果:
<div id="app">
<!-- :是v-bind: 指令的缩写形式。-->
<dsh v-bind:abc="message" :persons="arr1"></dsh>
</div>
<script>
Vue.component('dsh',{
// 组件中的模板有且只有一个根元素
// 组件动态化,向组件传值
// 数据从哪里来?谁使用组件,数据就从哪里来
template:`
<div>{{abc}}
<ul>
<li v-for="p in persons">{{p}}</li>
<li v-for="persons">{{persons}}</li>
</ul>
</div>
`,
// props=>propertles
props:['abc','persons']
})
var app = new Vue({
el:"#app",
data:{
message:"hello",
arr1:['zs','ls','ww']
}
})
// message的内容是hello 他的属性abc,找到props:['abc'] template的abc
</script>
组件props传值
效果:
组件实例
<div id="app">
<ol>
<!--
现在我们为每个 todo-item 提供 todo 对象
todo 对象是变量,即其内容可以是动态的。
我们也需要为每个组件提供一个“key”,稍后再
作详细解释。
-->
<!-- <todo-item v-for="item in groceryList" v-bind:todo="item" v-bind:key="item.id">
</todo-item> -->
<!-- ol中放一个自定义组件todo-item,不符合HTML5规范 -->
<!-- 注意is的用法 -->
<li
v-for="item in groceryList" v-bind:todo="item"
v-bind:key="item.id"
is="todo-item">
</li>
</ol>
</div>
<script>
Vue.component('todo-item', {
// todo-item 组件现在接受一个
// "prop",类似于一个自定义特性。
// 这个 prop 名为 todo。
props: ['todo'],
template: '<li>{{ todo.text }}</li>'
})
var app = new Vue({
el:"#app",
data:{
groceryList: [
{ id: 0, text: '蔬菜' },
{ id: 1, text: '奶酪' },
{ id: 2, text: '随便其它什么人吃的东西' }
]
}
})
</script>
效果:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>组件实例</title>
<script src="vue.min.js"></script>
<style>
html,body,#app,aside,.content{
height: 100%;
}
body{
margin: 0;
}
nav{
height: 80px;
background-color: #ccc;
}
.containner{
background-color:hotpink;
height: calc(100% - 80px);
}
aside{
background-color:greenyellow;
width: 200px;
float: left;
}
.content{
background-color: rebeccapurple;
width: calc(100% - 200px);
float: right;
}
.clearfix::after{
clear:both;
visibility: hidden;
content:'';
display: inline-block;
height: 0;
}
</style>
</head>
<body>
<div id="app">
<app-nav></app-nav>
<app-view class="clearfix">
<app-sidebar></app-sidebar>
<app-content></app-content>
</app-view>
</div>
<script>
// 推荐中线命名法
Vue.component('app-nav', {
template:"<nav>我是导航</nav>"
})
// 组件如果使用了小驼峰命名法,在浏览器端使用时需要用中线分割
Vue.component('appView', {
// slot插槽 留一个空间
template:`
<div class="containner">
<slot></slot>
</div>
`
})
Vue.component('app-sidebar', {
template:"<aside>我是侧边栏</aside>"
})
Vue.component('app-content', {
template:`
<div class="content">我是内容区</div>
`
})
var app = new Vue({
el:"#app"
})
</script>
</body>
</html>
效果:
总结练习
<div id="app">
<!-- 1 文本插值绑定元素特性 -->
{{message}}
<span v-bind:title="message">鼠标悬停几秒钟查看此处动态绑定的提示信息!</span>
<!-- 2 循环输出 -->
<ol>
<li v-for="todo in todos">
{{ todo.text }}
</li>
</ol>
<!--3 v-on 指令添加一个事件监听器 -->
{{message}}
<!-- 需求:点击让message倒着写 -->
<button v-on:click="reverseMessage">逆转消息</button>
<!--4 v-model 指令实现表单输入和应用状态之间的双向绑定。 -->
<!-- 需求:输入框显示message -->
<input type="text" v-model="message">
<!-- 5 注册组件 -->
<!-- 6 v-once 指令,你也能执行一次性地插值,当数据改变时,插值处的内容不会更新 -->
<span v-once>这个将不会改变: {{ msg }}</span>
<!-- 7 v-bind 指令可以用于响应式地更新 HTML 特性: -->
<!-- 完整语法 -->
<a v-bind:href="">...</a>
<!-- 缩写 -->
<a :href="">...</a>
<!-- 8 v-on 指令,它用于监听 DOM 事件: -->
<!-- 完整语法 -->
<a v-on:click="doSomething">...</a>
<!-- 缩写 -->
<a @click="doSomething">...</a>
<!--9 -->
<div class="static"
v-bind:class="{ active: isActive, 'text-danger': hasError }">
</div>
</div>
<script>
Vue.component('todo-item',{
prop:['todo'],
template:'<li>{{todo.text}}</li>'
})
var app = new Vue({
el: "#app",
data: {
message: 'Hello Vue!',
todos: [
{ text: '学习 JavaScript' },
{ text: '学习 Vue' },
{ text: '整个牛项目' }
],
msg:1
},
methods:{
reverseMessage(){
this.message = this.message.split('').reverse().join('')
}
}
})
</script>