此篇文章同时发布在知乎专栏 前端后端客户端 ,专栏专注于前端、后端、客户端开发的技术分享与探讨,欢迎关注。
虽然说一直不是很喜欢写前端的东西,但作为一个纯后端来说,想做一些直接提供给普通用户使用的 Demo 始终绕不开界面展示的问题。因为工作中也正好需要使用 Vue 进行项目的开发,所以趁此机会入门 Vue,作为前端新手正式上路。
安装 node node 安装包
Vue 独立版本 官网下载 vue.min.js
并使用 <script>
标签引入。
CDN
国内的 CDN 较不稳定,还是建议下到本地进行引入。
CLI $ sudo npm install --global vue-cli
项目初始化 定义一个基于 webpack 模板的新项目。
$ vue init webpack vue-project
进入项目,安装并运行。
$ npm install $ npm run dev
目录结构 ├── README.md ├── build 项目构建(webpack)相关代码 ├── config 配置目录,包括端口号等 ├── index.html 首页入口文件 ├── node_modules npm 加载的项目依赖模块 ├── package.json 项目配置文件 ├── src 开发目录 │ ├── App.vue 项目入口文件 │ ├── assets 放置一些图片 │ ├── components 放了一个组件文件 │ ├── main.js 项目的核心文件 │ └── router ├── static └── test
Hello World 一起来看下 Vue 下载后自带的 Demo。
App.vue <template > <div id ="app" > <img src ="./assets/logo.png" > <router-view /> </div > </template > <script > export default { name: 'App' // 其他文件 import 该文件时用到的名称 } </script > <style > #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style >
main.js import Vue from 'vue' import App from './App' import router from './router' Vue.config.productionTip = false new Vue({ el: '#app' , router, components: { App }, template: '<App/>' })
router/index.js import Vue from 'vue' import Router from 'vue-router' import HelloWorld from '@/components/HelloWorld' Vue.use(Router) export default new Router({ routes: [ { path: '/' , name: 'HelloWorld' , component: HelloWorld } ] })
输出 Hello World! 看了上述代码结构后,大家应该很清楚了,如果需要输出 Hello World,修改 HelloWorld.vue
组件即可:
<script > export default { name: 'HelloWorld' , data () { return { msg: 'Hello World!' } } } </script >
相关语法 模板 插值
{ {...} }
用于文本插值
v-html
用于输出 HTML 代码
v-bind
指令用于指定属性值
支持所有 JavaScript 表达式
指令 指令是带有 v-
前缀的特殊属性,用于在表达式值改变时,将某些行为应用到 DOM 上 。
v-if
根据表达式 seen
的值来决定是否插入 p
元素:
<div id ="app" > <p v-if ="seen" > 现在你看到我了</p > </div > <script > new Vue({ el: '#app' , data: { seen: true } }) </script >
参数:指令:参数
修饰符:以 .
指明的特殊后缀,用于指出一个指令应该以特殊方式绑定
用户输入 使用 v-model
双向绑定数据。
<div id ="app" > <p > {{ message }}</p > <input v-model ="message" > </div > <script > new Vue({ el: '#app' , data: { message: 'Runoob!' } }) </script >
过滤器 过滤器用于文本格式化。
用“管道符”指示
接受表达式的值作为第一个参数
过滤器是 JavaScript 函数
{{ message | capitalize }} <div v-bind:id ="rawId | formatId" > </div > {{ message | filterA | filterB }}
对输入的字符串第一个字母转为大写:
<div id ="app" > {{ message | capitalize }} </div > <script > new Vue({ el: '#app' , data: { message: 'runoob' }, filters: { capitalize: function (value ) { if (!value) return '' value = value.toString() return value.charAt(0 ).toUpperCase() + value.slice(1 ) } } }) </script >
缩写 v-bind
缩写:
<a v-bind:href ="url" > </a > <a :href ="url" > </a >
v-on
缩写:
<a v-on:click ="doSomething" > </a > <a @click ="doSomething" > </a >
条件 关键字:
<div id ="app" > <div v-if ="type === 'A'" > A </div > <div v-else-if ="type === 'B'" > B </div > <div v-else-if ="type === 'C'" > C </div > <div v-else > Not A/B/C </div > </div > <script > new Vue({ el: '#app' , data: { type: 'C' } }) </script >
也可以指定键名和索引进行迭代:
<div id ="app" > <ul > <li v-for ="(value, key, index) in object" > {{ index }}. {{ key }} : {{ value }} </li > </ul > </div >
循环
关键字:v-for
迭代对象需要是 site in sites
形式
<div id ="app" > <ol > <li v-for ="site in sites" > {{ site.name }} </li > </ol > </div > <script > new Vue({ el: '#app' , data: { sites: [ { name : 'Runoob' }, { name : 'Google' }, { name : 'Taobao' } ] } }) </script >
计算属性 当处理一些复杂逻辑时,可以把具体实现放到 computed
中。
<div id ="app" > <p > 原始字符串: {{ message }}</p > <p > 计算后反转字符串: {{ reversedMessage }}</p > </div > <script > var vm = new Vue({ el: '#app' , data: { message: 'Runoob!' }, computed: { reversedMessage: function ( ) { return this .message.split('' ).reverse().join('' ) } } }) </script >
computed 与 method 的区别
效果上是一样的
computed 基于它的以来缓存,只有相关依赖发生改变时才会重新获取
methods 在重新渲染时总会重新调用执行
监听属性 关键字:watch
,用于响应数据的变化。
<div id = "app" > <p style = "font-size:25px;" > 计数器: {{ counter }}</p > <button @click = "counter++" style = "font-size:25px;" > 点我</button > </div > <script type = "text/javascript" > var vm = new Vue({ el: '#app' , data: { counter: 1 } }); vm.$watch('counter' , function (nval, oval ) { alert('计数器值的变化 :' + oval + ' 变为 ' + nval + '!' ); }); </script >
事件处理器 v-on
用于监听事件。
<div id ="app" > <button v-on:click ="greet" > Greet</button > </div > <script > var app = new Vue({ el: '#app' , data: { name: 'Vue.js' }, methods: { greet: function (event ) { alert('Hello ' + this .name + '!' ) if (event) { alert(event.target.tagName) } } } }) app.greet() </script >
表单 使用 v-model
进行双向绑定数据。
复选框 多个复选框绑定到同一个数组中。
<div id ="app" > <p > 单个复选框:</p > <input type ="checkbox" id ="checkbox" v-model ="checked" > <label for ="checkbox" > {{ checked }}</label > <p > 多个复选框:</p > <input type ="checkbox" id ="runoob" value ="Runoob" v-model ="checkedNames" > <label for ="runoob" > Runoob</label > <input type ="checkbox" id ="google" value ="Google" v-model ="checkedNames" > <label for ="google" > Google</label > <input type ="checkbox" id ="taobao" value ="Taobao" v-model ="checkedNames" > <label for ="taobao" > taobao</label > <br > <span > 选择的值为: {{ checkedNames }}</span > </div > <script > new Vue({ el: '#app' , data: { checked : false , checkedNames: [] } }) </script >
单选按钮 <div id ="app" > <input type ="radio" id ="runoob" value ="Runoob" v-model ="picked" > <label for ="runoob" > Runoob</label > <br > <input type ="radio" id ="google" value ="Google" v-model ="picked" > <label for ="google" > Google</label > <br > <span > 选中值为: {{ picked }}</span > </div > <script > new Vue({ el: '#app' , data: { picked : 'Runoob' } }) </script >
select 列表 <div id ="app" > <select v-model ="selected" name ="fruit" > <option value ="" > 选择一个网站</option > <option value ="www.runoob.com" > Runoob</option > <option value ="www.google.com" > Google</option > </select > <div id ="output" > 选择的网站是: {{selected}} </div > </div > <script > new Vue({ el: '#app' , data: { selected: '' } }) </script >
修饰符
.lazy
:在默认情况下, v-model 在 input 事件中同步输入框的值与数据,添加一个修饰符 lazy 后转变为在 change 事件中同步
.number
:输入值转为 number
.trim
:过滤首尾空格
<input v-model.lazy ="msg" >
组件
组件可以扩展 HTML 元素,对代码进行封装
任何类型的应用界面都可以抽象为一个组件树
全局组件 注册一个全局组件:
Vue.component(tagName, options)
其中:
组件调用方式:
注册一个组件并使用:
<div id ="app" > <runoob > </runoob > </div > <script > Vue.component('runoob' , { template: '<h1 > 自定义组件!</h1 > ' }) new Vue({ el: '#app' }) </script >
局部组件 局部组件只能在某个实例中使用。
<div id ="app" > <runoob > </runoob > </div > <script > var Child = { template: '<h1 > 自定义组件!</h1 > ' } new Vue({ el: '#app' , components: { 'runoob' : Child } }) </script >
Prop
prop
是父组件用来传递数据的自定义属性
父组件的数据需要通过 props
把数据传递给子组件
子组件需要显式地用 props
选项声明 prop
<div id ="app" > <child message ="hello!" > </child > </div > <script > Vue.component('child' , { props: ['message' ], template: '<span > {{ message }}</span > ' }) new Vue({ el: '#app' }) </script >
路由 Vue Router 中文文档
<router-link>
相关属性:
to
:表示目标路由的链接。 当被点击后,内部会立刻把 to 的值传到 router.push()
replace
:当点击时,会调用 router.replace()
而不是 router.push()
,导航后不会留下 history 记录
append
:在当前 (相对) 路径前添加基路径
tag
:想要 <router-link>
渲染成某种标签可以使用 tag
active-class
:设置链接激活时使用的 CSS 类名
exact-active-class
:配置当链接被精确匹配的时候应该激活的 class
event
:声明可以用来触发导航的事件
HTML <script src ="https://unpkg.com/vue/dist/vue.js" > </script > <script src ="https://unpkg.com/vue-router/dist/vue-router.js" > </script > <div id ="app" > <h1 > Hello App!</h1 > <p > <router-link to ="/foo" > Go to Foo</router-link > <router-link to ="/bar" > Go to Bar</router-link > </p > <router-view > </router-view > </div >
JavaScript const Foo = { template : '<div>foo</div>' }const Bar = { template : '<div>bar</div>' } const routes = [ { path : '/foo' , component : Foo }, { path : '/bar' , component : Bar } ] const router = new VueRouter({ routes }) const app = new Vue({ router }).$mount('#app' )
Ajax 请求 Vue 使用异步加载需要使用到 vue-resource 库:
<script src="https://cdn.staticfile.org/vue-resource/1.5.1/vue-resource.min.js" ></script >
Get window .onload = function ( ) { var vm = new Vue({ el:'#box' , data:{ msg:'Hello World!' , }, methods:{ get:function ( ) { this .$http.get('get.php' , {params : {a :1 ,b :2 }}).then(function (res ) { document .write(res.body); },function ( ) { console .log('请求失败处理' ); }); } } }); }
POST emulateJSON 的作用: 如果Web服务器无法处理编码为 application/json 的请求,你可以启用 emulateJSON 选项。
window .onload = function ( ) { var vm = new Vue({ el:'#box' , data:{ msg:'Hello World!' , }, methods:{ post:function ( ) { this .$http.post('/try/ajax/demo_test_post.php' ,{name :"test" ,url :"http://www.runoob.com" },{emulateJSON :true }).then(function (res ) { document .write(res.body); },function (res ) { console .log(res.status); }); } } }); }
其他请求方式 vue-resource 还提供了其他 7 种符合 RESTful 设计的请求方式:
get(url, [options]) head(url, [options]) delete (url, [options])jsonp(url, [options]) post(url, [body], [options]) put(url, [body], [options]) patch(url, [body], [options])
参考资料