Vue 学习


Vue 学习


指令

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

  1. 功能上:computed是计算属性,watch是监听一个值的变化,然后执行对应的回调。
  2. 是否调用缓存:computed中的函数所依赖的属性没有发生变化,那么调用当前的函数的时候会从缓存中读取,而watch在每次监听的值发生变化的时候都会执行回调。
  3. 是否调用return:computed中的函数必须要用return返回,watch中的函数不是必须要用return。
  4. computed默认第一次加载的时候就开始监听;watch默认第一次加载不做监听,如果需要第一次加载做监听,添加immediate属性,设置为true(immediate:true)
  5. 使用场景: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


返回