指令
v-text {} 文本 <span v-text="msg"></span>
、 <span>{msg}</span>
v-html html内容 <div v-html="html"></div>
v-show 是否展示, CSS切换 <h1 v-show="ok">Hello!</h1>
v-if 是否保留 <p v-if="seen">现在你看到我了</p>
v-for 循环 <li v-for="todo in todos"> {todo.text } <li>
v-on @ 事件 <button v-on:click="reverseMessage">反转消息</button>
v-bind : 参数绑定 <a v-bind:href="a-href"> {text } </a>
v-model 双向数据绑定 <input v-model="message"> <p>{message }</p>
自定义指令和过滤器
directive 可以用来自定义指令。
filter 可以用来定义过滤器。
在main.js中:
import Vue from 'vue'
import VueResource from 'vue-resource'
import VueRouter from 'vue-router'
import App from './App'
import Routes from './routes'
Vue.config.productionTip = false
Vue.use(VueResource)
Vue.use(VueRouter)
// Vue.directive('rainbow', {
// bind(el, binding, vnode) {
// el.style.color = "#" + Math.random().toString(16).slice(2, 8);
// }
// });
Vue.directive('theme', {
bind(el, binding, vnode) {
if (binding.value == 'wide') {
el.style.maxWidth = '1260px';
} else if (binding.value == 'narrow') {
el.style.maxWidth = '560px';
}
if (binding.arg == 'column') {
el.style.background = '#6677cc';
el.style.padding = '20px';
}
}
});
// Vue.filter('to-uppercase', function(value){
// return value.toUpperCase();
// });
Vue.filter('snippt', function(value){
return value.slice(0, 100) + '...';
});
const router = new VueRouter({
routes: Routes,
mode: "history"
});
/* eslint-disable no-new */
new Vue({
el: '#app',
components: { App },
template: '<App/>',
router: router
})
在具体component中:
<template>
<div v-theme:column="'narrow'" id="show-blog">
<h1>博客总览</h1>
<input type="text" v-model="search" placehodler="搜索">
<div v-for="blog in filteredBlogs" class="single-blog">
<router-link v-bind:to="'/blog/' + blog.id">
<h2 v-rainbow></h2>
</router-link>
<article>
</article>
</div>
</div>
</template>
<script>
export default {
name: 'show-blog',
data() {
return {
blogs:[],
search: ''
}
},
created() {
// this.$http.get('https://jsonplaceholder.typicode.com/posts')
// .then(function(data) {
// this.blogs = data.body.slice(0, 10);
// });
// 未写router时
// this.$http.get('./../static/posts')
// .then(function(data) {
// this.blogs = data.body.slice(0, 10);
// })
// 写了router后,请求地址要完整
this.$http.get('./../static/posts.json')
.then(function(data) {
this.blogs = data.body.slice(0, 10);
})
},
computed: {
filteredBlogs: function() {
return this.blogs.filter((blog) => {
return blog.title.match(this.search);
})
}
},
filters: {
// "to-uppercase": function(value) {
// return value.toUpperCase();
// }
toUppercase(value) {
return value.toUpperCase();
}
},
directives: {
'rainbow': {
bind(el, binding, vnode) {
el.style.color = "#" + Math.random().toString(16).slice(2, 8);
}
}
}
}
</script>
数据
data()
props
propsData
computed 计算属性
<div id="example">
<p>Original message: "{message }"</p>
<p>Computed reversed message: "{reversedMessage }"</p>
</div>
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
return this.message.split('').reverse().join('')
}
}
})
methods
watch 侦听属性
<div id="watch-example">
<p>
Ask a yes/no question:
<input v-model="question">
</p>
<p>{answer }</p>
</div>
var watchExampleVM = new Vue({
el: '#watch-example',
data: {
question: '',
answer: 'I cannot give you an answer until you ask a question!'
},
watch: {
// 如果 `question` 发生改变,这个函数就会运行
question: function (newQuestion, oldQuestion) {
this.answer = 'Waiting for you to stop typing...'
this.debouncedGetAnswer()
}
},
created: function () {
// `_.debounce` 是一个通过 Lodash 限制操作频率的函数。
// 在这个例子中,我们希望限制访问 yesno.wtf/api 的频率
// AJAX 请求直到用户输入完毕才会发出。想要了解更多关于
// `_.debounce` 函数 (及其近亲 `_.throttle`) 的知识,
// 请参考:https://lodash.com/docs#debounce
this.debouncedGetAnswer = _.debounce(this.getAnswer, 500)
},
methods: {
getAnswer: function () {
if (this.question.indexOf('?') === -1) {
this.answer = 'Questions usually contain a question mark. ;-)'
return
}
this.answer = 'Thinking...'
var vm = this
axios.get('https://yesno.wtf/api')
.then(function (response) {
vm.answer = _.capitalize(response.data.answer)
})
.catch(function (error) {
vm.answer = 'Error! Could not reach the API. ' + error
})
}
}
})
生命周期钩子
beforeCreate
created created: function () {}
beforeMount
mounted
beforeUpdate
updated
activated
deactivated
beforeDestroy
destroyed
errorCaptured
<DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="vue.js"type="text/javascript"charset="utf-8"></script>
</head>
<body>
<div id="app">
</div>
<script type="text/javascript">
var vm = new Vue({
el "#app",
data: {
msg "hi vue",
},
//在实例初始化之后,数据观测(data observer)和 event/watcher 事件配置之前被调用。
beforeCreate:function() {
console.1og('beforeCreate');
},
//在实例创建完成后被立即调用。
/在这一步,实例已完成以下的配置:数据观测(data observer),属性和方法的运算,watch/event 事件回调。
/然而,挂载阶段还没开始,$e1属性目前不可见。
created:function() {
console.log('created');
},
//在挂载开始之前被调用:相关的渲染函数首次被调用
beforeMount:function() {
console.1og('beforeMount')
},
//el被新创建的 vm.$e1 替换,挂载成功
mounted:function() {
console.log('mounted');
}
//数据更新调用
beforeUpdate:function() {
console.log('beforeUpdate');
},
//组件D0M已经更新,组件更新完毕
updated:function(){
console.log('updated');
}
});
setTimeout(function(){
vm.msg = "change ......"
},3000);
</script>
</body>
</html>
事件修饰符
.stop
.prevent
.capture
.self
.once
.passive
<!--阻止单击事件继续传播-->
<a v-on:click[.stop="doThis"]></a>
<!--提交事件不再重载页面-->
<form v-on:submit.prevent="onSubmit"></form>
<!--修饰符可以,串联-->
<a v-on:click.stop.prevent="doThat"></a>
<!--只有修饰符-->
<form v-on:submit.prevent></form>
<!--添加事件监听器时使用事件捕获模式-->
<!--即元素自身触发的事件先在此处理,然后才交由内部元素进行处理-->
<div v-on:click.capture="doThis">...</div>
<!--只当在event.target是当前元素自身时角触发处理函数-->
<!--即事件不是从内元素触发的-->
<div v-on:click.self="doThat">...</div>
内置组件
component() 组件
<div id="app-7">
<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>
</div>
Vue.component('todo-item', {
props: ['todo'],
template: '<li>{todo.text }</li>'
})
var app7 = new Vue({
el: '#app-7',
data: {
groceryList: [
{ id: 0, text: '蔬菜' },
{ id: 1, text: '奶酪' },
{ id: 2, text: '随便其它什么人吃的东西' }
]
}
})
区别小结
show与if
show是css的是否显示,if是div块是否存在。
computed与watch
- 功能上:computed是计算属性,watch是监听一个值的变化,然后执行对应的回调。
- 是否调用缓存:computed中的函数所依赖的属性没有发生变化,那么调用当前的函数的时候会从缓存中读取,而watch在每次监听的值发生变化的时候都会执行回调。
- 是否调用return:computed中的函数必须要用return返回,watch中的函数不是必须要用return。
- computed默认第一次加载的时候就开始监听;watch默认第一次加载不做监听,如果需要第一次加载做监听,添加immediate属性,设置为true(immediate:true)
- 使用场景:computed,当一个属性受多个属性影响的时候,使用computed(购物车商品结算)。watch,当一条数据影响多条数据的时候,使用watch(搜索框)
computed 支持缓存,相依赖的数据发生改变才会重新计算;watch不支持缓存,只要监听的数据变化就会触发相应操作。
computed 不支持异步,当computed内有异步操作时是无法监听数据变化的;watch支持异步操作。
computed 属性的属性值是一函数,函数返回值为属性的属性值,computed中每个属性都可以设置set与get方法。 watch监听的数据必须是data中声明过或父组件传递过来的props中的数据,当数据变化时,触发监听器。
created与mounted
created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成识图。
mounted:在模板渲染成html后调用,通常初始化页面完成后,再对html的dom节点进行一些需要的操作。
通常created使用的次数多,而mounted通常是在一些插件的使用或者组件的使用中进行操作,比如插件chart.js的使用:var ctx = document.getElementById(ID);
。
如果写入created中,你会发现无法对chart进行一些初始化配置,一定要等到html渲染完成才可以进行,这时候就需要用到mounted。
问题记录
node报错ERR_OSSL_EVP_UNSUPPORTED
在一个项目下使用npm run dev
时报错:
Error: error:0308010C:digital envelope routines::unsupported
at new Hash (node:internal/crypto/hash:71:19)
at Object.createHash (node:crypto:133:10)
at module.exports (G:\VueProject\vue-element-admin\node_modules\webpack\lib\util\createHash.js:135:53)
at NormalModule._initBuildHash (G:\VueProject\vue-element-admin\node_modules\webpack\lib\NormalModule.js:417:16)
at handleParseError (G:\VueProject\vue-element-admin\node_modules\webpack\lib\NormalModule.js:471:10)
at G:\VueProject\vue-element-admin\node_modules\webpack\lib\NormalModule.js:503:5
at G:\VueProject\vue-element-admin\node_modules\webpack\lib\NormalModule.js:358:12
at G:\VueProject\vue-element-admin\node_modules\loader-runner\lib\LoaderRunner.js:373:3
at iterateNormalLoaders (G:\VueProject\vue-element-admin\node_modules\loader-runner\lib\LoaderRunner.js:214:10)
at Array.<anonymous> (G:\VueProject\vue-element-admin\node_modules\loader-runner\lib\LoaderRunner.js:205:4)
at Storage.finished (G:\VueProject\vue-element-admin\node_modules\enhanced-resolve\lib\CachedInputFileSystem.js:55:16)
at G:\VueProject\vue-element-admin\node_modules\enhanced-resolve\lib\CachedInputFileSystem.js:91:9
at G:\VueProject\vue-element-admin\node_modules\graceful-fs\graceful-fs.js:123:16
at FSReqCallback.readFileAfterClose [as oncomplete] (node:internal/fs/read_file_context:68:3) {
opensslErrorStack: [ 'error:03000086:digital envelope routines::initialization error' ],
library: 'digital envelope routines',
reason: 'unsupported',
code: 'ERR_OSSL_EVP_UNSUPPORTED'
}
Node.js v18.16.1
原因是从node v17以上版本的OpenSSL3.0对允许算法和密钥大小增加了严格的限制。
解决办法是在 CMD 命令行中输入:`
G:\VueProject\vue-element-admin>set NODE_OPTIONS=--openssl-legacy-provider
然后再运行就不报错了。
cross-env 不是内部或外部命令
运行时报错:
G:\VueProject\vue2-elm>npm run dev
> elm@2.0.1 dev
> cross-env NODE_ENV=online node build/dev-server.js
'cross-env' 不是内部或外部命令,也不是可运行的程序
或批处理文件。
G:\VueProject\vue2-elm>
运行命令安装:
npm install -g cross-env
参考资料
Vue V2版文档 https://v2.cn.vuejs.org/v2/guide/
Vue的API文档 https://v2.cn.vuejs.org/v2/api/
Node.js 官网 https://nodejs.org/zh-cn/
NPM 官网 https://www.npmjs.com/
Node.js 教程 https://www.runoob.com/nodejs/nodejs-tutorial.html
vue.js中npm安装教程图解 https://www.jb51.net/article/138020.htm
Node.js全套入门教程,nodejs新教程含es6模块化+npm+express+webpack+promise等_Nodejs实战案例详解 https://www.bilibili.com/video/BV1a34y167AZ