【问题标题】:Manipulating injected HTML using vue.js and axios使用 vue.js 和 axios 操作注入的 HTML
【发布时间】:2018-10-30 21:08:24
【问题描述】:

我正在使用 vue.js 和 axios 编写一个页面,以通过 REST API 从 WP 站点的类别中获取最新帖子的内容。帖子内容始终是有序列表 (OL)。注入的 OL 的项目随后将显示为轮播。 OL注入成功,但操作失败。有没有人会指出我写的JS中的问题?使用 jQuery 可以轻松完成相同的任务,但我只是想练习一些新的东西。

HTML:

<div class="frame ajax annoucements">
  <h1 id="announcements-title" class="material ajax-title">Announcements<span class="title-this-week"></span></h1>
  <div id="app" class="ajax-body material" v-html="posts[0].content.rendered">
  </div>
</div>

JS:

var tcnt = 0;

new Vue({
  el: '#app',
  data: {
    posts: []
  },
  created() {
    axios.get('http://www.just-a-wp-site.com/wp-json/wp/v2/categories/')
    .then((response) => {
      var categoryId = 0;
      response.data.forEach(function(category){
        if (category.slug == 'announcements') {
          categoryId = category.id;
          console.log('Category ID: ' + category.id);
        }
      });
      return categoryId;
    })
    .then((categoryId) => {
      console.log(categoryId);
      return axios.get('http://www.just-a-wp-site.com/wp-json/wp/v2/posts/', {
        params: {
          categories: categoryId,
          per_page: 1,
          status: 'publish'
        }
      });
    })
    .then((response) => {
      console.log(response.data);
      this.posts = response.data;
    })
    .catch((error) => {
      console.log(error.message);
    })
  },
  mounted() {
    var announcements = document.querySelectorAll('frame.ajax .ajax-body > ol > li');
    console.log(announcements.length);
    setInterval(function(){
      var target = announcements.length % tcnt;
      for (i = 0; i < announcements.length; i++) {
        if (i == target) {
          announcements[i].style.display = 'block';
        }
        else {
          announcements[i].style.display = 'initial';
        }
      }
      tcnt++;
    }, 1000);
  }
});

【问题讨论】:

  • 在 vue 项目中直接使用 DOM 并不是最佳实践,稍后我会举一个例子来实现相同的功能。 v-html 渲染的内容是非响应式的。

标签: javascript ajax vue.js axios


【解决方案1】:

这是一个时间问题。

您需要了解 Javascript 的异步特性。/

当你在mounted hook 中执行document.querySelectorAll('frame.ajax .ajax-body &gt; ol &gt; li') 时,ajax 请求可能还没有响应。因此,DOM 元素尚不存在,并且无法按预期工作。

我的建议是将DOM操作的代码放入一个方法中,并在ajax请求响应后调用它。

listManipulation方法:

var tcnt = 0;

new Vue({
    el: '#app',
    data: {
        posts: []
    },
    created() {
        axios.get('http://www.just-a-wp-site.com/wp-json/wp/v2/categories/')
            .then((response) => {
                var categoryId = 0;
                response.data.forEach(function(category) {
                    if (category.slug == 'announcements') {
                        categoryId = category.id;
                        console.log('Category ID: ' + category.id);
                    }
                });
                return categoryId;
            })
            .then((categoryId) => {
                console.log(categoryId);
                return axios.get('http://www.just-a-wp-site.com/wp-json/wp/v2/posts/', {
                    params: {
                        categories: categoryId,
                        per_page: 1,
                        status: 'publish'
                    }
                });
            })
            .then((response) => {
                console.log(response.data);
                this.posts = response.data;
                this.$nextTick(() => {
                    this.listManipulation();
                })
            })
            .catch((error) => {
                console.log(error.message);
            })
    },
    methods: {
        listManipulation() {
            var announcements = document.querySelectorAll('frame.ajax .ajax-body > ol > li');
            console.log(announcements.length);
            setInterval(function() {
                var target = announcements.length % tcnt;
                for (i = 0; i < announcements.length; i++) {
                    if (i == target) {
                        announcements[i].style.display = 'block';
                    } else {
                        announcements[i].style.display = 'initial';
                    }
                }
                tcnt++;
            }, 1000);
        }
    }
});

$nextTick表示先等待DOM更新,再执行里面的代码。


在 Vue 项目中直接操作 DOM 也被认为是不好的做法。因为 Vue 使用 Virtual DOM 来跟踪 DOM 的变化。如果你修改了 DOM,Vue 将不会跟踪它,并且可能会在下次更新时覆盖修改。

由于您正在控制显示器,您应该查看v-if

【讨论】:

    【解决方案2】:

    给你一个轮播的例子,没有jQuery和任何DOM操作:

    var app = new Vue({
    	el: '#app',
    	data() {
    		return {
    			list: [1,2,3,4],
    			curIndex: 0
    		}
    	},
    	created () {
    		window.setInterval(_=>{
    			if(this.curIndex+1>this.list.length-1){
    				this.curIndex = 0;
    			}else{
    				this.curIndex++
    			}
    		},3000)
    	}
    })
    .wrapper{
    		width: 200px;
    		height: 100px;
    		position: relative;
    	}
    	.wrapper>div{
    		position: absolute;
    		left: 0;
    		top: 0;
    		width: 100%;
    		height: 100px;
    		line-height: 100px;	
    		text-align: center;
    		color: #fff;	
    	}
    	.wrapper>div:nth-child(1){
    		background: red;
    	}
    	.wrapper>div:nth-child(2){
    		background: blue;
    	}
    	.wrapper>div:nth-child(3){
    		background: orange;
    	}
    	.wrapper>div:nth-child(4){
    		background: yellow;
    	}
    	.fade-enter,.fade-leave-active{
    		opacity: 0;
    	}
    	.fade-enter-active,.fade-leave-active{
    		transition: opacity .5s ease-in-out;
    	}
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <div id="app">
      	<transition-group tag="div" class="wrapper" name="fade">
      		<div v-for="(item,index) of list" :key="index" v-show="index==curIndex">
    			{{item}}
    		</div>
    	</transition-group>
    </div>

    【讨论】:

    • 你需要关注的只是列表的内容,而不是如何操作DOM元素
    • 非常感谢。是的,直接操作 DOM 元素听起来仍然很“jQuery”,但在这种情况下需要它,因为我需要直接抓取 HTML 中的帖子内容。但是,您的回答在另一个页面中对我有很大帮助,我取而代之的是一个 JSON 对象。
    猜你喜欢
    • 2021-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-11
    • 2019-04-29
    • 1970-01-01
    • 2018-11-04
    • 2021-06-25
    相关资源
    最近更新 更多