一 ESMAScript6的基础语法
1 声明变量 let和conset
我们在使用var声明变量时 在js中属于全局作用域,而使用let则属于局部作用域
let声明的变量有两种现象:
- 第一种 属于局部作用域
- 第二种 没有覆盖现象
const 声明的是常量并且也是局部作用域,也就是无法修改变量中的值
2 模板字符串
table键上面的反引号
如果说要拼接一串字符串, 那么不需要再使用+去拼接, 使用反引号来拼接,拼接的变量使用${变量名}
//es5的语法 /* let name = 'harry'; let age = 24; var desc = name+"是XXX,今年"+age+'了'; console.log(desc); */ // es6模板字符串 let name = 'harry'; let age = 24; var desc2 = `${name}是XXXX, 今年${age}了,sdf`; console.log(desc2)
3 函数的书写
es6箭头函数的使用:
funcation(){} ======= () =>{}
箭头函数使用带来的问题:
- 1 使用箭头函数this的指向发生了改变
- 2 使用箭头函数arguments不能使用
// 之前写的方法 /* var person = { name:'harry', age:24, fav:function () { // this 指的是当前的对象 console.log('玩PS4'); console.log(this.age) } } */ var person = { name: 'harry', age: 24, fav: () => { // this的指向发生了改变,指向了定义person的父级对象 window console.log('玩PS4') console.log(this) } };
4 对象的创建
fav(){}等价于 function fav(){} 等价于 var fav funcation(){}
5 es6中创建对象的方式 使用class
class Person{ constructor(name, age){ this.name = name; this.age = age; } showName(){ console.log(this.name) } } var p2 = new Person('张三', 20); p2.showNaem();
二 VUE的介绍与语法
vue是一个渐进式的javaScript框架
1 前端框架和库的区别
功能上的不同:
- jquery库:包含DOM(操作DOM)+请求,就是一块功能。
- art-template库:模板引擎渲染,高性能的渲染DOM
- 框架:大而全的概念,简易的DOM体验+请求处理+模板引擎
- 在KFC的世界里,库就是一个小套餐,框架就是全家桶。
代码上的不同:
- 一般使用库的代码,是调用某个函数或者直接使用抛出来的对象,我们自己处理库中的代码。
- 一般使用框架,其框架本身提供的好的成套的工具帮我们运行我们编写好的代码。
框架的使用:
- 1.初始化自身的一些行为
- 2.执行你所编写的代码
2.nodejs
(1)去官网https://nodejs.org/en/download/ 下载 安装(傻瓜式安装)
(2)打开终端 cmd : node -v 就跟python一样
(3)下载完node 自带包管理器 npm pip3包管理器 pip3 install xxx
(4) 使用npm 第一步 要初始化npm的项目 :
npm init --yes 自动生成一个package.json文件 { "name": "vue_lesson", "version": "1.0.0", "description": "这是我的vue的第一个项目", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "mjj", "license": "ISC", "dependencies": { "vue": "^2.5.16" } }
(5) npm install vue --save
npm install jquery --save
3 vue的起步
- 引包: <script type="text/javascript" src="./node_modules/vue/dist/vue.js"></script> - 创建实例化对象 // 创建VUE实例对象 var app = new Vue({ el:'#app', //目的地 data:{ // 数据属性 msg:'hello vue' } }); - 模板语法插入值 <! -- 模板语法 主要的作用是插值{{}} angualr{{}} react{} --> <h3>{{ msg }}</h3> <h3>{{ msg + 'harry' }} </h3> <h3>{{ 1<1? '真的':'假的' }} </h3>
4 vue指令系统
v-text和v-html
v-text 等价于 {{}} 实现原理:innerHTML v-html 实现原理: innerHTML 表单控件value <h2 v-text="msg2"></h2> <h3 v-html="msg2"></h3>
v-if和v-show
v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。 v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。 相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。 <div class="box" v-if="isShow"></div> <div class="box" v-show="isShow"></div> <div v-if="Math.random() > 0.5"> 大于0.5 </div> <div v-else="Math.random() < 0.5"> 小于0.5 </div>
v-for
item 中指的是数组中的每项元素 <ul> <li v-for="(item,index) in menuList"> <h3>书名:{{item.name}}</h3> <h3>价格:{{item.price}}</h3> </li> </ul>
v-bind
进行属性的绑定 所有的属性都可以进行绑定,注意只要使用了v-bind 后面的字符串一定是数据属性中的值
<div class="wrap" v-bind:class='{active:isGreen} || [] || 变量名 || 常量'></div> 对页面中的标签进行绑定
<a v-bind:href="href">路飞</a>
v-on
vue中使用v-on:click对当前DOM绑定click事件, 所有的原生js的事件使用v-on都可以绑定 示例 利用v-if和v-on来实现页面中dom的创建和销毁: <div id="app"> <h3>{{ msg }}</h3> <div class="box" v-if="isShow">{{ count }}</div> <button v-on:click="showHandler()">{{ btnText }}</button> </div> <script type="text/javascript" src="./node_modules/vue/dist/vue.js"></script> <script type="text/javascript"> new Vue({ el: "#app", template: ``, // data在Vue实例化中可以是一个对象,也可以是一个函数但是在组件中,data必须是一个函数 函数内容一定return一个对象 data: function () { return { msg: '事件处理', count: 0, isShow: true, btnText:'隐藏' } }, // 在vue中所有的事件都声明在methods中 methods: { showHandler() { if(this.isShow){ this.isShow = false; this.btnText = '显示' }else { this.isShow = true; this.btnText = '隐藏' } } } });
示例 使用vue实现一个轮播图的效果:
<div id="slider"> <img v-bind:src="currentImgSrc"> <ul> <li v-for="(item,index) in imgArr" v-bind:class=" {active:currentIndex==index}" v-on:click="clickHandler(index)"> {{ index+1 }} </li> </ul> </div> <script type="text/javascript" src="./node_modules/vue/dist/vue.js"></script> <script type="text/javascript"> var imgArr = [ {id:1, imgSrc:'./images/1.png'}, {id:2, imgSrc:'./images/2.png'}, {id:3, imgSrc:'./images/3.png'}, {id:4, imgSrc:'./images/4.png'} ] new Vue({ el:"#slider", template:``, data(){ return{ imgArr:imgArr, currentIndex:0, currentImgSrc:'./images/1.png' } }, methods:{ clickHandler(index){ this.currentIndex = index; this.currentImgSrc = this.imgArr[index].imgSrc } } }) </script> # 在vue中它可以简写: v-bind: :class :src :id === v-bind:class v-bind:src v-on:click === @click = '方法名'
v-model实现数据的双向绑定
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <div id="app"> <!-- v-model这个指令很好理解,其实它就是一个语法糖 (甜甜的) 它是oninput事件和绑定value的实现 --> <input type="text" :value = 'text' @input = 'valueChange'> <h3>{{ text }}</h3> </div> <script type="text/javascript" src="./node_modules/vue/dist/vue.min.js"></script> <script type="text/javascript"> new Vue({ el:"#app", template:``, data(){ return { text:'alex' } }, methods:{ valueChange(event){ console.log(event.target.value); this.text = event.target.value } } }); </script> </body> </html>
三 VUE组件
步骤:
- 1 先声明入口组件
- 2 挂载子组件 key表示组件名 value表示组件对象
- 3 使用子组件
//头部组件 var Vheader = { template: ` <header class='head'> 我是头部 </header> ` }; // 侧边栏组件 var Vaside = { template: ` <div class='aside'> 我是侧边栏 </div> ` } // 内容区域 var Vcontent = { template: ` <div class='content'> 我是内容区域 </div> ` } // 1. 声明入口组件 // 局部组件 var Vmain = { template: ` <div class="main"> <Vheader></Vheader> <div class="wrap"> <Vaside/> <Vcontent/> </div> </div> `, components: { // 等价于Vheader:Vheader Vheader, Vaside, Vcontent } }; new Vue({ el: "#app", // 3. 使用子组件 template: '<Vmain></Vmain>', data: {}, components: { // 2.挂载子组件 Vmain: Vmain } })
(1)父组件向子组件传递数据:通过Prop
1.在子组件自定义特性。props:['自定义的属性1','自定义属性2']
当一个值传递给一个 prop 特性的时候,它就变成了那个组件实例的一个属性,那么我们就可以像访问data中的值一样
2.要在父组件中导入的子组件内部 绑定自定义的属性 <Vheader :title = '父组件中data声明的数据属性'/>
注意:一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop。
//头部组件 var Vheader = { template: ` <header class='head'> {{title}} </header> `, props:['title'] }; // 侧边栏组件 var Vaside = { template: ` <div class='aside'> 我是侧边栏 </div> ` } // 内容区域 var Vcontent = { template: ` <div class='content'> <ul> <li v-for="post in posts" :key="post.id"> <h2>我的博客标题{{post.title}}</h2> <h2>我的博客内容{{post.content}}</h2> </li> </ul> </div> `, props:['posts'] } // 1. 声明入口组件 // 局部组件 var Vmain = { template: ` <div class="main"> <Vheader v-bind:title="title"></Vheader> <div class="wrap"> <Vaside/> <Vcontent v-bind:posts="appPosts"/> </div> </div> `, components: { // 等价于Vheader:Vheader Vheader, Vaside, Vcontent }, props:['title', 'appPosts'] }; new Vue({ el: "#app", // 3. 使用子组件 template: '<Vmain :title="text" :appPosts="posts"></Vmain>', data: { "text":'我是一个标题', posts:[ {id:1,title:"组件中的传值",content:"通过Prop传递数据"}, {id:2,title:"组件中的传值2",content:"通过Prop传递数据2"}, {id:3,title:"组件中的传值3",content:"通过Prop传递数据3"} ] }, components: { // 2.挂载子组件 Vmain: Vmain } })
(2)如何从子组件传递数据到父组件
1.给子组件中的某个按钮绑定原声事件,。我们可以调用内建的 this.$emit('自定义的事件名','传递的数据'),来向父级组件触发一个自定义的事件.
2.在父组件中的子组件标签中 要绑定自定义的事件,
# 点击改变字体大小 //头部组件 var Vheader = { template: ` <header class='head'> {{title}} </header> `, props: ['title'] }; // 侧边栏组件 var Vaside = { template: ` <div class='aside'> 我是侧边栏 </div> ` } // 内容区域 var Vcontent = { template: ` <div class='content'> <ul> <li v-for="post in posts" :key="post.id"> <h2>我的博客标题{{post.title}}</h2> <h2>我的博客内容{{post.content}}</h2> </li> </ul> <button @click="changeSize">改变字体大小</button> </div> `, props: ['posts'], methods: { changeSize() { // 通过$emit()方法来触发自定义的事件 // 第一个参数是自定义的事件名字 第二个参数就是传递的值 this.$emit('postChangeSize', 1) } } }; // 1. 声明入口组件 // 局部组件 var Vmain = { template: ` <div class="main" :style="{fontSize:fontsize+'px'}"> <Vheader v-bind:title="title"></Vheader> <div class="wrap"> <Vaside/> <Vcontent v-bind:posts="appPosts" @postChangeSize="clickHandler"/> </div> </div> `, methods:{ clickHandler(value){ this.fontsize = this.fontsize+value; } }, data() { return { fontsize: 18 } }, components: { // 等价于Vheader:Vheader Vheader, Vaside, Vcontent }, props: ['title', 'appPosts'] }; new Vue({ el: "#app", // 3. 使用子组件 template: '<Vmain :title="text" :appPosts="posts"></Vmain>', data: { "text": '我是一个标题', posts: [ {id: 1, title: "组件中的传值", content: "通过Prop传递数据"}, {id: 2, title: "组件中的传值2", content: "通过Prop传递数据2"}, {id: 3, title: "组件中的传值3", content: "通过Prop传递数据3"} ] }, components: { // 2.挂载子组件 Vmain: Vmain } })
全局组件的使用:
Vue.component('全局组件的名字',{
跟new Vue() 实例化对象中的options是一样,但是要注意:
不管是公共组件还是局部组件 data必须是个函数 函数一定要返回 {}
})
创建组件
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <style> * { padding: 0; margin: 0; } #head { width: 100%; height: 80px; background-color: purple; } .defalut { display: inline-block; line-height: 1; white-space: nowrap; cursor: pointer; background: #fff; border: 1px solid #dcdfe6; border-color: #dcdfe6; color: #606266; text-align: center; box-sizing: border-box; outline: none; margin: 0; transition: .1s; font-weight: 500; padding: 12px 20px; font-size: 14px; border-radius: 4px; } .primary { color: #fff; background-color: #409eff; border-color: #409eff } .success { color: #fff; background-color: #67c23a; border-color: #67c23a; } </style> </head> <body> <div id="app"> </div> <script type="text/javascript" src="./node_modules/vue/dist/vue.min.js"></script> <script type="text/javascript"> // 创建公共组件 // 第一个参数是公共组件的名字,第二个参数options Vue.component('Vbtn', { template: `<button class='defalut' :class='type'> <slot></slot> </button>`, props: ['type'] }); var Vheader = { data() { return { } }, template: `<div id='head'> <Vbtn>登录</Vbtn> <Vbtn>注册</Vbtn> <Vbtn>提交</Vbtn> <Vbtn>默认的按钮</Vbtn> <Vbtn type='primary'>主要的按钮</Vbtn> <Vbtn type='success' >成功的按钮</Vbtn> </div>` }; // 局部组件的使用 var App = { template: `<div> <Vheader></Vheader> </div>`, components: { Vheader } } new Vue({ el: '#app', data() { }, template: `<App />`, components: { App } }); </script> </body> </html>
全局过滤器的使用:
// 注册全局的过滤器 <!-- 第一个参数是过滤器的名字,第二个参数是执行的操作 --> Vue.filter('reverse',function(value) { return value.split('').reverse().join(''); });
1 <!DOCTYPE html> 2 <html> 3 4 <head> 5 <meta charset="utf-8"> 6 <title></title> 7 <style> 8 9 </style> 10 </head> 11 12 <body> 13 <div id="app"> 14 <input type="text" v-model = 'price'> 15 <h3>{{ price | currentPrice}}</h3> 16 <h4>{{msg | reverse}}</h4> 17 </div> 18 <script type="text/javascript" src="./node_modules/vue/dist/vue.min.js"></script> 19 <script type="text/javascript"> 20 21 // 注册全局的过滤器 22 Vue.filter('reverse',function(value) { 23 24 return value.split('').reverse().join(''); 25 }) 26 27 28 new Vue({ 29 el: '#app', 30 data() { 31 return{ 32 price:0, 33 msg:"hello luffy" 34 } 35 }, 36 // 局部过滤器 在当前 组件中声明过滤器 37 filters:{ 38 currentPrice:function (value) { 39 // 参数1就是纯涤的元数据 40 console.log(value); 41 return '$' + value; 42 } 43 } 44 }); 45 </script> 46 </body> 47 48 </html>
四 VUE的计算属性和侦听器
1 侦听属性之watch
计算属性(data中的相关数据)和侦听器(watch):
<!-- 侦听的是单个属性 -->
watch:{
数据属性的名字:function(value){
},
数据属性的名字2:function(value){
}
}
<!--侦听多个属性:计算属性 computed -->
<!-- {{str.split('').reverse().join('')}} -->
<!-- v-bind -->
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <div id="app"> <input type="text" v-model='myName'> <h3>{{ myName}}</h3> <button @click='clickHandler'>修改</button> </div> <script type="text/javascript" src="./node_modules/vue/dist/vue.min.js"></script> <script type="text/javascript"> new Vue({ el:'#app', template:``, data(){ return { myName:'', firtName:'wusir' } }, methods:{ clickHandler(){ this.myName = 'alex'; } }, watch:{ // 检测单个属性 命令式 myName:function(value) { console.log(value); if (value === 'alex') { console.log(value +' '+this.firtName+'是sb') } } } }); </script> </body> </html>
2 计算属性computed
计算属性语法默认只支持getter方法
data(){ return { name:'alex', age:18 } } compuetd:{ key:value 计算属性的方法名:funtion(){ return `${this.name}他的年龄是${this.age}岁` } }
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <div id="app"> <h4>{{alexDesc}}</h4> <button @click='clickHandler'>修改</button> </div> <script type="text/javascript" src="./node_modules/vue/dist/vue.min.js"></script> <script type="text/javascript"> new Vue({ el:'#app', template:``, data(){ return { myName:'alex', age:18 } }, methods:{ clickHandler(){ this.myName = 'WUSIR'; this.age = 28; } }, computed:{ alexDesc:function() { var str = `${this.myName}它的年龄是${this.age}岁了可以去大保健`; // 默认只有getter return str; } } }); </script> </body> </html>
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <div id="app"> <h4>{{alexDesc}}</h4> <button @click='clickHandler'>修改</button> </div> <script type="text/javascript" src="./node_modules/vue/dist/vue.min.js"></script> <script type="text/javascript"> new Vue({ el:'#app', template:``, data(){ return { myName:'alex', age:18 } }, methods:{ clickHandler(){ console.log(this.alexDesc); this.alexDesc = 'ALEX is SB!!!'; } }, computed:{ alexDesc:{ set:function(newValue) { console.log(newValue); this.myName = newValue; }, get:function() { var str = `${this.myName}它的年龄是${this.age}岁了可以去大保健`; // 默认只有getter return str; } } } }); </script> </body> </html>
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <div id="app"> <input type="text" v-model = 'alexDesc'> <h4>{{alexDesc}}</h4> <!-- <button @click='clickHandler'>修改</button> --> </div> <script type="text/javascript" src="./node_modules/vue/dist/vue.min.js"></script> <script type="text/javascript"> new Vue({ el:'#app', template:``, data(){ return { myName:'', } }, computed:{ alexDesc:{ set:function(newValue) { this.myName = newValue; }, get:function() { return this.myName; } } } }); </script> </body> </html>
3 计算属性音乐播放器案例
<style type="text/css"> *{ padding: 0; margin: 0; } ul{ list-style: none; } ul li { margin: 30px 20px; padding: 10px; } ul li.active{ background-color: #20FFFF; } </style> </head> <body> <div id="music"> <audio :src="currentSrc" controls autoplay></audio> <ul> <li v-for = '(item,index) in musics' @click = 'clickHandler(index)' :class = '{active:currentIndex == index}'> <h2>{{item.id}}--歌曲为:{{item.name}}</h2> <p>歌手:{{item.author}}</p> </li> </ul> </div> <script type="text/javascript" src="./node_modules/vue/dist/vue.min.js"></script> <script type="text/javascript"> var musicData = [{ id: 1, name: '于荣光 - 少林英雄', author: '于荣光', songSrc: './static/于荣光 - 少林英雄.mp3' }, { id: 2, name: 'Joel Adams - Please Dont Go', author: 'Joel Adams', songSrc: './static/Joel Adams - Please Dont Go.mp3' }, { id: 3, name: 'MKJ - Time', author: 'MKJ', songSrc: './static/MKJ - Time.mp3' }, { id: 4, name: 'Russ - Psycho (Pt. 2)', author: 'Russ', songSrc: './static/Russ - Psycho (Pt. 2).mp3' } ]; new Vue({ el: '#music', data() { return { musics:musicData, currentIndex:0 // musicSrc:'./static/于荣光 - 少林英雄.mp3' } }, methods:{ clickHandler(index){ // alert(index); this.currentIndex = index; } }, computed:{ currentSrc(){ // 监听了两个属性 musics currentIndex return this.musics[this.currentIndex].songSrc; } }, template: `` }); </script>
五 VUE的生命周期和钩子函数
每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。
<body> <div id="app"> <App></App> </div> <script type="text/javascript" src="./node_modules/vue/dist/vue.min.js"></script> <script type="text/javascript"> // beforeCreate // created // beforeMount // mounted // beforeUpdate // updated // activated // deactivated // beforeDestroy // destroyed var Test ={ data(){ return{ msg:"哈哈哈" } }, template:` <div> <div>{{msg}}</div> <button @click = 'changeHandler'>修改</button> </div> `, methods:{ changeHandler(){ this.msg= this.msg + 'alex' } }, beforeCreate(){ //在组件创建之前 console.log(this.msg) }, created(){ // 组件创建之后 // 使用该组件,就会触发以上的钩子函数, created中可以操作数据,如发送ajax,并且可以实现VUE对页面的影响 console.log(this.msg) }, beforeMount(){ // 装载数据到DOM之前会调用 console.log(document.getElementById('app')) }, mounted(){ // 装载数据到DOM之后会调用, 可以获取真实存在的DOM元素, VUE操作以后的DOM // 这个地方可以操作DOM console.log(document.getElementById('app')) }, beforeUpdate(){ // 在更新之前,调用此钩子函数, 应用:获取原始的DOM console.log(document.getElementById('app').innerHTML) }, updated(){ // 在更新之后, 调用此钩子函数, 应用:更新之后的DOM }, beforeDestroy(){ console.log('beforeDestroy') }, destroyed(){ console.log('destroyed') }, activated(){ console.log('组件被激活') }, deactivated(){ console.log('组件被停用') } }; var App = { data(){ return{ isShow:true } }, // <keep-alive>组件,可以让当前的组件产生缓存 template:` <div> <keep-alive> <Test v-if="isShow"></Test> </keep-alive> <button @click = 'changeHandler'>创建和销毁组件</button> </div> `, methods:{ changeHandler(){ this.isShow = !this.isShow; } }, components:{ Test } }; new Vue({ el:'#app', template:'', components:{ App } }) </script> </body>
六 VUE使用$ref获取DOM元素
- $refs获取组件内的元素
- $parent:获取当前组件的父组件
- $children:获取当前组件的子组件
- $root:获取New Vue的实例化对象
- $el:获取组件对象的DOM元素
<body> <div id="app"></div> <script type="text/javascript" src="./node_modules/vue/dist/vue.min.js"></script> <script type="text/javascript"> Vue.component('subComp', { template:`<div></div>` }); var App = { template:`<div> <subComp ref="subc"></subComp> <button ref="btn">我是按钮</button> <p ref="sb">alex</p> </div>`, beforeCreate(){ console.log(this.$refs.btn); // undefined }, created(){ console.log(this.$refs.btn); // undefined }, beforeMount(){ console.log(this.$refs.btn); // undefined }, mounted(){ console.log(this.$refs.btn); // 如果是给组件绑定的ref属性那么this.$refs.subc取到的是组件对象 console.log(this.$refs.subc); var op = this.$refs.sb; this.$refs.btn.onclick = function () { alert(op.innerHTML) } } }; new Vue({ el:'#app', data(){ return{ } }, template:'<App/>', components:{ App } }) </script> </body>
获取更新之后的dom添加事件的特殊情况
// $nextTick 是在下次Dom更新循环结束之后执行的延迟回调,在修改数据之后使用$nextTick ,则可以在回调中获 <body> <div id="app"></div> <script type="text/javascript" src="./node_modules/vue/dist/vue.min.js"></script> <script type="text/javascript"> Vue.component('subComp', { template:`<div></div>` }); var App = { data(){ return{ isShow:false } }, template:`<div> <input type="text" v-if="isShow" ref="fos"> </div>`, mounted(){ // vue实现响应式并不是数据发生变化之后DOM立即发生变化, 而是按一定的策略进行DOM更新 // $nextTick是在下次Dom更新循环结束之后执行的延迟回调,在修改数据之后使用$nexTick,则可以在回调中获取更新之后的DOM this.isShow = true; this.$nextTick(function () { // 获取更新之后的Dom this.$refs.fos.focus() }) } }; new Vue({ el:'#app', data(){ return{ } }, template:'<App/>', components:{ App } }) </script> </body>